aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore75
-rw-r--r--.travis.yml8
-rw-r--r--Android.mk486
-rw-r--r--CHANGES.txt309
-rw-r--r--CONTRIBUTORS.txt14
-rw-r--r--LICENSE (renamed from COPYING.txt)15
-rw-r--r--Makefile.am251
-rw-r--r--README.md (renamed from README.txt)77
-rwxr-xr-xautogen.sh8
-rw-r--r--benchmarks/ProtoBench.java2
-rw-r--r--config.h.include7
-rw-r--r--configure.ac27
-rw-r--r--editors/proto.vim11
-rw-r--r--examples/AddPerson.java14
-rw-r--r--examples/README.txt2
-rwxr-xr-xgenerate_descriptor_proto.sh38
-rw-r--r--java/README.md (renamed from java/README.txt)10
-rw-r--r--java/pom.xml112
-rw-r--r--java/src/main/java/com/google/protobuf/AbstractMessage.java672
-rw-r--r--java/src/main/java/com/google/protobuf/AbstractMessageLite.java50
-rw-r--r--java/src/main/java/com/google/protobuf/AbstractParser.java253
-rw-r--r--java/src/main/java/com/google/protobuf/BlockingRpcChannel.java2
-rw-r--r--java/src/main/java/com/google/protobuf/BlockingService.java2
-rw-r--r--java/src/main/java/com/google/protobuf/BoundedByteString.java180
-rw-r--r--java/src/main/java/com/google/protobuf/ByteString.java941
-rw-r--r--java/src/main/java/com/google/protobuf/CodedInputStream.java712
-rw-r--r--java/src/main/java/com/google/protobuf/CodedOutputStream.java258
-rw-r--r--java/src/main/java/com/google/protobuf/Descriptors.java640
-rw-r--r--java/src/main/java/com/google/protobuf/DynamicMessage.java250
-rw-r--r--java/src/main/java/com/google/protobuf/Extension.java85
-rw-r--r--java/src/main/java/com/google/protobuf/ExtensionLite.java63
-rw-r--r--java/src/main/java/com/google/protobuf/ExtensionRegistry.java188
-rw-r--r--java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java20
-rw-r--r--java/src/main/java/com/google/protobuf/FieldSet.java289
-rw-r--r--java/src/main/java/com/google/protobuf/GeneratedMessage.java1075
-rw-r--r--java/src/main/java/com/google/protobuf/GeneratedMessageLite.java837
-rw-r--r--java/src/main/java/com/google/protobuf/Internal.java501
-rw-r--r--java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java31
-rw-r--r--java/src/main/java/com/google/protobuf/LazyField.java154
-rw-r--r--java/src/main/java/com/google/protobuf/LazyFieldLite.java339
-rw-r--r--java/src/main/java/com/google/protobuf/LazyStringArrayList.java250
-rw-r--r--java/src/main/java/com/google/protobuf/LazyStringList.java119
-rw-r--r--java/src/main/java/com/google/protobuf/LiteralByteString.java377
-rw-r--r--java/src/main/java/com/google/protobuf/MapEntry.java433
-rw-r--r--java/src/main/java/com/google/protobuf/MapEntryLite.java331
-rw-r--r--java/src/main/java/com/google/protobuf/MapField.java259
-rw-r--r--java/src/main/java/com/google/protobuf/MapFieldLite.java182
-rw-r--r--java/src/main/java/com/google/protobuf/Message.java58
-rw-r--r--java/src/main/java/com/google/protobuf/MessageLite.java43
-rw-r--r--java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java4
-rw-r--r--java/src/main/java/com/google/protobuf/MessageOrBuilder.java41
-rw-r--r--java/src/main/java/com/google/protobuf/MessageReflection.java952
-rw-r--r--java/src/main/java/com/google/protobuf/Parser.java261
-rw-r--r--java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java2
-rw-r--r--java/src/main/java/com/google/protobuf/ProtocolStringList.java48
-rw-r--r--java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java42
-rw-r--r--java/src/main/java/com/google/protobuf/RopeByteString.java977
-rw-r--r--java/src/main/java/com/google/protobuf/RpcCallback.java2
-rw-r--r--java/src/main/java/com/google/protobuf/RpcChannel.java2
-rw-r--r--java/src/main/java/com/google/protobuf/RpcController.java2
-rw-r--r--java/src/main/java/com/google/protobuf/RpcUtil.java7
-rw-r--r--java/src/main/java/com/google/protobuf/Service.java2
-rw-r--r--java/src/main/java/com/google/protobuf/ServiceException.java2
-rw-r--r--java/src/main/java/com/google/protobuf/SingleFieldBuilder.java16
-rw-r--r--java/src/main/java/com/google/protobuf/SmallSortedMap.java12
-rw-r--r--java/src/main/java/com/google/protobuf/TextFormat.java992
-rw-r--r--java/src/main/java/com/google/protobuf/UninitializedMessageException.java2
-rw-r--r--java/src/main/java/com/google/protobuf/UnknownFieldSet.java63
-rw-r--r--java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java297
-rw-r--r--java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java65
-rw-r--r--java/src/main/java/com/google/protobuf/Utf8.java349
-rw-r--r--java/src/main/java/com/google/protobuf/WireFormat.java86
-rw-r--r--java/src/test/java/com/google/protobuf/AbstractMessageTest.java71
-rw-r--r--java/src/test/java/com/google/protobuf/BoundedByteStringTest.java87
-rw-r--r--java/src/test/java/com/google/protobuf/ByteStringTest.java759
-rw-r--r--java/src/test/java/com/google/protobuf/CheckUtf8Test.java141
-rw-r--r--java/src/test/java/com/google/protobuf/CodedInputStreamTest.java291
-rw-r--r--java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java103
-rw-r--r--java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java2
-rw-r--r--java/src/test/java/com/google/protobuf/DescriptorsTest.java291
-rw-r--r--java/src/test/java/com/google/protobuf/DynamicMessageTest.java136
-rw-r--r--java/src/test/java/com/google/protobuf/FieldPresenceTest.java363
-rw-r--r--java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java2
-rw-r--r--java/src/test/java/com/google/protobuf/GeneratedMessageTest.java708
-rw-r--r--java/src/test/java/com/google/protobuf/IsValidUtf8Test.java180
-rw-r--r--java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java421
-rw-r--r--java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java271
-rw-r--r--java/src/test/java/com/google/protobuf/LazyFieldTest.java121
-rw-r--r--java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java307
-rw-r--r--java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java58
-rw-r--r--java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java30
-rw-r--r--java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java108
-rw-r--r--java/src/test/java/com/google/protobuf/LiteTest.java22
-rw-r--r--java/src/test/java/com/google/protobuf/LiteralByteStringTest.java432
-rw-r--r--java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java277
-rw-r--r--java/src/test/java/com/google/protobuf/MapForProto2Test.java516
-rw-r--r--java/src/test/java/com/google/protobuf/MapTest.java614
-rw-r--r--java/src/test/java/com/google/protobuf/MessageTest.java42
-rw-r--r--java/src/test/java/com/google/protobuf/NestedBuildersTest.java2
-rw-r--r--java/src/test/java/com/google/protobuf/ParserTest.java381
-rw-r--r--java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java2
-rw-r--r--java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java97
-rw-r--r--java/src/test/java/com/google/protobuf/RopeByteStringTest.java161
-rw-r--r--java/src/test/java/com/google/protobuf/ServiceTest.java2
-rw-r--r--java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java2
-rw-r--r--java/src/test/java/com/google/protobuf/SmallSortedMapTest.java2
-rw-r--r--java/src/test/java/com/google/protobuf/TestBadIdentifiers.java53
-rw-r--r--java/src/test/java/com/google/protobuf/TestUtil.java389
-rw-r--r--java/src/test/java/com/google/protobuf/TextFormatTest.java279
-rw-r--r--java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java255
-rw-r--r--java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java316
-rw-r--r--java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java218
-rw-r--r--java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java77
-rw-r--r--java/src/test/java/com/google/protobuf/WireFormatTest.java189
-rw-r--r--java/src/test/java/com/google/protobuf/field_presence_test.proto93
-rw-r--r--java/src/test/java/com/google/protobuf/lazy_fields_lite.proto71
-rw-r--r--java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto72
-rw-r--r--java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto75
-rw-r--r--java/src/test/java/com/google/protobuf/map_for_proto2_test.proto74
-rw-r--r--java/src/test/java/com/google/protobuf/map_test.proto64
-rw-r--r--java/src/test/java/com/google/protobuf/multiple_files_test.proto11
-rw-r--r--java/src/test/java/com/google/protobuf/nested_builders_test.proto3
-rw-r--r--java/src/test/java/com/google/protobuf/nested_extension.proto4
-rw-r--r--java/src/test/java/com/google/protobuf/nested_extension_lite.proto3
-rw-r--r--java/src/test/java/com/google/protobuf/non_nested_extension.proto4
-rw-r--r--java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto3
-rw-r--r--java/src/test/java/com/google/protobuf/outer_class_name_test.proto40
-rw-r--r--java/src/test/java/com/google/protobuf/outer_class_name_test2.proto44
-rw-r--r--java/src/test/java/com/google/protobuf/outer_class_name_test3.proto45
-rw-r--r--java/src/test/java/com/google/protobuf/test_bad_identifiers.proto102
-rw-r--r--java/src/test/java/com/google/protobuf/test_check_utf8.proto51
-rw-r--r--java/src/test/java/com/google/protobuf/test_check_utf8_size.proto52
-rw-r--r--java/src/test/java/com/google/protobuf/test_custom_options.proto44
-rw-r--r--java/src/test/java/com/google/protobuf/test_extra_interfaces.proto61
-rw-r--r--javanano/README.md375
-rw-r--r--javanano/pom.xml225
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java681
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java1003
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java187
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/Extension.java687
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/FieldArray.java273
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/FieldData.java190
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/InternalNano.java555
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java93
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/MapFactories.java67
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/MessageNano.java190
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java271
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java84
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java124
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/NanoTest.java4388
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/map_test.proto70
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto118
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto48
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto48
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto28
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto33
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto29
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto34
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto34
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto82
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto48
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto41
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto63
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto195
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto49
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto116
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto47
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto95
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto54
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto38
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto43
-rw-r--r--m4/acx_check_suncc.m41
-rwxr-xr-xpost_process_dist.sh24
-rw-r--r--protobuf.pc.in3
-rw-r--r--python/README.md (renamed from python/README.txt)33
-rwxr-xr-xpython/ez_setup.py1
-rwxr-xr-xpython/google/protobuf/__init__.py35
-rwxr-xr-xpython/google/protobuf/descriptor.py378
-rw-r--r--python/google/protobuf/descriptor_database.py137
-rw-r--r--python/google/protobuf/descriptor_pool.py671
-rwxr-xr-xpython/google/protobuf/internal/_parameterized.py438
-rw-r--r--python/google/protobuf/internal/api_implementation.cc129
-rwxr-xr-xpython/google/protobuf/internal/api_implementation.py81
-rwxr-xr-xpython/google/protobuf/internal/containers.py73
-rwxr-xr-xpython/google/protobuf/internal/cpp_message.py121
-rwxr-xr-xpython/google/protobuf/internal/decoder.py168
-rw-r--r--python/google/protobuf/internal/descriptor_database_test.py65
-rw-r--r--python/google/protobuf/internal/descriptor_pool_test.py591
-rw-r--r--python/google/protobuf/internal/descriptor_pool_test1.proto96
-rw-r--r--python/google/protobuf/internal/descriptor_pool_test2.proto72
-rw-r--r--python/google/protobuf/internal/descriptor_python_test.py54
-rwxr-xr-xpython/google/protobuf/internal/descriptor_test.py615
-rwxr-xr-xpython/google/protobuf/internal/encoder.py45
-rw-r--r--python/google/protobuf/internal/enum_type_wrapper.py89
-rw-r--r--python/google/protobuf/internal/factory_test1.proto58
-rw-r--r--python/google/protobuf/internal/factory_test2.proto99
-rwxr-xr-xpython/google/protobuf/internal/generator_test.py113
-rw-r--r--python/google/protobuf/internal/import_test_package/__init__.py33
-rw-r--r--python/google/protobuf/internal/import_test_package/inner.proto37
-rw-r--r--python/google/protobuf/internal/import_test_package/outer.proto39
-rw-r--r--python/google/protobuf/internal/message_factory_python_test.py54
-rw-r--r--python/google/protobuf/internal/message_factory_test.py131
-rwxr-xr-xpython/google/protobuf/internal/message_listener.py2
-rw-r--r--python/google/protobuf/internal/message_python_test.py54
-rwxr-xr-xpython/google/protobuf/internal/message_test.py986
-rw-r--r--python/google/protobuf/internal/missing_enum_values.proto52
-rw-r--r--python/google/protobuf/internal/more_extensions.proto3
-rw-r--r--python/google/protobuf/internal/more_extensions_dynamic.proto50
-rw-r--r--python/google/protobuf/internal/more_messages.proto3
-rw-r--r--python/google/protobuf/internal/proto_builder_test.py77
-rwxr-xr-xpython/google/protobuf/internal/python_message.py304
-rwxr-xr-xpython/google/protobuf/internal/reflection_test.py755
-rwxr-xr-xpython/google/protobuf/internal/service_reflection_test.py10
-rw-r--r--python/google/protobuf/internal/symbol_database_test.py120
-rw-r--r--python/google/protobuf/internal/test_bad_identifiers.proto53
-rwxr-xr-xpython/google/protobuf/internal/test_util.py283
-rwxr-xr-xpython/google/protobuf/internal/text_encoding_test.py68
-rwxr-xr-xpython/google/protobuf/internal/text_format_test.py760
-rwxr-xr-xpython/google/protobuf/internal/type_checkers.py83
-rwxr-xr-xpython/google/protobuf/internal/unknown_fields_test.py264
-rwxr-xr-xpython/google/protobuf/internal/wire_format.py2
-rwxr-xr-xpython/google/protobuf/internal/wire_format_test.py10
-rwxr-xr-xpython/google/protobuf/message.py36
-rw-r--r--python/google/protobuf/message_factory.py155
-rw-r--r--python/google/protobuf/proto_builder.py98
-rw-r--r--python/google/protobuf/pyext/README6
-rw-r--r--python/google/protobuf/pyext/__init__.py0
-rw-r--r--python/google/protobuf/pyext/cpp_message.py57
-rw-r--r--python/google/protobuf/pyext/descriptor.cc1471
-rw-r--r--python/google/protobuf/pyext/descriptor.h92
-rw-r--r--python/google/protobuf/pyext/descriptor_containers.cc1564
-rw-r--r--python/google/protobuf/pyext/descriptor_containers.h95
-rw-r--r--python/google/protobuf/pyext/descriptor_pool.cc370
-rw-r--r--python/google/protobuf/pyext/descriptor_pool.h152
-rw-r--r--python/google/protobuf/pyext/extension_dict.cc309
-rw-r--r--python/google/protobuf/pyext/extension_dict.h132
-rw-r--r--python/google/protobuf/pyext/message.cc2575
-rw-r--r--python/google/protobuf/pyext/message.h310
-rw-r--r--python/google/protobuf/pyext/proto2_api_test.proto40
-rw-r--r--python/google/protobuf/pyext/python-proto2.cc1658
-rw-r--r--python/google/protobuf/pyext/python.proto68
-rw-r--r--python/google/protobuf/pyext/python_descriptor.cc334
-rw-r--r--python/google/protobuf/pyext/python_protobuf.h2
-rw-r--r--python/google/protobuf/pyext/repeated_composite_container.cc776
-rw-r--r--python/google/protobuf/pyext/repeated_composite_container.h177
-rw-r--r--python/google/protobuf/pyext/repeated_scalar_container.cc813
-rw-r--r--python/google/protobuf/pyext/repeated_scalar_container.h118
-rw-r--r--python/google/protobuf/pyext/scoped_pyobject_ptr.h97
-rwxr-xr-xpython/google/protobuf/reflection.py75
-rwxr-xr-xpython/google/protobuf/service.py2
-rwxr-xr-xpython/google/protobuf/service_reflection.py2
-rw-r--r--python/google/protobuf/symbol_database.py185
-rw-r--r--python/google/protobuf/text_encoding.py110
-rwxr-xr-xpython/google/protobuf/text_format.py567
-rwxr-xr-xpython/mox.py2
-rwxr-xr-xpython/setup.py183
-rw-r--r--ruby/.gitignore6
-rw-r--r--ruby/Gemfile3
-rw-r--r--ruby/Gemfile.lock25
-rw-r--r--ruby/README.md111
-rw-r--r--ruby/Rakefile33
-rw-r--r--ruby/ext/google/protobuf_c/defs.c1676
-rw-r--r--ruby/ext/google/protobuf_c/encode_decode.c1167
-rw-r--r--ruby/ext/google/protobuf_c/extconf.rb10
-rw-r--r--ruby/ext/google/protobuf_c/map.c805
-rw-r--r--ruby/ext/google/protobuf_c/message.c516
-rw-r--r--ruby/ext/google/protobuf_c/protobuf.c105
-rw-r--r--ruby/ext/google/protobuf_c/protobuf.h533
-rw-r--r--ruby/ext/google/protobuf_c/repeated_field.c598
-rw-r--r--ruby/ext/google/protobuf_c/storage.c848
-rw-r--r--ruby/ext/google/protobuf_c/upb.c11220
-rw-r--r--ruby/ext/google/protobuf_c/upb.h8050
-rw-r--r--ruby/google-protobuf.gemspec23
-rw-r--r--ruby/lib/google/protobuf.rb36
-rw-r--r--ruby/pom.xml84
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java167
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java267
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java169
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java86
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java82
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java185
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java248
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java434
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java744
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java217
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java84
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java124
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java118
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java391
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java776
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/Utils.java300
-rw-r--r--ruby/src/main/java/google/ProtobufJavaService.java60
-rw-r--r--ruby/src/main/sentinel.proto15
-rw-r--r--ruby/tests/basic.rb1006
-rw-r--r--ruby/tests/generated_code.proto67
-rw-r--r--ruby/tests/generated_code.rb74
-rw-r--r--ruby/tests/generated_code_test.rb17
-rw-r--r--ruby/tests/stress.rb38
-rw-r--r--src/Makefile.am313
-rw-r--r--src/google/protobuf/any.proto98
-rwxr-xr-xsrc/google/protobuf/arena.cc285
-rw-r--r--src/google/protobuf/arena.h602
-rw-r--r--src/google/protobuf/arena_nc.cc45
-rw-r--r--src/google/protobuf/arena_nc_test.py59
-rw-r--r--src/google/protobuf/arena_test_util.cc (renamed from python/google/protobuf/pyext/python_protobuf.cc)36
-rw-r--r--src/google/protobuf/arena_test_util.h59
-rw-r--r--src/google/protobuf/arena_unittest.cc1173
-rw-r--r--src/google/protobuf/arenastring.cc53
-rwxr-xr-xsrc/google/protobuf/arenastring.h315
-rw-r--r--src/google/protobuf/arenastring_unittest.cc112
-rw-r--r--src/google/protobuf/compiler/code_generator.cc10
-rw-r--r--src/google/protobuf/compiler/code_generator.h5
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc726
-rw-r--r--src/google/protobuf/compiler/command_line_interface.h90
-rw-r--r--src/google/protobuf/compiler/command_line_interface_unittest.cc364
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc15
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc83
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.h10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc261
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.h34
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.cc10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.h7
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.cc90
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h50
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc206
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h20
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc22
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.h2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc224
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h105
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc345
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.h76
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc2167
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h30
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc491
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.h36
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_options.h58
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc150
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc135
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.h35
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_service.cc10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_service.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc669
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.h39
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto49
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc849
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.h51
-rw-r--r--src/google/protobuf/compiler/cpp/test_large_enum_value.proto43
-rw-r--r--src/google/protobuf/compiler/importer.cc48
-rw-r--r--src/google/protobuf/compiler/importer.h22
-rw-r--r--src/google/protobuf/compiler/importer_unittest.cc187
-rw-r--r--src/google/protobuf/compiler/java/java_context.cc195
-rw-r--r--src/google/protobuf/compiler/java/java_context.h98
-rw-r--r--src/google/protobuf/compiler/java/java_doc_comment.cc233
-rw-r--r--src/google/protobuf/compiler/java/java_doc_comment.h (renamed from python/google/protobuf/pyext/python_descriptor.h)78
-rw-r--r--src/google/protobuf/compiler/java/java_doc_comment_unittest.cc67
-rw-r--r--src/google/protobuf/compiler/java/java_enum.cc154
-rw-r--r--src/google/protobuf/compiler/java/java_enum.h19
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.cc727
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.h67
-rw-r--r--src/google/protobuf/compiler/java/java_extension.cc101
-rw-r--r--src/google/protobuf/compiler/java/java_extension.h48
-rw-r--r--src/google/protobuf/compiler/java/java_field.cc218
-rw-r--r--src/google/protobuf/compiler/java/java_field.h86
-rw-r--r--src/google/protobuf/compiler/java/java_file.cc387
-rw-r--r--src/google/protobuf/compiler/java/java_file.h37
-rw-r--r--src/google/protobuf/compiler/java/java_generator.cc89
-rw-r--r--src/google/protobuf/compiler/java/java_generator.h2
-rw-r--r--src/google/protobuf/compiler/java/java_generator_factory.cc77
-rw-r--r--src/google/protobuf/compiler/java/java_generator_factory.h101
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.cc381
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.h183
-rw-r--r--src/google/protobuf/compiler/java/java_lazy_message_field.cc824
-rw-r--r--src/google/protobuf/compiler/java/java_lazy_message_field.h121
-rw-r--r--src/google/protobuf/compiler/java/java_map_field.cc484
-rw-r--r--src/google/protobuf/compiler/java/java_map_field.h83
-rw-r--r--src/google/protobuf/compiler/java/java_message.cc1668
-rw-r--r--src/google/protobuf/compiler/java/java_message.h56
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.cc736
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.h73
-rw-r--r--src/google/protobuf/compiler/java/java_name_resolver.cc266
-rw-r--r--src/google/protobuf/compiler/java/java_name_resolver.h124
-rw-r--r--src/google/protobuf/compiler/java/java_names.h87
-rw-r--r--src/google/protobuf/compiler/java/java_plugin_unittest.cc31
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.cc565
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.h67
-rw-r--r--src/google/protobuf/compiler/java/java_service.cc85
-rw-r--r--src/google/protobuf/compiler/java/java_service.h40
-rw-r--r--src/google/protobuf/compiler/java/java_shared_code_generator.cc205
-rw-r--r--src/google/protobuf/compiler/java/java_shared_code_generator.h94
-rw-r--r--src/google/protobuf/compiler/java/java_string_field.cc752
-rw-r--r--src/google/protobuf/compiler/java/java_string_field.h68
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum.cc111
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum.h87
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.cc520
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.h125
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_extension.cc150
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_extension.h74
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_field.cc209
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_field.h129
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_file.cc263
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_file.h94
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_generator.cc219
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_generator.h72
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.cc585
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.h199
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_map_field.cc186
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_map_field.h70
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.cc615
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.h95
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.cc334
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.h118
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_params.h240
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.cc960
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.h149
-rw-r--r--src/google/protobuf/compiler/main.cc17
-rw-r--r--src/google/protobuf/compiler/mock_code_generator.cc50
-rw-r--r--src/google/protobuf/compiler/mock_code_generator.h6
-rw-r--r--src/google/protobuf/compiler/package_info.h2
-rw-r--r--src/google/protobuf/compiler/parser.cc856
-rw-r--r--src/google/protobuf/compiler/parser.h181
-rw-r--r--src/google/protobuf/compiler/parser_unittest.cc1490
-rw-r--r--src/google/protobuf/compiler/plugin.cc15
-rw-r--r--src/google/protobuf/compiler/plugin.h5
-rw-r--r--src/google/protobuf/compiler/plugin.pb.cc1019
-rw-r--r--src/google/protobuf/compiler/plugin.pb.h596
-rw-r--r--src/google/protobuf/compiler/plugin.proto7
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc460
-rw-r--r--src/google/protobuf/compiler/python/python_generator.h21
-rw-r--r--src/google/protobuf/compiler/python/python_plugin_unittest.cc25
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator.cc393
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator.h58
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc119
-rw-r--r--src/google/protobuf/compiler/subprocess.cc15
-rw-r--r--src/google/protobuf/compiler/subprocess.h4
-rw-r--r--src/google/protobuf/compiler/test_plugin.cc2
-rwxr-xr-xsrc/google/protobuf/compiler/zip_output_unittest.sh2
-rw-r--r--src/google/protobuf/compiler/zip_writer.cc4
-rw-r--r--src/google/protobuf/compiler/zip_writer.h4
-rw-r--r--src/google/protobuf/descriptor.cc2120
-rw-r--r--src/google/protobuf/descriptor.h499
-rw-r--r--src/google/protobuf/descriptor.pb.cc9138
-rw-r--r--src/google/protobuf/descriptor.pb.h4737
-rw-r--r--src/google/protobuf/descriptor.proto260
-rw-r--r--src/google/protobuf/descriptor_database.cc36
-rw-r--r--src/google/protobuf/descriptor_database.h9
-rw-r--r--src/google/protobuf/descriptor_database_unittest.cc8
-rw-r--r--src/google/protobuf/descriptor_unittest.cc2218
-rw-r--r--src/google/protobuf/drop_unknown_fields_test.cc88
-rw-r--r--src/google/protobuf/duration.proto93
-rw-r--r--src/google/protobuf/dynamic_message.cc387
-rw-r--r--src/google/protobuf/dynamic_message.h23
-rw-r--r--src/google/protobuf/dynamic_message_unittest.cc125
-rw-r--r--src/google/protobuf/extension_set.cc933
-rw-r--r--src/google/protobuf/extension_set.h500
-rw-r--r--src/google/protobuf/extension_set_heavy.cc321
-rw-r--r--src/google/protobuf/extension_set_unittest.cc583
-rw-r--r--src/google/protobuf/field_mask.proto161
-rw-r--r--src/google/protobuf/generated_enum_reflection.h88
-rw-r--r--src/google/protobuf/generated_enum_util.h46
-rw-r--r--src/google/protobuf/generated_message_reflection.cc1241
-rw-r--r--src/google/protobuf/generated_message_reflection.h246
-rw-r--r--src/google/protobuf/generated_message_reflection_unittest.cc417
-rw-r--r--src/google/protobuf/generated_message_util.cc15
-rw-r--r--src/google/protobuf/generated_message_util.h65
-rw-r--r--src/google/protobuf/io/coded_stream.cc231
-rw-r--r--src/google/protobuf/io/coded_stream.h259
-rw-r--r--src/google/protobuf/io/coded_stream_inl.h16
-rw-r--r--src/google/protobuf/io/coded_stream_unittest.cc260
-rw-r--r--src/google/protobuf/io/gzip_stream.cc33
-rw-r--r--src/google/protobuf/io/gzip_stream.h17
-rwxr-xr-xsrc/google/protobuf/io/gzip_stream_unittest.sh2
-rw-r--r--src/google/protobuf/io/package_info.h2
-rw-r--r--src/google/protobuf/io/printer.cc22
-rw-r--r--src/google/protobuf/io/printer.h7
-rw-r--r--src/google/protobuf/io/printer_unittest.cc32
-rw-r--r--src/google/protobuf/io/strtod.cc113
-rw-r--r--src/google/protobuf/io/strtod.h50
-rw-r--r--src/google/protobuf/io/tokenizer.cc541
-rw-r--r--src/google/protobuf/io/tokenizer.h109
-rw-r--r--src/google/protobuf/io/tokenizer_unittest.cc267
-rw-r--r--src/google/protobuf/io/zero_copy_stream.cc11
-rw-r--r--src/google/protobuf/io/zero_copy_stream.h12
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl.cc13
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl.h3
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl_lite.cc25
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl_lite.h47
-rw-r--r--src/google/protobuf/io/zero_copy_stream_unittest.cc160
-rw-r--r--src/google/protobuf/lite_unittest.cc248
-rw-r--r--src/google/protobuf/map.h436
-rw-r--r--src/google/protobuf/map_entry.h295
-rw-r--r--src/google/protobuf/map_entry_lite.h409
-rw-r--r--src/google/protobuf/map_field.cc142
-rw-r--r--src/google/protobuf/map_field.h237
-rw-r--r--src/google/protobuf/map_field_inl.h302
-rw-r--r--src/google/protobuf/map_field_lite.h278
-rw-r--r--src/google/protobuf/map_field_test.cc466
-rw-r--r--src/google/protobuf/map_lite_test_util.cc93
-rw-r--r--src/google/protobuf/map_lite_test_util.h80
-rw-r--r--src/google/protobuf/map_lite_unittest.proto133
-rw-r--r--src/google/protobuf/map_proto2_unittest.proto68
-rw-r--r--src/google/protobuf/map_test.cc2310
-rw-r--r--src/google/protobuf/map_test_util.cc1265
-rw-r--r--src/google/protobuf/map_test_util.h156
-rw-r--r--src/google/protobuf/map_test_util_impl.h474
-rw-r--r--src/google/protobuf/map_type_handler.h516
-rw-r--r--src/google/protobuf/map_unittest.proto105
-rw-r--r--src/google/protobuf/message.cc171
-rw-r--r--src/google/protobuf/message.h448
-rw-r--r--src/google/protobuf/message_lite.cc31
-rw-r--r--src/google/protobuf/message_lite.h49
-rw-r--r--src/google/protobuf/message_unittest.cc173
-rw-r--r--src/google/protobuf/metadata.h164
-rw-r--r--src/google/protobuf/no_field_presence_test.cc537
-rw-r--r--src/google/protobuf/package_info.h2
-rw-r--r--src/google/protobuf/preserve_unknown_enum_test.cc289
-rw-r--r--src/google/protobuf/proto3_arena_unittest.cc185
-rw-r--r--src/google/protobuf/proto_cast.h58
-rw-r--r--src/google/protobuf/proto_cast_test.cc60
-rwxr-xr-xsrc/google/protobuf/reflection.h599
-rw-r--r--src/google/protobuf/reflection_internal.h378
-rw-r--r--src/google/protobuf/reflection_ops.cc25
-rw-r--r--src/google/protobuf/reflection_ops.h3
-rw-r--r--src/google/protobuf/reflection_ops_unittest.cc78
-rw-r--r--src/google/protobuf/repeated_field.cc83
-rw-r--r--src/google/protobuf/repeated_field.h1502
-rw-r--r--src/google/protobuf/repeated_field_reflection.h337
-rw-r--r--src/google/protobuf/repeated_field_reflection_unittest.cc706
-rw-r--r--src/google/protobuf/repeated_field_unittest.cc530
-rw-r--r--src/google/protobuf/service.cc2
-rw-r--r--src/google/protobuf/service.h2
-rw-r--r--src/google/protobuf/struct.proto83
-rw-r--r--src/google/protobuf/stubs/atomic_sequence_num.h54
-rw-r--r--src/google/protobuf/stubs/atomicops.h241
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_aix.h440
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_arm64_gcc.h325
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_arm_gcc.h151
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_arm_qnx.h146
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h122
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_generic_gcc.h137
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_macosx.h225
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_mips_gcc.h313
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_pnacl.h73
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_solaris.h188
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_tsan.h219
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc137
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_x86_gcc.h293
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc112
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_x86_msvc.h150
-rw-r--r--src/google/protobuf/stubs/casts.h123
-rw-r--r--src/google/protobuf/stubs/common.cc35
-rw-r--r--src/google/protobuf/stubs/common.h207
-rw-r--r--src/google/protobuf/stubs/common_unittest.cc17
-rw-r--r--src/google/protobuf/stubs/fastmem.h152
-rwxr-xr-x[-rw-r--r--]src/google/protobuf/stubs/hash.h82
-rw-r--r--src/google/protobuf/stubs/map-util.h119
-rw-r--r--src/google/protobuf/stubs/map_util.h769
-rw-r--r--src/google/protobuf/stubs/once.cc81
-rw-r--r--src/google/protobuf/stubs/once.h103
-rw-r--r--src/google/protobuf/stubs/once_unittest.cc2
-rw-r--r--src/google/protobuf/stubs/platform_macros.h108
-rw-r--r--src/google/protobuf/stubs/shared_ptr.h470
-rw-r--r--src/google/protobuf/stubs/singleton.h68
-rw-r--r--src/google/protobuf/stubs/stl_util.h (renamed from src/google/protobuf/stubs/stl_util-inl.h)10
-rw-r--r--src/google/protobuf/stubs/stringprintf.cc175
-rw-r--r--src/google/protobuf/stubs/stringprintf.h76
-rw-r--r--src/google/protobuf/stubs/stringprintf_unittest.cc152
-rw-r--r--src/google/protobuf/stubs/strutil.cc482
-rw-r--r--src/google/protobuf/stubs/strutil.h262
-rw-r--r--src/google/protobuf/stubs/strutil_unittest.cc12
-rw-r--r--src/google/protobuf/stubs/substitute.cc4
-rw-r--r--src/google/protobuf/stubs/substitute.h2
-rw-r--r--src/google/protobuf/stubs/template_util.h138
-rw-r--r--src/google/protobuf/stubs/template_util_unittest.cc130
-rw-r--r--src/google/protobuf/stubs/type_traits.h360
-rw-r--r--src/google/protobuf/stubs/type_traits_unittest.cc631
-rw-r--r--src/google/protobuf/test_util.cc687
-rw-r--r--src/google/protobuf/test_util.h45
-rw-r--r--src/google/protobuf/test_util_lite.cc191
-rw-r--r--src/google/protobuf/test_util_lite.h2
-rw-r--r--src/google/protobuf/testdata/bad_utf8_string1
-rw-r--r--src/google/protobuf/testdata/golden_messagebin487 -> 531 bytes
-rw-r--r--src/google/protobuf/testdata/golden_message_oneof_implementedbin0 -> 515 bytes
-rw-r--r--src/google/protobuf/testdata/golden_message_proto3bin0 -> 398 bytes
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_data.txt18
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt129
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_data_pointy.txt134
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt129
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_extensions_data.txt18
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt134
-rw-r--r--src/google/protobuf/testing/file.cc26
-rw-r--r--src/google/protobuf/testing/file.h19
-rw-r--r--src/google/protobuf/testing/googletest.cc13
-rw-r--r--src/google/protobuf/testing/googletest.h18
-rw-r--r--src/google/protobuf/testing/zcgunzip.cc2
-rw-r--r--src/google/protobuf/testing/zcgzip.cc2
-rw-r--r--src/google/protobuf/text_format.cc824
-rw-r--r--src/google/protobuf/text_format.h219
-rw-r--r--src/google/protobuf/text_format_unittest.cc394
-rw-r--r--src/google/protobuf/timestamp.proto103
-rw-r--r--src/google/protobuf/unittest.proto246
-rw-r--r--src/google/protobuf/unittest_arena.proto46
-rw-r--r--src/google/protobuf/unittest_custom_options.proto32
-rw-r--r--src/google/protobuf/unittest_drop_unknown_fields.proto55
-rw-r--r--src/google/protobuf/unittest_embed_optimize_for.proto3
-rw-r--r--src/google/protobuf/unittest_empty.proto3
-rw-r--r--src/google/protobuf/unittest_enormous_descriptor.proto3
-rw-r--r--src/google/protobuf/unittest_import.proto9
-rw-r--r--src/google/protobuf/unittest_import_lite.proto5
-rw-r--r--src/google/protobuf/unittest_import_public.proto41
-rw-r--r--src/google/protobuf/unittest_import_public_lite.proto43
-rw-r--r--src/google/protobuf/unittest_lite.proto75
-rw-r--r--src/google/protobuf/unittest_lite_imports_nonlite.proto3
-rw-r--r--src/google/protobuf/unittest_mset.proto15
-rw-r--r--src/google/protobuf/unittest_no_arena.proto201
-rw-r--r--src/google/protobuf/unittest_no_arena_import.proto37
-rw-r--r--src/google/protobuf/unittest_no_field_presence.proto138
-rw-r--r--src/google/protobuf/unittest_no_generic_services.proto4
-rw-r--r--src/google/protobuf/unittest_optimize_for.proto10
-rw-r--r--src/google/protobuf/unittest_preserve_unknown_enum.proto68
-rw-r--r--src/google/protobuf/unittest_preserve_unknown_enum2.proto50
-rw-r--r--src/google/protobuf/unittest_proto3_arena.proto186
-rw-r--r--src/google/protobuf/unknown_enum_impl.h155
-rw-r--r--src/google/protobuf/unknown_enum_test.proto61
-rw-r--r--src/google/protobuf/unknown_field_set.cc205
-rw-r--r--src/google/protobuf/unknown_field_set.h123
-rw-r--r--src/google/protobuf/unknown_field_set_unittest.cc104
-rw-r--r--src/google/protobuf/wire_format.cc186
-rw-r--r--src/google/protobuf/wire_format.h52
-rw-r--r--src/google/protobuf/wire_format_lite.cc190
-rw-r--r--src/google/protobuf/wire_format_lite.h102
-rw-r--r--src/google/protobuf/wire_format_lite_inl.h156
-rw-r--r--src/google/protobuf/wire_format_unittest.cc251
-rw-r--r--src/google/protobuf/wrappers.proto97
-rwxr-xr-x[-rw-r--r--]vsprojects/config.h29
-rwxr-xr-xvsprojects/extract_includes.bat82
-rwxr-xr-xvsprojects/google/protobuf/stubs/pbconfig.h39
-rw-r--r--vsprojects/libprotobuf-lite.vcproj65
-rw-r--r--vsprojects/libprotobuf.vcproj137
-rw-r--r--vsprojects/libprotoc.vcproj936
-rw-r--r--vsprojects/lite-test.vcproj68
-rw-r--r--vsprojects/protoc.vcproj4
-rw-r--r--vsprojects/readme.txt7
-rwxr-xr-xvsprojects/test_plugin.vcproj8
-rw-r--r--vsprojects/tests.vcproj590
645 files changed, 160731 insertions, 16460 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..cb0347fc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,75 @@
+# autogen.sh-generated files
+Makefile.in
+src/Makefile.in
+config.guess
+config.h.in
+config.sub
+configure
+depcomp
+install-sh
+ltmain.sh
+missing
+
+aclocal.m4
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+autom4te.cache
+
+# downloaded files
+gtest
+
+# in-tree configure-generated files
+Makefile
+src/Makefile
+/config.h
+config.log
+config.status
+
+libtool
+protobuf-lite.pc
+protobuf.pc
+.deps
+stamp-h1
+
+# in-tree build products
+*.o
+*.lo
+*.la
+src/.libs
+*.so
+
+.dirstamp
+
+map*unittest.pb.*
+unittest*.pb.*
+cpp_test*.pb.*
+
+*.pyc
+*.egg-info
+*_pb2.py
+python/.eggs/
+python/build/
+python/google/protobuf/compiler/
+
+src/protoc
+src/unittest_proto_middleman
+
+# Generated test scaffolding
+src/protobuf*-test
+src/test_plugin
+src/testzip.*
+src/zcg*zip
+ar-lib
+
+test-driver
+compile
+
+src/**/*.log
+src/**/*.trs
+
+# JavaBuild output.
+java/target
+javanano/target
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..18114878
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+sudo: false
+language: cpp
+os:
+ - linux
+ - osx
+script: ./autogen.sh && ./configure && make distcheck -j2
+notifications:
+ email: false
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 00000000..18bdd091
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,486 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+LOCAL_PATH := $(call my-dir)
+
+IGNORED_WARNINGS := -Wno-sign-compare -Wno-unused-parameter -Wno-sign-promo
+
+CC_LITE_SRC_FILES := \
+ src/google/protobuf/stubs/common.cc \
+ src/google/protobuf/stubs/once.cc \
+ src/google/protobuf/stubs/hash.cc \
+ src/google/protobuf/stubs/hash.h \
+ src/google/protobuf/stubs/map-util.h \
+ src/google/protobuf/stubs/stl_util-inl.h \
+ src/google/protobuf/extension_set.cc \
+ src/google/protobuf/generated_message_util.cc \
+ src/google/protobuf/message_lite.cc \
+ src/google/protobuf/repeated_field.cc \
+ src/google/protobuf/wire_format_lite.cc \
+ src/google/protobuf/io/coded_stream.cc \
+ src/google/protobuf/io/coded_stream_inl.h \
+ src/google/protobuf/io/zero_copy_stream.cc \
+ src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+
+JAVA_LITE_SRC_FILES := \
+ java/src/main/java/com/google/protobuf/UninitializedMessageException.java \
+ java/src/main/java/com/google/protobuf/MessageLite.java \
+ java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
+ java/src/main/java/com/google/protobuf/CodedOutputStream.java \
+ java/src/main/java/com/google/protobuf/ByteString.java \
+ java/src/main/java/com/google/protobuf/CodedInputStream.java \
+ java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java \
+ java/src/main/java/com/google/protobuf/AbstractMessageLite.java \
+ java/src/main/java/com/google/protobuf/FieldSet.java \
+ java/src/main/java/com/google/protobuf/Internal.java \
+ java/src/main/java/com/google/protobuf/WireFormat.java \
+ java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+
+COMPILER_SRC_FILES := \
+ src/google/protobuf/descriptor.cc \
+ src/google/protobuf/descriptor.pb.cc \
+ src/google/protobuf/descriptor_database.cc \
+ src/google/protobuf/dynamic_message.cc \
+ src/google/protobuf/extension_set.cc \
+ src/google/protobuf/extension_set_heavy.cc \
+ src/google/protobuf/generated_message_reflection.cc \
+ src/google/protobuf/generated_message_util.cc \
+ src/google/protobuf/message.cc \
+ src/google/protobuf/message_lite.cc \
+ src/google/protobuf/reflection_ops.cc \
+ src/google/protobuf/repeated_field.cc \
+ src/google/protobuf/service.cc \
+ src/google/protobuf/text_format.cc \
+ src/google/protobuf/unknown_field_set.cc \
+ src/google/protobuf/wire_format.cc \
+ src/google/protobuf/wire_format_lite.cc \
+ src/google/protobuf/compiler/code_generator.cc \
+ src/google/protobuf/compiler/command_line_interface.cc \
+ src/google/protobuf/compiler/importer.cc \
+ src/google/protobuf/compiler/main.cc \
+ src/google/protobuf/compiler/parser.cc \
+ src/google/protobuf/compiler/plugin.cc \
+ src/google/protobuf/compiler/plugin.pb.cc \
+ src/google/protobuf/compiler/subprocess.cc \
+ src/google/protobuf/compiler/zip_writer.cc \
+ src/google/protobuf/compiler/cpp/cpp_enum.cc \
+ src/google/protobuf/compiler/cpp/cpp_enum_field.cc \
+ src/google/protobuf/compiler/cpp/cpp_extension.cc \
+ src/google/protobuf/compiler/cpp/cpp_field.cc \
+ src/google/protobuf/compiler/cpp/cpp_file.cc \
+ src/google/protobuf/compiler/cpp/cpp_generator.cc \
+ src/google/protobuf/compiler/cpp/cpp_helpers.cc \
+ src/google/protobuf/compiler/cpp/cpp_message.cc \
+ src/google/protobuf/compiler/cpp/cpp_message_field.cc \
+ src/google/protobuf/compiler/cpp/cpp_primitive_field.cc \
+ src/google/protobuf/compiler/cpp/cpp_service.cc \
+ src/google/protobuf/compiler/cpp/cpp_string_field.cc \
+ src/google/protobuf/compiler/java/java_enum.cc \
+ src/google/protobuf/compiler/java/java_enum_field.cc \
+ src/google/protobuf/compiler/java/java_extension.cc \
+ src/google/protobuf/compiler/java/java_field.cc \
+ src/google/protobuf/compiler/java/java_file.cc \
+ src/google/protobuf/compiler/java/java_generator.cc \
+ src/google/protobuf/compiler/java/java_helpers.cc \
+ src/google/protobuf/compiler/java/java_message.cc \
+ src/google/protobuf/compiler/java/java_message_field.cc \
+ src/google/protobuf/compiler/java/java_primitive_field.cc \
+ src/google/protobuf/compiler/java/java_service.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_enum.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_field.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_file.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_generator.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_helpers.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_message.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_message_field.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc \
+ src/google/protobuf/compiler/javanano/javanano_enum.cc \
+ src/google/protobuf/compiler/javanano/javanano_enum_field.cc \
+ src/google/protobuf/compiler/javanano/javanano_extension.cc \
+ src/google/protobuf/compiler/javanano/javanano_field.cc \
+ src/google/protobuf/compiler/javanano/javanano_file.cc \
+ src/google/protobuf/compiler/javanano/javanano_generator.cc \
+ src/google/protobuf/compiler/javanano/javanano_helpers.cc \
+ src/google/protobuf/compiler/javanano/javanano_message.cc \
+ src/google/protobuf/compiler/javanano/javanano_message_field.cc \
+ src/google/protobuf/compiler/javanano/javanano_primitive_field.cc \
+ src/google/protobuf/compiler/python/python_generator.cc \
+ src/google/protobuf/io/coded_stream.cc \
+ src/google/protobuf/io/gzip_stream.cc \
+ src/google/protobuf/io/printer.cc \
+ src/google/protobuf/io/tokenizer.cc \
+ src/google/protobuf/io/zero_copy_stream.cc \
+ src/google/protobuf/io/zero_copy_stream_impl.cc \
+ src/google/protobuf/io/zero_copy_stream_impl_lite.cc \
+ src/google/protobuf/stubs/common.cc \
+ src/google/protobuf/stubs/hash.cc \
+ src/google/protobuf/stubs/once.cc \
+ src/google/protobuf/stubs/structurally_valid.cc \
+ src/google/protobuf/stubs/strutil.cc \
+ src/google/protobuf/stubs/substitute.cc
+
+# Java nano library (for device-side users)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-java-nano
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := 8
+
+LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/nano)
+LOCAL_SRC_FILES += $(call all-java-files-under, java/src/device/main/java/com/google/protobuf/nano)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Java nano library (for host-side users)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := host-libprotobuf-java-nano
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/nano)
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Java micro library (for device-side users)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-java-micro
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := 8
+
+LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/micro)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Java micro library (for host-side users)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := host-libprotobuf-java-micro
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/micro)
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Java lite library (for device-side users)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-java-lite
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := 8
+
+LOCAL_SRC_FILES := $(JAVA_LITE_SRC_FILES)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Java lite library (for host-side users)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := host-libprotobuf-java-lite
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(JAVA_LITE_SRC_FILES)
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# C++ lite library
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-lite
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ $(LOCAL_PATH)/src
+
+# Define the header files to be copied
+#LOCAL_COPY_HEADERS := \
+# src/google/protobuf/stubs/once.h \
+# src/google/protobuf/stubs/common.h \
+# src/google/protobuf/io/coded_stream.h \
+# src/google/protobuf/generated_message_util.h \
+# src/google/protobuf/repeated_field.h \
+# src/google/protobuf/extension_set.h \
+# src/google/protobuf/wire_format_lite_inl.h
+#
+#LOCAL_COPY_HEADERS_TO := $(LOCAL_MODULE)
+
+LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
+
+# These are the minimum versions and don't need to be update.
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SDK_VERSION := 8
+else
+# x86/mips support only available from API 9.
+LOCAL_SDK_VERSION := 9
+endif
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+include $(BUILD_STATIC_LIBRARY)
+
+# C++ lite library (libc++ flavored for the platform)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-lite
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ $(LOCAL_PATH)/src
+
+LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
+
+include $(BUILD_SHARED_LIBRARY)
+
+# C++ full library
+# =======================================================
+protobuf_cc_full_src_files := \
+ $(CC_LITE_SRC_FILES) \
+ src/google/protobuf/stubs/strutil.cc \
+ src/google/protobuf/stubs/strutil.h \
+ src/google/protobuf/stubs/substitute.cc \
+ src/google/protobuf/stubs/substitute.h \
+ src/google/protobuf/stubs/structurally_valid.cc \
+ src/google/protobuf/descriptor.cc \
+ src/google/protobuf/descriptor.pb.cc \
+ src/google/protobuf/descriptor_database.cc \
+ src/google/protobuf/dynamic_message.cc \
+ src/google/protobuf/extension_set_heavy.cc \
+ src/google/protobuf/generated_message_reflection.cc \
+ src/google/protobuf/message.cc \
+ src/google/protobuf/reflection_ops.cc \
+ src/google/protobuf/service.cc \
+ src/google/protobuf/text_format.cc \
+ src/google/protobuf/unknown_field_set.cc \
+ src/google/protobuf/wire_format.cc \
+ src/google/protobuf/io/gzip_stream.cc \
+ src/google/protobuf/io/printer.cc \
+ src/google/protobuf/io/tokenizer.cc \
+ src/google/protobuf/io/zero_copy_stream_impl.cc \
+ src/google/protobuf/compiler/importer.cc \
+ src/google/protobuf/compiler/parser.cc
+
+# C++ full library - stlport version
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-full
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := $(protobuf_cc_full_src_files)
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ external/zlib \
+ $(LOCAL_PATH)/src
+
+# Define the header files to be copied
+#LOCAL_COPY_HEADERS := \
+# src/google/protobuf/stubs/once.h \
+# src/google/protobuf/stubs/common.h \
+# src/google/protobuf/io/coded_stream.h \
+# src/google/protobuf/generated_message_util.h \
+# src/google/protobuf/repeated_field.h \
+# src/google/protobuf/extension_set.h \
+# src/google/protobuf/wire_format_lite_inl.h
+#
+#LOCAL_COPY_HEADERS_TO := $(LOCAL_MODULE)
+
+LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
+
+# These are the minimum versions and don't need to be update.
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SDK_VERSION := 8
+else
+# x86/mips support only available from API 9.
+LOCAL_SDK_VERSION := 9
+endif
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+include $(BUILD_STATIC_LIBRARY)
+
+# C++ full library - Gnustl+rtti version
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-full-gnustl-rtti
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := $(protobuf_cc_full_src_files)
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ external/zlib \
+ $(LOCAL_PATH)/src
+
+LOCAL_CFLAGS := -frtti $(IGNORED_WARNINGS)
+LOCAL_SDK_VERSION := 14
+LOCAL_NDK_STL_VARIANT := gnustl_static
+
+include $(BUILD_STATIC_LIBRARY)
+
+# C++ full library - libc++ version for the platform
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-full
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := $(protobuf_cc_full_src_files)
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ external/zlib \
+ $(LOCAL_PATH)/src
+
+LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
+LOCAL_SHARED_LIBRARIES := libz
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Clean temp vars
+protobuf_cc_full_src_files :=
+
+
+# Android Protocol buffer compiler, aprotoc (host executable)
+# used by the build systems as $(PROTOC) defined in
+# build/core/config.mk
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := aprotoc
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := $(COMPILER_SRC_FILES)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ external/zlib \
+ $(LOCAL_PATH)/src
+
+LOCAL_STATIC_LIBRARIES += libz
+
+ifneq ($(HOST_OS),windows)
+LOCAL_LDLIBS := -lpthread
+endif
+
+LOCAL_CFLAGS := $(IGNORED_WARNINGS)
+
+include $(BUILD_HOST_EXECUTABLE)
+
+# To test java proto params build rules.
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := aprotoc-test-nano-params
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_SRC_FILES := \
+ src/google/protobuf/unittest_import_nano.proto \
+ src/google/protobuf/unittest_simple_nano.proto \
+ src/google/protobuf/unittest_stringutf8_nano.proto \
+ src/google/protobuf/unittest_recursive_nano.proto
+
+
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
+
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
+ java_package = $(LOCAL_PATH)/src/google/protobuf/unittest_import_nano.proto|com.google.protobuf.nano, \
+ java_outer_classname = $(LOCAL_PATH)/src/google/protobuf/unittest_import_nano.proto|UnittestImportNano
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# To test Android-specific nanoproto features.
+# =======================================================
+include $(CLEAR_VARS)
+
+# Parcelable messages
+LOCAL_MODULE := android-nano-test-parcelable
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_SRC_FILES := src/google/protobuf/unittest_simple_nano.proto
+
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
+
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
+ parcelable_messages = true
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# Parcelable and extendable messages
+LOCAL_MODULE := android-nano-test-parcelable-extendable
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_SRC_FILES := src/google/protobuf/unittest_extension_nano.proto
+
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
+
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
+ parcelable_messages = true, \
+ store_unknown_fields = true
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# Test APK
+LOCAL_PACKAGE_NAME := NanoAndroidTest
+
+LOCAL_SDK_VERSION := 8
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, java/src/device/test/java/com/google/protobuf/nano)
+
+LOCAL_MANIFEST_FILE := java/src/device/test/AndroidManifest.xml
+
+LOCAL_STATIC_JAVA_LIBRARIES := libprotobuf-java-nano \
+ android-nano-test-parcelable \
+ android-nano-test-parcelable-extendable
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+# 2.3.0 prebuilts for backwards compatibility.
+include $(LOCAL_PATH)/prebuilts/Android.mk
diff --git a/CHANGES.txt b/CHANGES.txt
index 737f8659..ac42aa5a 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,312 @@
+2015-02-26 version 3.0.0-alpha-2 (Python/Ruby/JavaNano):
+ General
+ * Introduced three new language implementations (Ruby, JavaNano, and
+ Python) to proto3.
+ * Various bug fixes since 3.0.0-alpha-1
+
+ Python:
+ Python has received several updates, most notably support for proto3
+ semantics in any .proto file that declares syntax="proto3".
+ Messages declared in proto3 files no longer represent field presence
+ for scalar fields (number, enums, booleans, or strings). You can
+ no longer call HasField() for such fields, and they are serialized
+ based on whether they have a non-zero/empty/false value.
+
+ One other notable change is in the C++-accelerated implementation.
+ Descriptor objects (which describe the protobuf schema and allow
+ reflection over it) are no longer duplicated between the Python
+ and C++ layers. The Python descriptors are now simple wrappers
+ around the C++ descriptors. This change should significantly
+ reduce the memory usage of programs that use a lot of message
+ types.
+
+ Ruby:
+ We have added proto3 support for Ruby via a native C extension.
+
+ The Ruby extension itself is included in the ruby/ directory, and details on
+ building and installing the extension are in ruby/README.md. The extension
+ will also be published as a Ruby gem. Code generator support is included as
+ part of `protoc` with the `--ruby_out` flag.
+
+ The Ruby extension implements a user-friendly DSL to define message types
+ (also generated by the code generator from `.proto` files). Once a message
+ type is defined, the user may create instances of the message that behave in
+ ways idiomatic to Ruby. For example:
+
+ - Message fields are present as ordinary Ruby properties (getter method
+ `foo` and setter method `foo=`).
+ - Repeated field elements are stored in a container that acts like a native
+ Ruby array, and map elements are stored in a container that acts like a
+ native Ruby hashmap.
+ - The usual well-known methods, such as `#to_s`, `#dup`, and the like, are
+ present.
+
+ Unlike several existing third-party Ruby extensions for protobuf, this
+ extension is built on a "strongly-typed" philosophy: message fields and
+ array/map containers will throw exceptions eagerly when values of the
+ incorrect type are inserted.
+
+ See ruby/README.md for details.
+
+ JavaNano:
+ JavaNano is a special code generator and runtime library designed especially
+ for resource-restricted systems, like Android. It is very resource-friendly
+ in both the amount of code and the runtime overhead. Here is an an overview
+ of JavaNano features compared with the official Java protobuf:
+
+ - No descriptors or message builders.
+ - All messages are mutable; fields are public Java fields.
+ - For optional fields only, encapsulation behind setter/getter/hazzer/
+ clearer functions is opt-in, which provide proper 'has' state support.
+ - For proto2, if not opted in, has state (field presence) is not available.
+ Serialization outputs all fields not equal to their defaults.
+ The behavior is consistent with proto3 semantics.
+ - Required fields (proto2 only) are always serialized.
+ - Enum constants are integers; protection against invalid values only
+ when parsing from the wire.
+ - Enum constants can be generated into container interfaces bearing
+ the enum's name (so the referencing code is in Java style).
+ - CodedInputByteBufferNano can only take byte[] (not InputStream).
+ - Similarly CodedOutputByteBufferNano can only write to byte[].
+ - Repeated fields are in arrays, not ArrayList or Vector. Null array
+ elements are allowed and silently ignored.
+ - Full support for serializing/deserializing repeated packed fields.
+ - Support extensions (in proto2).
+ - Unset messages/groups are null, not an immutable empty default
+ instance.
+ - toByteArray(...) and mergeFrom(...) are now static functions of
+ MessageNano.
+ - The 'bytes' type translates to the Java type byte[].
+
+ See javanano/README.txt for details.
+
+2014-12-01 version 3.0.0-alpha-1 (C++/Java):
+
+ General
+ * Introduced Protocol Buffers language version 3 (aka proto3).
+
+ When protobuf was initially opensourced it implemented Protocol Buffers
+ language version 2 (aka proto2), which is why the version number
+ started from v2.0.0. From v3.0.0, a new language version (proto3) is
+ introduced while the old version (proto2) will continue to be supported.
+
+ The main intent of introducing proto3 is to clean up protobuf before
+ pushing the language as the foundation of Google's new API platform.
+ In proto3, the language is simplified, both for ease of use and to
+ make it available in a wider range of programming languages. At the
+ same time a few features are added to better support common idioms
+ found in APIs.
+
+ The following are the main new features in language version 3:
+
+ 1. Removal of field presence logic for primitive value fields, removal
+ of required fields, and removal of default values. This makes proto3
+ significantly easier to implement with open struct representations,
+ as in languages like Android Java, Objective C, or Go.
+ 2. Removal of unknown fields.
+ 3. Removal of extensions, which are instead replaced by a new standard
+ type called Any.
+ 4. Fix semantics for unknown enum values.
+ 5. Addition of maps.
+ 6. Addition of a small set of standard types for representation of time,
+ dynamic data, etc.
+ 7. A well-defined encoding in JSON as an alternative to binary proto
+ encoding.
+
+ This release (v3.0.0-alpha-1) includes partial proto3 support for C++ and
+ Java. Items 6 (well-known types) and 7 (JSON format) in the above feature
+ list are not impelmented.
+
+ A new notion "syntax" is introduced to specify whether a .proto file
+ uses proto2 or proto3:
+
+ // foo.proto
+ syntax = "proto3";
+ message Bar {...}
+
+ If omitted, the protocol compiler will generate a warning and "proto2" will
+ be used as the default. This warning will be turned into an error in a
+ future release.
+
+ We recommend that new Protocol Buffers users use proto3. However, we do not
+ generally recommend that existing users migrate from proto2 from proto3 due
+ to API incompatibility, and we will continue to support proto2 for a long
+ time.
+
+ * Added support for map fields (implemented in C++/Java for both proto2 and
+ proto3).
+
+ Map fields can be declared using the following syntax:
+
+ message Foo {
+ map<string, string> values = 1;
+ }
+
+ Data of a map field will be stored in memory as an unordered map and it
+ can be accessed through generated accessors.
+
+ C++
+ * Added arena allocation support (for both proto2 and proto3).
+
+ Profiling shows memory allocation and deallocation constitutes a significant
+ fraction of CPU-time spent in protobuf code and arena allocation is a
+ technique introduced to reduce this cost. With arena allocation, new
+ objects will be allocated from a large piece of preallocated memory and
+ deallocation of these objects is almost free. Early adoption shows 20% to
+ 50% improvement in some Google binaries.
+
+ To enable arena support, add the following option to your .proto file:
+
+ option cc_enable_arenas = true;
+
+ Protocol compiler will generate additional code to make the generated
+ message classes work with arenas. This does not change the existing API
+ of protobuf messages and does not affect wire format. Your existing code
+ should continue to work after adding this option. In the future we will
+ make this option enabled by default.
+
+ To actually take advantage of arena allocation, you need to use the arena
+ APIs when creating messages. A quick example of using the arena API:
+
+ {
+ google::protobuf::Arena arena;
+ // Allocate a protobuf message in the arena.
+ MyMessage* message = Arena::CreateMessage<MyMessage>(&arena);
+ // All submessages will be allocated in the same arena.
+ if (!message->ParseFromString(data)) {
+ // Deal with malformed input data.
+ }
+ // Must not delete the message here. It will be deleted automatically
+ // when the arena is destroyed.
+ }
+
+ Currently arena does not work with map fields. Enabling arena in a .proto
+ file containing map fields will result in compile errors in the generated
+ code. This will be addressed in a future release.
+
+2014-10-20 version 2.6.1:
+
+ C++
+ * Added atomicops support for Solaris.
+ * Released memory allocated by InitializeDefaultRepeatedFields() and
+ GetEmptyString(). Some memory sanitizers reported them as memory leaks.
+
+ Java
+ * Updated DynamicMessage.setField() to handle repeated enum values
+ correctly.
+ * Fixed a bug that caused NullPointerException to be thrown when
+ converting manually constructed FileDescriptorProto to
+ FileDescriptor.
+
+ Python
+ * Fixed WhichOneof() to work with de-serialized protobuf messages.
+ * Fixed a missing file problem of Python C++ implementation.
+
+2014-08-15 version 2.6.0:
+
+ General
+ * Added oneofs(unions) feature. Fields in the same oneof will share
+ memory and at most one field can be set at the same time. Use the
+ oneof keyword to define a oneof like:
+ message SampleMessage {
+ oneof test_oneof {
+ string name = 4;
+ YourMessage sub_message = 9;
+ }
+ }
+ * Files, services, enums, messages, methods and enum values can be marked
+ as deprecated now.
+ * Added Support for list values, including lists of mesaages, when
+ parsing text-formatted protos in C++ and Java.
+ For example: foo: [1, 2, 3]
+
+ C++
+ * Enhanced customization on TestFormat printing.
+ * Added SwapFields() in reflection API to swap a subset of fields.
+ Added SetAllocatedMessage() in reflection API.
+ * Repeated primitive extensions are now packable. The
+ [packed=true] option only affects serializers. Therefore, it is
+ possible to switch a repeated extension field to packed format
+ without breaking backwards-compatibility.
+ * Various speed optimizations.
+
+ Java
+ * writeTo() method in ByteString can now write a substring to an
+ output stream. Added endWith() method for ByteString.
+ * ByteString and ByteBuffer are now supported in CodedInputStream
+ and CodedOutputStream.
+ * java_generate_equals_and_hash can now be used with the LITE_RUNTIME.
+
+ Python
+ * A new C++-backed extension module (aka "cpp api v2") that replaces the
+ old ("cpp api v1") one. Much faster than the pure Python code. This one
+ resolves many bugs and is recommended for general use over the
+ pure Python when possible.
+ * Descriptors now have enum_types_by_name and extension_types_by_name dict
+ attributes.
+ * Support for Python 3.
+
+2013-02-27 version 2.5.0:
+
+ General
+ * New notion "import public" that allows a proto file to forward the content
+ it imports to its importers. For example,
+ // foo.proto
+ import public "bar.proto";
+ import "baz.proto";
+
+ // qux.proto
+ import "foo.proto";
+ // Stuff defined in bar.proto may be used in this file, but stuff from
+ // baz.proto may NOT be used without importing it explicitly.
+ This is useful for moving proto files. To move a proto file, just leave
+ a single "import public" in the old proto file.
+ * New enum option "allow_alias" that specifies whether different symbols can
+ be assigned the same numeric value. Default value is "true". Setting it to
+ false causes the compiler to reject enum definitions where multiple symbols
+ have the same numeric value.
+ Note: We plan to flip the default value to "false" in a future release.
+ Projects using enum aliases should set the option to "true" in their .proto
+ files.
+
+ C++
+ * New generated method set_allocated_foo(Type* foo) for message and string
+ fields. This method allows you to set the field to a pre-allocated object
+ and the containing message takes the ownership of that object.
+ * Added SetAllocatedExtension() and ReleaseExtension() to extensions API.
+ * Custom options are now formatted correctly when descriptors are printed in
+ text format.
+ * Various speed optimizations.
+
+ Java
+ * Comments in proto files are now collected and put into generated code as
+ comments for corresponding classes and data members.
+ * Added Parser to parse directly into messages without a Builder. For
+ example,
+ Foo foo = Foo.PARSER.ParseFrom(input);
+ Using Parser is ~25% faster than using Builder to parse messages.
+ * Added getters/setters to access the underlying ByteString of a string field
+ directly.
+ * ByteString now supports more operations: substring(), prepend(), and
+ append(). The implementation of ByteString uses a binary tree structure
+ to support these operations efficiently.
+ * New method findInitializationErrors() that lists all missing required
+ fields.
+ * Various code size and speed optimizations.
+
+ Python
+ * Added support for dynamic message creation. DescriptorDatabase,
+ DescriptorPool, and MessageFactory work like their C++ couterparts to
+ simplify Descriptor construction from *DescriptorProtos, and MessageFactory
+ provides a message instance from a Descriptor.
+ * Added pickle support for protobuf messages.
+ * Unknown fields are now preserved after parsing.
+ * Fixed bug where custom options were not correctly populated. Custom
+ options can be accessed now.
+ * Added EnumTypeWrapper that provides better accessibility to enum types.
+ * Added ParseMessage(descriptor, bytes) to generate a new Message instance
+ from a descriptor and a byte string.
+
2011-05-01 version 2.4.1:
C++
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index b39ec308..b8d97fc2 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -17,6 +17,12 @@ Proto2 Python primary authors:
Will Robinson <robinson@google.com>
Petar Petrov <petar@google.com>
+Java Nano primary authors:
+ Brian Duff <bduff@google.com>
+ Tom Chao <chaot@google.com>
+ Max Cai <maxtroy@google.com>
+ Ulas Kirazci <ulas@google.com>
+
Large code contributions:
Jason Hsueh <jasonh@google.com>
Joseph Schorr <jschorr@google.com>
@@ -50,7 +56,7 @@ Patch contributors:
text format.
Brian Atkinson <nairb774@gmail.com>
* Added @Override annotation to generated Java code where appropriate.
- Vincent Choinière <Choiniere.Vincent@hydro.qc.ca>
+ Vincent Choinière <Choiniere.Vincent@hydro.qc.ca>
* Tru64 support.
Monty Taylor <monty.taylor@gmail.com>
* Solaris 10 + Sun Studio fixes.
@@ -88,3 +94,9 @@ Patch contributors:
* Added CodedInputStream.getTotalBytesRead().
Kacper Kowalik <xarthisius.kk@gmail.com>
* Fixed m4/acx_pthread.m4 problem for some Linux distributions.
+ William Orr <will@worrbase.com>
+ * Fixed detection of sched_yield on Solaris.
+ * Added atomicops for Solaris
+ Andrew Paprocki <andrew@ishiboo.com>
+ * Fixed minor IBM xlC compiler build issues
+ * Added atomicops for AIX (POWER)
diff --git a/COPYING.txt b/LICENSE
index 705db579..f086efdb 100644
--- a/COPYING.txt
+++ b/LICENSE
@@ -1,5 +1,16 @@
-Copyright 2008, Google Inc.
-All rights reserved.
+This license applies to all parts of Protocol Buffers except the following:
+
+ - Atomicops support for generic gcc, located in
+ src/google/protobuf/stubs/atomicops_internals_generic_gcc.h.
+ This file is copyrighted by Red Hat Inc.
+
+ - Atomicops support for AIX/POWER, located in
+ src/google/protobuf/stubs/atomicops_internals_aix.h.
+ This file is copyrighted by Bloomberg Finance LP.
+
+ - Andorid.mk, which is copyrighted by The Android Open Source Project.
+
+Copyright 2014, Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
diff --git a/Makefile.am b/Makefile.am
index 9b960fc5..e7820f2a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,47 +35,20 @@ clean-local:
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = protobuf.pc protobuf-lite.pc
-EXTRA_DIST = \
- autogen.sh \
- generate_descriptor_proto.sh \
- README.txt \
- INSTALL.txt \
- COPYING.txt \
- CONTRIBUTORS.txt \
- CHANGES.txt \
- editors/README.txt \
- editors/proto.vim \
- editors/protobuf-mode.el \
- vsprojects/config.h \
- vsprojects/extract_includes.bat \
- vsprojects/libprotobuf.vcproj \
- vsprojects/libprotobuf-lite.vcproj \
- vsprojects/libprotoc.vcproj \
- vsprojects/protobuf.sln \
- vsprojects/protoc.vcproj \
- vsprojects/readme.txt \
- vsprojects/test_plugin.vcproj \
- vsprojects/tests.vcproj \
- vsprojects/lite-test.vcproj \
- vsprojects/convert2008to2005.sh \
- examples/README.txt \
- examples/Makefile \
- examples/addressbook.proto \
- examples/add_person.cc \
- examples/list_people.cc \
- examples/AddPerson.java \
- examples/ListPeople.java \
- examples/add_person.py \
- examples/list_people.py \
+java_EXTRA_DIST= \
java/src/main/java/com/google/protobuf/AbstractMessage.java \
java/src/main/java/com/google/protobuf/AbstractMessageLite.java \
+ java/src/main/java/com/google/protobuf/AbstractParser.java \
java/src/main/java/com/google/protobuf/BlockingRpcChannel.java \
java/src/main/java/com/google/protobuf/BlockingService.java \
+ java/src/main/java/com/google/protobuf/BoundedByteString.java \
java/src/main/java/com/google/protobuf/ByteString.java \
java/src/main/java/com/google/protobuf/CodedInputStream.java \
java/src/main/java/com/google/protobuf/CodedOutputStream.java \
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 \
@@ -83,89 +56,220 @@ EXTRA_DIST = \
java/src/main/java/com/google/protobuf/GeneratedMessageLite.java \
java/src/main/java/com/google/protobuf/Internal.java \
java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
+ java/src/main/java/com/google/protobuf/LazyField.java \
+ java/src/main/java/com/google/protobuf/LazyFieldLite.java \
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 \
java/src/main/java/com/google/protobuf/MessageOrBuilder.java \
+ java/src/main/java/com/google/protobuf/MessageReflection.java \
+ java/src/main/java/com/google/protobuf/Parser.java \
java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java \
+ java/src/main/java/com/google/protobuf/ProtocolStringList.java \
java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java \
+ java/src/main/java/com/google/protobuf/RopeByteString.java \
java/src/main/java/com/google/protobuf/RpcCallback.java \
java/src/main/java/com/google/protobuf/RpcChannel.java \
java/src/main/java/com/google/protobuf/RpcController.java \
java/src/main/java/com/google/protobuf/RpcUtil.java \
- java/src/main/java/com/google/protobuf/Service.java \
java/src/main/java/com/google/protobuf/ServiceException.java \
+ java/src/main/java/com/google/protobuf/Service.java \
java/src/main/java/com/google/protobuf/SingleFieldBuilder.java \
java/src/main/java/com/google/protobuf/SmallSortedMap.java \
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 \
java/src/test/java/com/google/protobuf/AbstractMessageTest.java \
+ java/src/test/java/com/google/protobuf/BoundedByteStringTest.java \
+ java/src/test/java/com/google/protobuf/ByteStringTest.java \
+ java/src/test/java/com/google/protobuf/CheckUtf8Test.java \
java/src/test/java/com/google/protobuf/CodedInputStreamTest.java \
java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java \
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/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 \
java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java \
+ java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java \
+ java/src/test/java/com/google/protobuf/RopeByteStringTest.java \
java/src/test/java/com/google/protobuf/ServiceTest.java \
java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java \
java/src/test/java/com/google/protobuf/SmallSortedMapTest.java \
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_lite_test.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.proto \
java/src/test/java/com/google/protobuf/nested_extension_lite.proto \
- java/src/test/java/com/google/protobuf/non_nested_extension.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_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 \
+ java/src/test/java/com/google/protobuf/test_custom_options.proto \
java/pom.xml \
- java/README.txt \
- python/google/protobuf/internal/generator_test.py \
+ java/README.md
+
+javanano_EXTRA_DIST= \
+ javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java \
+ javanano/src/main/java/com/google/protobuf/nano/FieldData.java \
+ javanano/src/main/java/com/google/protobuf/nano/FieldArray.java \
+ javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java \
+ javanano/src/main/java/com/google/protobuf/nano/Extension.java \
+ javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java \
+ javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java \
+ javanano/src/main/java/com/google/protobuf/nano/MessageNano.java \
+ javanano/src/main/java/com/google/protobuf/nano/InternalNano.java \
+ javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java \
+ javanano/src/main/java/com/google/protobuf/nano/MapFactories.java \
+ javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java \
+ javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/NanoTest.java \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto \
+ javanano/src/test/java/com/google/protobuf/nano/map_test.proto \
+ javanano/README.md \
+ javanano/pom.xml
+
+
+python_EXTRA_DIST= \
+ python/google/protobuf/internal/api_implementation.cc \
+ python/google/protobuf/internal/api_implementation.py \
python/google/protobuf/internal/containers.py \
+ python/google/protobuf/internal/cpp_message.py \
python/google/protobuf/internal/decoder.py \
+ python/google/protobuf/internal/descriptor_database_test.py \
+ python/google/protobuf/internal/descriptor_pool_test.py \
+ python/google/protobuf/internal/descriptor_pool_test1.proto \
+ python/google/protobuf/internal/descriptor_pool_test2.proto \
+ python/google/protobuf/internal/descriptor_python_test.py \
python/google/protobuf/internal/descriptor_test.py \
python/google/protobuf/internal/encoder.py \
+ python/google/protobuf/internal/enum_type_wrapper.py \
+ python/google/protobuf/internal/factory_test1.proto \
+ python/google/protobuf/internal/factory_test2.proto \
+ python/google/protobuf/internal/generator_test.py \
+ python/google/protobuf/internal/message_factory_python_test.py \
+ python/google/protobuf/internal/message_factory_test.py \
python/google/protobuf/internal/message_listener.py \
+ python/google/protobuf/internal/message_python_test.py \
python/google/protobuf/internal/message_test.py \
+ python/google/protobuf/internal/missing_enum_values.proto \
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/_parameterized.py \
+ python/google/protobuf/internal/proto_builder_test.py \
python/google/protobuf/internal/python_message.py \
- python/google/protobuf/internal/cpp_message.py \
- python/google/protobuf/internal/api_implementation.py \
python/google/protobuf/internal/reflection_test.py \
python/google/protobuf/internal/service_reflection_test.py \
+ python/google/protobuf/internal/symbol_database_test.py \
+ python/google/protobuf/internal/test_bad_identifiers.proto \
python/google/protobuf/internal/test_util.py \
+ python/google/protobuf/internal/text_encoding_test.py \
python/google/protobuf/internal/text_format_test.py \
python/google/protobuf/internal/type_checkers.py \
+ python/google/protobuf/internal/unknown_fields_test.py \
python/google/protobuf/internal/wire_format.py \
python/google/protobuf/internal/wire_format_test.py \
python/google/protobuf/internal/__init__.py \
- python/google/protobuf/pyext/python-proto2.cc \
- python/google/protobuf/pyext/python_descriptor.cc \
- python/google/protobuf/pyext/python_descriptor.h \
- python/google/protobuf/pyext/python_protobuf.cc \
+ 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 \
+ python/google/protobuf/pyext/descriptor.cc \
+ python/google/protobuf/pyext/descriptor_pool.h \
+ python/google/protobuf/pyext/descriptor_pool.cc \
+ python/google/protobuf/pyext/descriptor_containers.h \
+ python/google/protobuf/pyext/descriptor_containers.cc \
+ python/google/protobuf/pyext/extension_dict.h \
+ python/google/protobuf/pyext/extension_dict.cc \
+ python/google/protobuf/pyext/message.h \
+ python/google/protobuf/pyext/message.cc \
+ python/google/protobuf/pyext/proto2_api_test.proto \
+ python/google/protobuf/pyext/python.proto \
python/google/protobuf/pyext/python_protobuf.h \
+ python/google/protobuf/pyext/repeated_composite_container.h \
+ python/google/protobuf/pyext/repeated_composite_container.cc \
+ python/google/protobuf/pyext/repeated_scalar_container.h \
+ python/google/protobuf/pyext/repeated_scalar_container.cc \
+ python/google/protobuf/pyext/scoped_pyobject_ptr.h \
+ python/google/protobuf/pyext/__init__.py \
python/google/protobuf/descriptor.py \
+ python/google/protobuf/descriptor_database.py \
+ 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 \
+ python/google/protobuf/symbol_database.py \
+ python/google/protobuf/text_encoding.py \
python/google/protobuf/text_format.py \
python/google/protobuf/__init__.py \
python/google/__init__.py \
@@ -173,7 +277,66 @@ EXTRA_DIST = \
python/setup.py \
python/mox.py \
python/stubout.py \
- python/README.txt
+ python/README.md
+
+ruby_EXTRA_DIST= \
+ ruby/README.md \
+ ruby/Rakefile \
+ ruby/ext/google/protobuf_c/defs.c \
+ ruby/ext/google/protobuf_c/encode_decode.c \
+ ruby/ext/google/protobuf_c/extconf.rb \
+ ruby/ext/google/protobuf_c/map.c \
+ ruby/ext/google/protobuf_c/message.c \
+ ruby/ext/google/protobuf_c/protobuf.c \
+ ruby/ext/google/protobuf_c/protobuf.h \
+ ruby/ext/google/protobuf_c/repeated_field.c \
+ ruby/ext/google/protobuf_c/storage.c \
+ ruby/ext/google/protobuf_c/upb.c \
+ ruby/ext/google/protobuf_c/upb.h \
+ ruby/google-protobuf.gemspec \
+ ruby/lib/google/protobuf.rb \
+ ruby/tests/basic.rb \
+ ruby/tests/stress.rb \
+ ruby/tests/generated_code.proto \
+ ruby/tests/generated_code.rb \
+ ruby/tests/generated_code_test.rb
+
+all_EXTRA_DIST=$(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST)
+
+EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST) \
+ autogen.sh \
+ generate_descriptor_proto.sh \
+ README.md \
+ INSTALL.txt \
+ LICENSE \
+ CONTRIBUTORS.txt \
+ CHANGES.txt \
+ config.h.include \
+ editors/README.txt \
+ editors/proto.vim \
+ editors/protobuf-mode.el \
+ vsprojects/config.h \
+ vsprojects/google/protobuf/stubs/pbconfig.h \
+ vsprojects/extract_includes.bat \
+ vsprojects/libprotobuf.vcproj \
+ vsprojects/libprotobuf-lite.vcproj \
+ vsprojects/libprotoc.vcproj \
+ vsprojects/protobuf.sln \
+ vsprojects/protoc.vcproj \
+ vsprojects/readme.txt \
+ vsprojects/test_plugin.vcproj \
+ vsprojects/tests.vcproj \
+ vsprojects/lite-test.vcproj \
+ vsprojects/convert2008to2005.sh \
+ examples/README.txt \
+ examples/Makefile \
+ examples/addressbook.proto \
+ examples/add_person.cc \
+ examples/list_people.cc \
+ examples/AddPerson.java \
+ examples/ListPeople.java \
+ examples/add_person.py \
+ examples/list_people.py
# Deletes all the files generated by autogen.sh.
MAINTAINERCLEANFILES = \
diff --git a/README.txt b/README.md
index a8f66044..5ea6aff6 100644
--- a/README.txt
+++ b/README.md
@@ -1,17 +1,34 @@
Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
Copyright 2008 Google Inc.
-http://code.google.com/apis/protocolbuffers/
+
+https://developers.google.com/protocol-buffers/
C++ Installation - Unix
-=======================
+-----------------------
+
+If you get the source from github, you need to generate the configure script
+first:
+
+ $ ./autogen.sh
+
+This will download gtest source (which is used for C++ Protocol Buffer
+unit-tests) to the current directory and run automake, autoconf, etc.
+to generate the configure script and various template makefiles.
+
+You can skip this step if you are using a release package (which already
+contains gtest and the configure script).
To build and install the C++ Protocol Buffer runtime and the Protocol
Buffer compiler (protoc) execute the following:
- $ ./configure
- $ make
- $ make check
- $ make install
+ $ ./configure
+ $ make
+ $ make check
+ $ make install
If "make check" fails, you can still install, but it is likely that
some features of this library will not work correctly on your system.
@@ -21,7 +38,7 @@ Proceed at your own risk.
For advanced usage information on configure and make, see INSTALL.txt.
-** Hint on install location **
+**Hint on install location**
By default, the package will be installed to /usr/local. However,
on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH.
@@ -33,7 +50,7 @@ For advanced usage information on configure and make, see INSTALL.txt.
If you already built the package with a different prefix, make sure
to run "make clean" before building again.
-** Compiling dependent packages **
+**Compiling dependent packages**
To compile a package that uses Protocol Buffers, you need to pass
various flags to your compiler and linker. As of version 2.2.0,
@@ -71,7 +88,23 @@ For advanced usage information on configure and make, see INSTALL.txt.
If you only want protobuf-lite, substitute "protobuf-lite" in place
of "protobuf" in these examples.
-** Note for cross-compiling **
+**Note for Mac users**
+
+ For a Mac system, Unix tools are not available by default. You will first need
+ to install Xcode from the Mac AppStore and then run the following command from
+ a terminal:
+
+ $ sudo xcode-select --install
+
+ To install Unix tools, you can install "port" following the instructions at
+ https://www.macports.org . This will reside in /opt/local/bin/port for most
+ Mac installations.
+
+ $ sudo /opt/local/bin/port install autoconf automake libtool
+
+ Then follow the Unix instructions above.
+
+**Note for cross-compiling**
The makefiles normally invoke the protoc executable that they just
built in order to build tests. When cross-compiling, the protoc
@@ -94,7 +127,7 @@ For advanced usage information on configure and make, see INSTALL.txt.
has the same version as the protobuf source code you are trying to
use it with.
-** Note for Solaris users **
+**Note for Solaris users**
Solaris 10 x86 has a bug that will make linking fail, complaining
about libstdc++.la being invalid. We have included a work-around
@@ -104,7 +137,7 @@ For advanced usage information on configure and make, see INSTALL.txt.
See src/solaris/libstdc++.la for more info on this bug.
-** Note for HP C++ Tru64 users **
+**Note for HP C++ Tru64 users**
To compile invoke configure as follows:
@@ -112,16 +145,24 @@ For advanced usage information on configure and make, see INSTALL.txt.
Also, you will need to use gmake instead of make.
+**Note for AIX users**
+
+ Compile using the IBM xlC C++ compiler as follows:
+
+ ./configure CXX=xlC
+
+ Also, you will need to use GNU `make` (`gmake`) instead of AIX `make`.
+
C++ Installation - Windows
-==========================
+--------------------------
-If you are using Micosoft Visual C++, see vsprojects/readme.txt.
+If you are using Microsoft Visual C++, see vsprojects/readme.txt.
If you are using Cygwin or MinGW, follow the Unix installation
instructions, above.
Binary Compatibility Warning
-============================
+----------------------------
Due to the nature of C++, it is unlikely that any two versions of the
Protocol Buffers C++ runtime libraries will have compatible ABIs.
@@ -132,10 +173,10 @@ immediately on startup of your app. Still, you may want to consider
using static linkage. You can configure this package to install
static libraries only using:
- ./configure --disable-shared
+ ./configure --disable-shared
Java and Python Installation
-============================
+----------------------------
The Java and Python runtime libraries for Protocol Buffers are located
in the java and python directories. See the README file in each
@@ -144,9 +185,9 @@ Note that both of them require you to first install the Protocol
Buffer compiler (protoc), which is part of the C++ package.
Usage
-=====
+-----
The complete documentation for Protocol Buffers is available via the
web at:
- http://code.google.com/apis/protocolbuffers/
+ https://developers.google.com/protocol-buffers/
diff --git a/autogen.sh b/autogen.sh
index 04d65b16..08966c63 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -18,9 +18,11 @@ fi
# Check that gtest is present. Usually it is already there since the
# directory is set up as an SVN external.
if test ! -e gtest; then
- echo "Google Test not present. Fetching gtest-1.3.0 from the web..."
- curl http://googletest.googlecode.com/files/gtest-1.3.0.tar.bz2 | tar jx
- mv gtest-1.3.0 gtest
+ echo "Google Test not present. Fetching gtest-1.7.0 from the web..."
+ curl -O https://googletest.googlecode.com/files/gtest-1.7.0.zip
+ unzip -q gtest-1.7.0.zip
+ rm gtest-1.7.0.zip
+ mv gtest-1.7.0 gtest
fi
set -ex
diff --git a/benchmarks/ProtoBench.java b/benchmarks/ProtoBench.java
index 6717ffa2..86d62feb 100644
--- a/benchmarks/ProtoBench.java
+++ b/benchmarks/ProtoBench.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2009 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/config.h.include b/config.h.include
new file mode 100644
index 00000000..0c557fbe
--- /dev/null
+++ b/config.h.include
@@ -0,0 +1,7 @@
+HASH_MAP_CLASS
+HASH_MAP_H
+HASH_NAMESPACE
+HASH_SET_CLASS
+HASH_SET_H
+HAVE_HASH_MAP
+HAVE_HASH_SET
diff --git a/configure.ac b/configure.ac
index 2f70a39b..14351a8b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,13 +12,22 @@ AC_PREREQ(2.59)
# In the SVN trunk, the version should always be the next anticipated release
# version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed
# the size of one file name in the dist tarfile over the 99-char limit.)
-AC_INIT([Protocol Buffers],[2.4.1],[protobuf@googlegroups.com],[protobuf])
+AC_INIT([Protocol Buffers],[3.0.0-alpha-3-pre],[protobuf@googlegroups.com],[protobuf])
+AM_MAINTAINER_MODE([enable])
AC_CONFIG_SRCDIR(src/google/protobuf/message.cc)
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
+AC_ARG_VAR(DIST_LANG, [language to include in the distribution package (i.e., make dist)])
+case "$DIST_LANG" in
+ "") DIST_LANG=all ;;
+ all | cpp | java | python | javanano | ruby) ;;
+ *) AC_MSG_FAILURE([unknown language: $DIST_LANG]) ;;
+esac
+AC_SUBST(DIST_LANG)
+
# autoconf's default CXXFLAGS are usually "-g -O2". These aren't necessarily
# the best choice for libprotobuf.
AS_IF([test "x${ac_cv_env_CFLAGS_set}" = "x"],
@@ -28,7 +37,7 @@ AS_IF([test "x${ac_cv_env_CXXFLAGS_set}" = "x"],
AC_CANONICAL_TARGET
-AM_INIT_AUTOMAKE
+AM_INIT_AUTOMAKE([1.9 tar-ustar subdir-objects])
AC_ARG_WITH([zlib],
[AS_HELP_STRING([--with-zlib],
@@ -45,6 +54,7 @@ AC_PROG_CC
AC_PROG_CXX
AC_LANG([C++])
ACX_USE_SYSTEM_EXTENSIONS
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
AM_CONDITIONAL(GCC, test "$GCC" = yes) # let the Makefile know if we're gcc
# test_util.cc takes forever to compile with GCC and optimization turned on.
@@ -89,12 +99,12 @@ AS_IF([test "$with_zlib" != no], [
# First check the zlib header version.
AC_COMPILE_IFELSE(
- AC_LANG_PROGRAM([[
+ [AC_LANG_PROGRAM([[
#include <zlib.h>
#if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
# error zlib version too old
#endif
- ]], []), [
+ ]], [])], [
AC_MSG_RESULT([ok (1.2.0.4 or later)])
# Also need to add -lz to the linker flags and make sure this succeeds.
@@ -138,6 +148,15 @@ AM_CONDITIONAL([USE_EXTERNAL_PROTOC], [test "$with_protoc" != "no"])
ACX_PTHREAD
AC_CXX_STL_HASH
+case "$target_os" in
+ mingw* | cygwin* | win*)
+ ;;
+ *)
+ # Need to link against rt on Solaris
+ AC_SEARCH_LIBS([sched_yield], [rt], [], [AC_MSG_FAILURE([sched_yield was not found on your system])])
+ ;;
+esac
+
# HACK: Make gtest's configure script pick up our copy of CFLAGS and CXXFLAGS,
# since the flags added by ACX_CHECK_SUNCC must be used when compiling gtest
# too.
diff --git a/editors/proto.vim b/editors/proto.vim
index 42f33075..23085a28 100644
--- a/editors/proto.vim
+++ b/editors/proto.vim
@@ -1,6 +1,6 @@
" Protocol Buffers - Google's data interchange format
" Copyright 2008 Google Inc. All rights reserved.
-" http://code.google.com/p/protobuf/
+" 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
@@ -54,7 +54,7 @@ syn keyword pbTodo contained TODO FIXME XXX
syn cluster pbCommentGrp contains=pbTodo
syn keyword pbSyntax syntax import option
-syn keyword pbStructure package message group
+syn keyword pbStructure package message group oneof
syn keyword pbRepeat optional required repeated
syn keyword pbDefault default
syn keyword pbExtend extend extensions to max
@@ -69,11 +69,10 @@ syn keyword pbBool true false
syn match pbInt /-\?\<\d\+\>/
syn match pbInt /\<0[xX]\x+\>/
syn match pbFloat /\<-\?\d*\(\.\d*\)\?/
-" TODO: .proto also supports C-style block comments;
-" see /usr/share/vim/vim70/syntax/c.vim for how it's done.
+syn region pbComment start="\/\*" end="\*\/" contains=@pbCommentGrp
syn region pbComment start="//" skip="\\$" end="$" keepend contains=@pbCommentGrp
-syn region pbString start=/"/ skip=/\\"/ end=/"/
-syn region pbString start=/'/ skip=/\\'/ end=/'/
+syn region pbString start=/"/ skip=/\\./ end=/"/
+syn region pbString start=/'/ skip=/\\./ end=/'/
if version >= 508 || !exists("did_proto_syn_inits")
if version < 508
diff --git a/examples/AddPerson.java b/examples/AddPerson.java
index 4917684b..ca5ac273 100644
--- a/examples/AddPerson.java
+++ b/examples/AddPerson.java
@@ -70,8 +70,11 @@ class AddPerson {
// Read the existing address book.
try {
FileInputStream input = new FileInputStream(args[0]);
- addressBook.mergeFrom(input);
- input.close();
+ try {
+ addressBook.mergeFrom(input);
+ } finally {
+ try { input.close(); } catch (Throwable ignore) {}
+ }
} catch (FileNotFoundException e) {
System.out.println(args[0] + ": File not found. Creating a new file.");
}
@@ -83,7 +86,10 @@ class AddPerson {
// Write the new address book back to disk.
FileOutputStream output = new FileOutputStream(args[0]);
- addressBook.build().writeTo(output);
- output.close();
+ try {
+ addressBook.build().writeTo(output);
+ } finally {
+ output.close();
+ }
}
}
diff --git a/examples/README.txt b/examples/README.txt
index d22bf06c..f5530a5e 100644
--- a/examples/README.txt
+++ b/examples/README.txt
@@ -22,7 +22,7 @@ All of these programs simply take an address book file as their parameter.
The add_person programs will create the file if it doesn't already exist.
These examples are part of the Protocol Buffers tutorial, located at:
- http://code.google.com/apis/protocolbuffers/docs/tutorials.html
+ https://developers.google.com/protocol-buffers/docs/tutorials
* Note that on some platforms you may have to edit the Makefile and remove
"-lpthread" from the linker commands (perhaps replacing it with something else).
diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh
index 07219dc1..b25a3c6a 100755
--- a/generate_descriptor_proto.sh
+++ b/generate_descriptor_proto.sh
@@ -27,7 +27,39 @@ __EOF__
fi
cd src
-make $@ protoc &&
- ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto && \
- ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:. google/protobuf/compiler/plugin.proto
+CORE_PROTO_IS_CORRECT=0
+while [ $CORE_PROTO_IS_CORRECT -ne 1 ]
+do
+ CORE_PROTO_IS_CORRECT=1
+ cp google/protobuf/descriptor.pb.h google/protobuf/descriptor.pb.h.tmp
+ cp google/protobuf/descriptor.pb.cc google/protobuf/descriptor.pb.cc.tmp
+ cp google/protobuf/compiler/plugin.pb.h google/protobuf/compiler/plugin.pb.h.tmp
+ cp google/protobuf/compiler/plugin.pb.cc google/protobuf/compiler/plugin.pb.cc.tmp
+
+ make $@ protoc &&
+ ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto && \
+ ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:. google/protobuf/compiler/plugin.proto
+
+ diff google/protobuf/descriptor.pb.h google/protobuf/descriptor.pb.h.tmp > /dev/null
+ if test $? -ne 0; then
+ CORE_PROTO_IS_CORRECT=0
+ fi
+ diff google/protobuf/descriptor.pb.cc google/protobuf/descriptor.pb.cc.tmp > /dev/null
+ if test $? -ne 0; then
+ CORE_PROTO_IS_CORRECT=0
+ fi
+ diff google/protobuf/compiler/plugin.pb.h google/protobuf/compiler/plugin.pb.h.tmp > /dev/null
+ if test $? -ne 0; then
+ CORE_PROTO_IS_CORRECT=0
+ fi
+ diff google/protobuf/compiler/plugin.pb.cc google/protobuf/compiler/plugin.pb.cc.tmp > /dev/null
+ if test $? -ne 0; then
+ CORE_PROTO_IS_CORRECT=0
+ fi
+
+ rm google/protobuf/descriptor.pb.h.tmp
+ rm google/protobuf/descriptor.pb.cc.tmp
+ rm google/protobuf/compiler/plugin.pb.h.tmp
+ rm google/protobuf/compiler/plugin.pb.cc.tmp
+done
cd ..
diff --git a/java/README.txt b/java/README.md
index 3ed06a1e..060d9ac6 100644
--- a/java/README.txt
+++ b/java/README.md
@@ -1,4 +1,8 @@
Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
Copyright 2008 Google Inc.
This directory contains the Java Protocol Buffers runtime library.
@@ -50,17 +54,19 @@ http://maven.apache.org/guides/introduction/introduction-to-profiles.html)
E.g. to install the lite version of the jar, you would run:
- $ mvn install -P lite
+ $ mvn install -P lite
The resulting artifact has the 'lite' classifier. To reference it
for dependency resolution, you would specify it as:
+```
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${version}</version>
<classifier>lite</classifier>
</dependency>
+```
Installation - Without Maven
============================
@@ -93,4 +99,4 @@ Usage
The complete documentation for Protocol Buffers is available via the
web at:
- http://code.google.com/apis/protocolbuffers/
+ https://developers.google.com/protocol-buffers/
diff --git a/java/pom.xml b/java/pom.xml
index 9e095207..3eb7a703 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -10,15 +10,15 @@
</parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
- <version>2.4.1</version>
- <packaging>jar</packaging>
+ <version>3.0.0-alpha-3-pre</version>
+ <packaging>bundle</packaging>
<name>Protocol Buffer Java API</name>
<description>
Protocol Buffers are a way of encoding structured data in an efficient yet
extensible format.
</description>
<inceptionYear>2008</inceptionYear>
- <url>http://code.google.com/p/protobuf</url>
+ <url>https://developers.google.com/protocol-buffers/</url>
<licenses>
<license>
<name>New BSD license</name>
@@ -27,9 +27,9 @@
</license>
</licenses>
<scm>
- <url>http://code.google.com/p/protobuf/source/browse</url>
+ <url>https://github.com/google/protobuf</url>
<connection>
- scm:svn:http://protobuf.googlecode.com/svn/trunk/
+ scm:git:https://github.com/google/protobuf.git
</connection>
</scm>
<dependencies>
@@ -102,7 +102,10 @@
<arg value="--proto_path=src/test/java" />
<arg value="../src/google/protobuf/unittest.proto" />
<arg value="../src/google/protobuf/unittest_import.proto" />
+ <arg value="../src/google/protobuf/unittest_import_public.proto" />
<arg value="../src/google/protobuf/unittest_mset.proto" />
+ <arg value="src/test/java/com/google/protobuf/lazy_fields_lite.proto" />
+ <arg value="src/test/java/com/google/protobuf/lite_equals_and_hash.proto" />
<arg
value="src/test/java/com/google/protobuf/multiple_files_test.proto" />
<arg value="src/test/java/com/google/protobuf/nested_builders_test.proto" />
@@ -110,16 +113,27 @@
<arg value="src/test/java/com/google/protobuf/nested_extension_lite.proto" />
<arg value="src/test/java/com/google/protobuf/non_nested_extension.proto" />
<arg value="src/test/java/com/google/protobuf/non_nested_extension_lite.proto" />
+ <arg value="src/test/java/com/google/protobuf/outer_class_name_test.proto" />
+ <arg value="src/test/java/com/google/protobuf/outer_class_name_test2.proto" />
+ <arg value="src/test/java/com/google/protobuf/outer_class_name_test3.proto" />
<arg value="src/test/java/com/google/protobuf/test_bad_identifiers.proto" />
+ <arg value="src/test/java/com/google/protobuf/test_check_utf8.proto" />
+ <arg value="src/test/java/com/google/protobuf/test_check_utf8_size.proto" />
+ <arg value="src/test/java/com/google/protobuf/test_custom_options.proto" />
<arg
value="../src/google/protobuf/unittest_optimize_for.proto" />
<arg
value="../src/google/protobuf/unittest_custom_options.proto" />
<arg value="../src/google/protobuf/unittest_lite.proto" />
<arg value="../src/google/protobuf/unittest_import_lite.proto" />
+ <arg value="../src/google/protobuf/unittest_import_public_lite.proto" />
<arg value="../src/google/protobuf/unittest_lite_imports_nonlite.proto" />
<arg value="../src/google/protobuf/unittest_enormous_descriptor.proto" />
<arg value="../src/google/protobuf/unittest_no_generic_services.proto" />
+ <arg value="src/test/java/com/google/protobuf/field_presence_test.proto" />
+ <arg value="src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto" />
+ <arg value="src/test/java/com/google/protobuf/map_for_proto2_test.proto" />
+ <arg value="src/test/java/com/google/protobuf/map_test.proto" />
</exec>
</tasks>
<testSourceRoot>target/generated-test-sources</testSourceRoot>
@@ -130,10 +144,80 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
+ <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
+ <Export-Package>com.google.protobuf;version=3.0.0-alpha-3-pre</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
</plugins>
</build>
<profiles>
<profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.2.1</version>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9.1</version>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>nexus-staging-maven-plugin</artifactId>
+ <version>1.6.3</version>
+ <extensions>true</extensions>
+ <configuration>
+ <serverId>sonatype-nexus-staging</serverId>
+ <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+ <autoReleaseAfterClose>false</autoReleaseAfterClose>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
<id>lite</id>
<build>
<plugins>
@@ -142,26 +226,40 @@
<configuration>
<includes>
<include>**/AbstractMessageLite.java</include>
+ <include>**/AbstractParser.java</include>
+ <include>**/BoundedByteString.java</include>
<include>**/ByteString.java</include>
<include>**/CodedInputStream.java</include>
<include>**/CodedOutputStream.java</include>
+ <include>**/ExtensionLite.java</include>
<include>**/ExtensionRegistryLite.java</include>
<include>**/FieldSet.java</include>
<include>**/GeneratedMessageLite.java</include>
<include>**/Internal.java</include>
<include>**/InvalidProtocolBufferException.java</include>
+ <include>**/LazyFieldLite.java</include>
<include>**/LazyStringArrayList.java</include>
<include>**/LazyStringList.java</include>
+ <include>**/LiteralByteString.java</include>
+ <include>**/MapEntryLite.java</include>
+ <include>**/MapFieldLite.java</include>
<include>**/MessageLite.java</include>
<include>**/MessageLiteOrBuilder.java</include>
+ <include>**/Parser.java</include>
+ <include>**/ProtocolStringList.java</include>
+ <include>**/RopeByteString.java</include>
<include>**/SmallSortedMap.java</include>
<include>**/UninitializedMessageException.java</include>
+ <include>**/UnknownFieldSetLite.java</include>
<include>**/UnmodifiableLazyStringList.java</include>
+ <include>**/Utf8.java</include>
<include>**/WireFormat.java</include>
</includes>
<testIncludes>
- <testInclude>**/LiteTest.java</testInclude>
<testInclude>**/*Lite.java</testInclude>
+ <testInclude>**/LazyMessageLiteTest.java</testInclude>
+ <testInclude>**/LiteTest.java</testInclude>
+ <testInclude>**/UnknownFieldSetLiteTest.java</testInclude>
</testIncludes>
</configuration>
</plugin>
@@ -169,7 +267,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
- <include>**/LiteTest.java</include>
+ <include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java
index b9d83016..cc89173a 100644
--- a/java/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,13 +30,16 @@
package com.google.protobuf;
-import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.Internal.EnumLite;
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -48,37 +51,30 @@ import java.util.Map;
*/
public abstract class AbstractMessage extends AbstractMessageLite
implements Message {
- @SuppressWarnings("unchecked")
public boolean isInitialized() {
- // Check that all required fields are present.
- for (final FieldDescriptor field : getDescriptorForType().getFields()) {
- if (field.isRequired()) {
- if (!hasField(field)) {
- return false;
- }
- }
- }
+ return MessageReflection.isInitialized(this);
+ }
- // Check that embedded messages are initialized.
- for (final Map.Entry<FieldDescriptor, Object> entry :
- getAllFields().entrySet()) {
- final FieldDescriptor field = entry.getKey();
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
- if (field.isRepeated()) {
- for (final Message element : (List<Message>) entry.getValue()) {
- if (!element.isInitialized()) {
- return false;
- }
- }
- } else {
- if (!((Message) entry.getValue()).isInitialized()) {
- return false;
- }
- }
- }
- }
- return true;
+ public List<String> findInitializationErrors() {
+ return MessageReflection.findMissingFields(this);
+ }
+
+ public String getInitializationErrorString() {
+ return MessageReflection.delimitWithCommas(findInitializationErrors());
+ }
+
+ /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+ @Override
+ public boolean hasOneof(OneofDescriptor oneof) {
+ throw new UnsupportedOperationException("hasOneof() is not implemented.");
+ }
+
+ /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+ @Override
+ public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+ throw new UnsupportedOperationException(
+ "getOneofFieldDescriptor() is not implemented.");
}
@Override
@@ -87,31 +83,10 @@ public abstract class AbstractMessage extends AbstractMessageLite
}
public void writeTo(final CodedOutputStream output) throws IOException {
- final boolean isMessageSet =
- getDescriptorForType().getOptions().getMessageSetWireFormat();
-
- for (final Map.Entry<FieldDescriptor, Object> entry :
- getAllFields().entrySet()) {
- final FieldDescriptor field = entry.getKey();
- final Object value = entry.getValue();
- if (isMessageSet && field.isExtension() &&
- field.getType() == FieldDescriptor.Type.MESSAGE &&
- !field.isRepeated()) {
- output.writeMessageSetExtension(field.getNumber(), (Message) value);
- } else {
- FieldSet.writeField(field, value, output);
- }
- }
-
- final UnknownFieldSet unknownFields = getUnknownFields();
- if (isMessageSet) {
- unknownFields.writeAsMessageSetTo(output);
- } else {
- unknownFields.writeTo(output);
- }
+ MessageReflection.writeMessageTo(this, getAllFields(), output, false);
}
- private int memoizedSize = -1;
+ protected int memoizedSize = -1;
public int getSerializedSize() {
int size = memoizedSize;
@@ -119,33 +94,8 @@ public abstract class AbstractMessage extends AbstractMessageLite
return size;
}
- size = 0;
- final boolean isMessageSet =
- getDescriptorForType().getOptions().getMessageSetWireFormat();
-
- for (final Map.Entry<FieldDescriptor, Object> entry :
- getAllFields().entrySet()) {
- final FieldDescriptor field = entry.getKey();
- final Object value = entry.getValue();
- if (isMessageSet && field.isExtension() &&
- field.getType() == FieldDescriptor.Type.MESSAGE &&
- !field.isRepeated()) {
- size += CodedOutputStream.computeMessageSetExtensionSize(
- field.getNumber(), (Message) value);
- } else {
- size += FieldSet.computeFieldSize(field, value);
- }
- }
-
- final UnknownFieldSet unknownFields = getUnknownFields();
- if (isMessageSet) {
- size += unknownFields.getSerializedSizeAsMessageSet();
- } else {
- size += unknownFields.getSerializedSize();
- }
-
- memoizedSize = size;
- return size;
+ memoizedSize = MessageReflection.getSerializedSize(this, getAllFields());
+ return memoizedSize;
}
@Override
@@ -160,72 +110,165 @@ public abstract class AbstractMessage extends AbstractMessageLite
if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
return false;
}
- return getAllFields().equals(otherMessage.getAllFields()) &&
+ return compareFields(getAllFields(), otherMessage.getAllFields()) &&
getUnknownFields().equals(otherMessage.getUnknownFields());
}
@Override
public int hashCode() {
- int hash = 41;
- hash = (19 * hash) + getDescriptorForType().hashCode();
- hash = hashFields(hash, getAllFields());
- hash = (29 * hash) + getUnknownFields().hashCode();
+ int hash = memoizedHashCode;
+ if (hash == 0) {
+ hash = 41;
+ hash = (19 * hash) + getDescriptorForType().hashCode();
+ hash = hashFields(hash, getAllFields());
+ hash = (29 * hash) + getUnknownFields().hashCode();
+ memoizedHashCode = hash;
+ }
return hash;
}
+
+ private static ByteString toByteString(Object value) {
+ if (value instanceof byte[]) {
+ return ByteString.copyFrom((byte[]) value);
+ } else {
+ return (ByteString) value;
+ }
+ }
+
+ /**
+ * Compares two bytes fields. The parameters must be either a byte array or a
+ * ByteString object. They can be of different type though.
+ */
+ private static boolean compareBytes(Object a, Object b) {
+ if (a instanceof byte[] && b instanceof byte[]) {
+ return Arrays.equals((byte[])a, (byte[])b);
+ }
+ 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)}
+ * and {@link AbstractMutableMessage#equals(Object)}. It takes special care
+ * of bytes fields because immutable messages and mutable messages use
+ * different Java type to reprensent a bytes field and this method should be
+ * able to compare immutable messages, mutable messages and also an immutable
+ * message to a mutable message.
+ */
+ static boolean compareFields(Map<FieldDescriptor, Object> a,
+ Map<FieldDescriptor, Object> b) {
+ if (a.size() != b.size()) {
+ return false;
+ }
+ for (FieldDescriptor descriptor : a.keySet()) {
+ if (!b.containsKey(descriptor)) {
+ return false;
+ }
+ Object value1 = a.get(descriptor);
+ Object value2 = b.get(descriptor);
+ if (descriptor.getType() == FieldDescriptor.Type.BYTES) {
+ if (descriptor.isRepeated()) {
+ List list1 = (List) value1;
+ List list2 = (List) value2;
+ if (list1.size() != list2.size()) {
+ return false;
+ }
+ for (int i = 0; i < list1.size(); i++) {
+ if (!compareBytes(list1.get(i), list2.get(i))) {
+ return false;
+ }
+ }
+ } else {
+ // Compares a singular bytes field.
+ if (!compareBytes(value1, value2)) {
+ return false;
+ }
+ }
+ } else if (descriptor.isMapField()) {
+ if (!compareMapField(value1, value2)) {
+ return false;
+ }
+ } else {
+ // Compare non-bytes fields.
+ if (!value1.equals(value2)) {
+ return false;
+ }
+ }
+ }
+ 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")
- protected int hashFields(int hash, Map<FieldDescriptor, Object> map) {
+ protected static int hashFields(int hash, Map<FieldDescriptor, Object> map) {
for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
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<? extends EnumLite> list = (List<? extends EnumLite>) value;
- hash = (53 * hash) + hashEnumList(list);
+ hash = (53 * hash) + Internal.hashEnumList(list);
} else {
- hash = (53 * hash) + hashEnum((EnumLite) value);
+ hash = (53 * hash) + Internal.hashEnum((EnumLite) value);
}
}
return hash;
}
/**
- * Helper method for implementing {@link Message#hashCode()}.
- * @see Boolean#hashCode()
- */
- protected static int hashLong(long n) {
- return (int) (n ^ (n >>> 32));
- }
-
- /**
- * Helper method for implementing {@link Message#hashCode()}.
- * @see Boolean#hashCode()
- */
- protected static int hashBoolean(boolean b) {
- return b ? 1231 : 1237;
- }
-
- /**
- * Helper method for implementing {@link Message#hashCode()}.
- * <p>
- * This is needed because {@link java.lang.Enum#hashCode()} is final, but we
- * need to use the field number as the hash code to ensure compatibility
- * between statically and dynamically generated enum objects.
+ * Package private helper method for AbstractParser to create
+ * UninitializedMessageException with missing field information.
*/
- protected static int hashEnum(EnumLite e) {
- return e.getNumber();
- }
-
- /** Helper method for implementing {@link Message#hashCode()}. */
- protected static int hashEnumList(List<? extends EnumLite> list) {
- int hash = 1;
- for (EnumLite e : list) {
- hash = 31 * hash + hashEnum(e);
- }
- return hash;
+ @Override
+ UninitializedMessageException newUninitializedMessageException() {
+ return Builder.newUninitializedMessageException(this);
}
// =================================================================
@@ -243,6 +286,25 @@ public abstract class AbstractMessage extends AbstractMessageLite
@Override
public abstract BuilderType clone();
+ /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+ @Override
+ public boolean hasOneof(OneofDescriptor oneof) {
+ throw new UnsupportedOperationException("hasOneof() is not implemented.");
+ }
+
+ /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+ @Override
+ public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+ throw new UnsupportedOperationException(
+ "getOneofFieldDescriptor() is not implemented.");
+ }
+
+ /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+ @Override
+ public BuilderType clearOneof(OneofDescriptor oneof) {
+ throw new UnsupportedOperationException("clearOneof() is not implemented.");
+ }
+
public BuilderType clear() {
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
@@ -251,6 +313,14 @@ public abstract class AbstractMessage extends AbstractMessageLite
return (BuilderType) this;
}
+ public List<String> findInitializationErrors() {
+ return MessageReflection.findMissingFields(this);
+ }
+
+ public String getInitializationErrorString() {
+ return MessageReflection.delimitWithCommas(findInitializationErrors());
+ }
+
public BuilderType mergeFrom(final Message other) {
if (other.getDescriptorForType() != getDescriptorForType()) {
throw new IllegalArgumentException(
@@ -313,8 +383,13 @@ public abstract class AbstractMessage extends AbstractMessageLite
break;
}
- if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
- this, tag)) {
+ MessageReflection.BuilderAdapter builderAdapter =
+ new MessageReflection.BuilderAdapter(this);
+ if (!MessageReflection.mergeFieldFrom(input, unknownFields,
+ extensionRegistry,
+ getDescriptorForType(),
+ builderAdapter,
+ tag)) {
// end group tag
break;
}
@@ -323,271 +398,6 @@ public abstract class AbstractMessage extends AbstractMessageLite
return (BuilderType) this;
}
- /**
- * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
- * ExtensionRegistryLite, Message.Builder)}, but parses a single field.
- * Package-private because it is used by GeneratedMessage.ExtendableMessage.
- * @param tag The tag, which should have already been read.
- * @return {@code true} unless the tag is an end-group tag.
- */
- static boolean mergeFieldFrom(
- final CodedInputStream input,
- final UnknownFieldSet.Builder unknownFields,
- final ExtensionRegistryLite extensionRegistry,
- final Message.Builder builder,
- final int tag) throws IOException {
- final Descriptor type = builder.getDescriptorForType();
-
- if (type.getOptions().getMessageSetWireFormat() &&
- tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
- mergeMessageSetExtensionFromCodedStream(
- input, unknownFields, extensionRegistry, builder);
- return true;
- }
-
- final int wireType = WireFormat.getTagWireType(tag);
- final int fieldNumber = WireFormat.getTagFieldNumber(tag);
-
- final FieldDescriptor field;
- Message defaultInstance = null;
-
- if (type.isExtensionNumber(fieldNumber)) {
- // extensionRegistry may be either ExtensionRegistry or
- // ExtensionRegistryLite. Since the type we are parsing is a full
- // message, only a full ExtensionRegistry could possibly contain
- // extensions of it. Otherwise we will treat the registry as if it
- // were empty.
- if (extensionRegistry instanceof ExtensionRegistry) {
- final ExtensionRegistry.ExtensionInfo extension =
- ((ExtensionRegistry) extensionRegistry)
- .findExtensionByNumber(type, fieldNumber);
- if (extension == null) {
- field = null;
- } else {
- field = extension.descriptor;
- defaultInstance = extension.defaultInstance;
- if (defaultInstance == null &&
- field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
- throw new IllegalStateException(
- "Message-typed extension lacked default instance: " +
- field.getFullName());
- }
- }
- } else {
- field = null;
- }
- } else {
- field = type.findFieldByNumber(fieldNumber);
- }
-
- boolean unknown = false;
- boolean packed = false;
- if (field == null) {
- unknown = true; // Unknown field.
- } else if (wireType == FieldSet.getWireFormatForFieldType(
- field.getLiteType(),
- false /* isPacked */)) {
- packed = false;
- } else if (field.isPackable() &&
- wireType == FieldSet.getWireFormatForFieldType(
- field.getLiteType(),
- true /* isPacked */)) {
- packed = true;
- } else {
- unknown = true; // Unknown wire type.
- }
-
- if (unknown) { // Unknown field or wrong wire type. Skip.
- return unknownFields.mergeFieldFrom(tag, input);
- }
-
- if (packed) {
- final int length = input.readRawVarint32();
- final int limit = input.pushLimit(length);
- 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;
- }
- builder.addRepeatedField(field, value);
- }
- } else {
- while (input.getBytesUntilLimit() > 0) {
- final Object value =
- FieldSet.readPrimitiveField(input, field.getLiteType());
- builder.addRepeatedField(field, value);
- }
- }
- input.popLimit(limit);
- } else {
- final Object value;
- switch (field.getType()) {
- case GROUP: {
- final Message.Builder subBuilder;
- if (defaultInstance != null) {
- subBuilder = defaultInstance.newBuilderForType();
- } else {
- subBuilder = builder.newBuilderForField(field);
- }
- if (!field.isRepeated()) {
- subBuilder.mergeFrom((Message) builder.getField(field));
- }
- input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
- value = subBuilder.build();
- break;
- }
- case MESSAGE: {
- final Message.Builder subBuilder;
- if (defaultInstance != null) {
- subBuilder = defaultInstance.newBuilderForType();
- } else {
- subBuilder = builder.newBuilderForField(field);
- }
- if (!field.isRepeated()) {
- subBuilder.mergeFrom((Message) builder.getField(field));
- }
- input.readMessage(subBuilder, extensionRegistry);
- value = subBuilder.build();
- break;
- }
- 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;
- }
- break;
- default:
- value = FieldSet.readPrimitiveField(input, field.getLiteType());
- break;
- }
-
- if (field.isRepeated()) {
- builder.addRepeatedField(field, value);
- } else {
- builder.setField(field, value);
- }
- }
-
- return true;
- }
-
- /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */
- private static void mergeMessageSetExtensionFromCodedStream(
- final CodedInputStream input,
- final UnknownFieldSet.Builder unknownFields,
- final ExtensionRegistryLite extensionRegistry,
- final Message.Builder builder) throws IOException {
- final Descriptor type = builder.getDescriptorForType();
-
- // The wire format for MessageSet is:
- // message MessageSet {
- // repeated group Item = 1 {
- // required int32 typeId = 2;
- // required bytes message = 3;
- // }
- // }
- // "typeId" is the extension's field number. The extension can only be
- // a message type, where "message" contains the encoded bytes of that
- // message.
- //
- // In practice, we will probably never see a MessageSet item in which
- // the message appears before the type ID, or where either field does not
- // appear exactly once. However, in theory such cases are valid, so we
- // should be prepared to accept them.
-
- int typeId = 0;
- ByteString rawBytes = null; // If we encounter "message" before "typeId"
- Message.Builder subBuilder = null;
- FieldDescriptor field = null;
-
- while (true) {
- final int tag = input.readTag();
- if (tag == 0) {
- break;
- }
-
- if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
- typeId = input.readUInt32();
- // Zero is not a valid type ID.
- if (typeId != 0) {
- final ExtensionRegistry.ExtensionInfo extension;
-
- // extensionRegistry may be either ExtensionRegistry or
- // ExtensionRegistryLite. Since the type we are parsing is a full
- // message, only a full ExtensionRegistry could possibly contain
- // extensions of it. Otherwise we will treat the registry as if it
- // were empty.
- if (extensionRegistry instanceof ExtensionRegistry) {
- extension = ((ExtensionRegistry) extensionRegistry)
- .findExtensionByNumber(type, typeId);
- } else {
- extension = null;
- }
-
- if (extension != null) {
- field = extension.descriptor;
- subBuilder = extension.defaultInstance.newBuilderForType();
- final Message originalMessage = (Message)builder.getField(field);
- if (originalMessage != null) {
- subBuilder.mergeFrom(originalMessage);
- }
- if (rawBytes != null) {
- // We already encountered the message. Parse it now.
- subBuilder.mergeFrom(
- CodedInputStream.newInstance(rawBytes.newInput()));
- rawBytes = null;
- }
- } else {
- // Unknown extension number. If we already saw data, put it
- // in rawBytes.
- if (rawBytes != null) {
- unknownFields.mergeField(typeId,
- UnknownFieldSet.Field.newBuilder()
- .addLengthDelimited(rawBytes)
- .build());
- rawBytes = null;
- }
- }
- }
- } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
- if (typeId == 0) {
- // We haven't seen a type ID yet, so we have to store the raw bytes
- // for now.
- rawBytes = input.readBytes();
- } else if (subBuilder == null) {
- // We don't know how to parse this. Ignore it.
- unknownFields.mergeField(typeId,
- UnknownFieldSet.Field.newBuilder()
- .addLengthDelimited(input.readBytes())
- .build());
- } else {
- // We already know the type, so we can parse directly from the input
- // with no copying. Hooray!
- input.readMessage(subBuilder, extensionRegistry);
- }
- } else {
- // Unknown tag. Skip it.
- if (!input.skipField(tag)) {
- break; // end of group
- }
- }
- }
-
- input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
-
- if (subBuilder != null) {
- builder.setField(field, subBuilder.build());
- }
- }
-
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
setUnknownFields(
UnknownFieldSet.newBuilder(getUnknownFields())
@@ -596,78 +406,29 @@ public abstract class AbstractMessage extends AbstractMessageLite
return (BuilderType) this;
}
+ public Message.Builder getFieldBuilder(final FieldDescriptor field) {
+ throw new UnsupportedOperationException(
+ "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);
+ }
+
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
*/
protected static UninitializedMessageException
newUninitializedMessageException(Message message) {
- return new UninitializedMessageException(findMissingFields(message));
- }
-
- /**
- * Populates {@code this.missingFields} with the full "path" of each
- * missing required field in the given message.
- */
- private static List<String> findMissingFields(final Message message) {
- final List<String> results = new ArrayList<String>();
- findMissingFields(message, "", results);
- return results;
- }
-
- /** Recursive helper implementing {@link #findMissingFields(Message)}. */
- private static void findMissingFields(final Message message,
- final String prefix,
- final List<String> results) {
- for (final FieldDescriptor field :
- message.getDescriptorForType().getFields()) {
- if (field.isRequired() && !message.hasField(field)) {
- results.add(prefix + field.getName());
- }
- }
-
- for (final Map.Entry<FieldDescriptor, Object> entry :
- message.getAllFields().entrySet()) {
- final FieldDescriptor field = entry.getKey();
- final Object value = entry.getValue();
-
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
- if (field.isRepeated()) {
- int i = 0;
- for (final Object element : (List) value) {
- findMissingFields((Message) element,
- subMessagePrefix(prefix, field, i++),
- results);
- }
- } else {
- if (message.hasField(field)) {
- findMissingFields((Message) value,
- subMessagePrefix(prefix, field, -1),
- results);
- }
- }
- }
- }
- }
-
- private static String subMessagePrefix(final String prefix,
- final FieldDescriptor field,
- final int index) {
- final StringBuilder result = new StringBuilder(prefix);
- if (field.isExtension()) {
- result.append('(')
- .append(field.getFullName())
- .append(')');
- } else {
- result.append(field.getName());
- }
- if (index != -1) {
- result.append('[')
- .append(index)
- .append(']');
- }
- result.append('.');
- return result.toString();
+ return new UninitializedMessageException(
+ MessageReflection.findMissingFields(message));
}
// ===============================================================
@@ -759,6 +520,5 @@ public abstract class AbstractMessage extends AbstractMessageLite
throws IOException {
return super.mergeDelimitedFrom(input, extensionRegistry);
}
-
}
}
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
index 77b27370..aac4fa77 100644
--- a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -44,6 +44,8 @@ import java.util.Collection;
* @author kenton@google.com Kenton Varda
*/
public abstract class AbstractMessageLite implements MessageLite {
+ protected int memoizedHashCode = 0;
+
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
@@ -91,6 +93,22 @@ public abstract class AbstractMessageLite implements MessageLite {
codedOutput.flush();
}
+
+ /**
+ * Package private helper method for AbstractParser to create
+ * UninitializedMessageException.
+ */
+ UninitializedMessageException newUninitializedMessageException() {
+ return new UninitializedMessageException(this);
+ }
+
+ protected static void checkByteStringIsUtf8(ByteString byteString)
+ throws IllegalArgumentException {
+ if (!byteString.isValidUtf8()) {
+ throw new IllegalArgumentException("Byte string is not UTF-8.");
+ }
+ }
+
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
@@ -303,23 +321,35 @@ public abstract class AbstractMessageLite implements MessageLite {
* used by generated code. Users should ignore it.
*
* @throws NullPointerException if any of the elements of {@code values} is
- * null.
+ * null. When that happens, some elements of {@code values} may have already
+ * been added to the result {@code list}.
*/
protected static <T> void addAll(final Iterable<T> values,
final Collection<? super T> list) {
- for (final T value : values) {
- if (value == null) {
- throw new NullPointerException();
- }
- }
- if (values instanceof Collection) {
- final Collection<T> collection = (Collection<T>) values;
- list.addAll(collection);
+ if (values instanceof LazyStringList) {
+ // For StringOrByteStringLists, check the underlying elements to avoid
+ // forcing conversions of ByteStrings to Strings.
+ checkForNullValues(((LazyStringList) values).getUnderlyingElements());
+ list.addAll((Collection<T>) values);
+ } else if (values instanceof Collection) {
+ checkForNullValues(values);
+ list.addAll((Collection<T>) values);
} else {
for (final T value : values) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
list.add(value);
}
}
}
+
+ private static void checkForNullValues(final Iterable<?> values) {
+ for (final Object value : values) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ }
+ }
}
}
diff --git a/java/src/main/java/com/google/protobuf/AbstractParser.java b/java/src/main/java/com/google/protobuf/AbstractParser.java
new file mode 100644
index 00000000..1a4c6311
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/AbstractParser.java
@@ -0,0 +1,253 @@
+// 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.AbstractMessageLite.Builder.LimitedInputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A partial implementation of the {@link Parser} interface which implements
+ * as many methods of that interface as possible in terms of other methods.
+ *
+ * Note: This class implements all the convenience methods in the
+ * {@link Parser} interface. See {@link Parser} for related javadocs.
+ * Subclasses need to implement
+ * {@link Parser#parsePartialFrom(CodedInputStream, ExtensionRegistryLite)}
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+public abstract class AbstractParser<MessageType extends MessageLite>
+ implements Parser<MessageType> {
+ /**
+ * Creates an UninitializedMessageException for MessageType.
+ */
+ private UninitializedMessageException
+ newUninitializedMessageException(MessageType message) {
+ if (message instanceof AbstractMessageLite) {
+ return ((AbstractMessageLite) message).newUninitializedMessageException();
+ }
+ return new UninitializedMessageException(message);
+ }
+
+ /**
+ * Helper method to check if message is initialized.
+ *
+ * @throws InvalidProtocolBufferException if it is not initialized.
+ * @return The message to check.
+ */
+ private MessageType checkMessageInitialized(MessageType message)
+ throws InvalidProtocolBufferException {
+ if (message != null && !message.isInitialized()) {
+ throw newUninitializedMessageException(message)
+ .asInvalidProtocolBufferException()
+ .setUnfinishedMessage(message);
+ }
+ return message;
+ }
+
+ private static final ExtensionRegistryLite EMPTY_REGISTRY
+ = ExtensionRegistryLite.getEmptyRegistry();
+
+ public MessageType parsePartialFrom(CodedInputStream input)
+ throws InvalidProtocolBufferException {
+ return parsePartialFrom(input, EMPTY_REGISTRY);
+ }
+
+ public MessageType parseFrom(CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialFrom(input, extensionRegistry));
+ }
+
+ public MessageType parseFrom(CodedInputStream input)
+ throws InvalidProtocolBufferException {
+ return parseFrom(input, EMPTY_REGISTRY);
+ }
+
+ public MessageType parsePartialFrom(ByteString data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ MessageType message;
+ try {
+ CodedInputStream input = data.newCodedInput();
+ message = parsePartialFrom(input, extensionRegistry);
+ try {
+ input.checkLastTagWas(0);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(message);
+ }
+ return message;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ }
+ }
+
+ public MessageType parsePartialFrom(ByteString data)
+ throws InvalidProtocolBufferException {
+ return parsePartialFrom(data, EMPTY_REGISTRY);
+ }
+
+ public MessageType parseFrom(ByteString data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(parsePartialFrom(data, extensionRegistry));
+ }
+
+ public MessageType parseFrom(ByteString data)
+ throws InvalidProtocolBufferException {
+ return parseFrom(data, EMPTY_REGISTRY);
+ }
+
+ public MessageType parsePartialFrom(byte[] data, int off, int len,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ try {
+ CodedInputStream input = CodedInputStream.newInstance(data, off, len);
+ MessageType message = parsePartialFrom(input, extensionRegistry);
+ try {
+ input.checkLastTagWas(0);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(message);
+ }
+ return message;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ }
+ }
+
+ public MessageType parsePartialFrom(byte[] data, int off, int len)
+ throws InvalidProtocolBufferException {
+ return parsePartialFrom(data, off, len, EMPTY_REGISTRY);
+ }
+
+ public MessageType parsePartialFrom(byte[] data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return parsePartialFrom(data, 0, data.length, extensionRegistry);
+ }
+
+ public MessageType parsePartialFrom(byte[] data)
+ throws InvalidProtocolBufferException {
+ return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY);
+ }
+
+ public MessageType parseFrom(byte[] data, int off, int len,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialFrom(data, off, len, extensionRegistry));
+ }
+
+ public MessageType parseFrom(byte[] data, int off, int len)
+ throws InvalidProtocolBufferException {
+ return parseFrom(data, off, len, EMPTY_REGISTRY);
+ }
+
+ public MessageType parseFrom(byte[] data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return parseFrom(data, 0, data.length, extensionRegistry);
+ }
+
+ public MessageType parseFrom(byte[] data)
+ throws InvalidProtocolBufferException {
+ return parseFrom(data, EMPTY_REGISTRY);
+ }
+
+ public MessageType parsePartialFrom(InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ CodedInputStream codedInput = CodedInputStream.newInstance(input);
+ MessageType message = parsePartialFrom(codedInput, extensionRegistry);
+ try {
+ codedInput.checkLastTagWas(0);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(message);
+ }
+ return message;
+ }
+
+ public MessageType parsePartialFrom(InputStream input)
+ throws InvalidProtocolBufferException {
+ return parsePartialFrom(input, EMPTY_REGISTRY);
+ }
+
+ public MessageType parseFrom(InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialFrom(input, extensionRegistry));
+ }
+
+ public MessageType parseFrom(InputStream input)
+ throws InvalidProtocolBufferException {
+ return parseFrom(input, EMPTY_REGISTRY);
+ }
+
+ public MessageType parsePartialDelimitedFrom(
+ InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ int size;
+ try {
+ int firstByte = input.read();
+ if (firstByte == -1) {
+ return null;
+ }
+ size = CodedInputStream.readRawVarint32(firstByte, input);
+ } catch (IOException e) {
+ throw new InvalidProtocolBufferException(e.getMessage());
+ }
+ InputStream limitedInput = new LimitedInputStream(input, size);
+ return parsePartialFrom(limitedInput, extensionRegistry);
+ }
+
+ public MessageType parsePartialDelimitedFrom(InputStream input)
+ throws InvalidProtocolBufferException {
+ return parsePartialDelimitedFrom(input, EMPTY_REGISTRY);
+ }
+
+ public MessageType parseDelimitedFrom(
+ InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialDelimitedFrom(input, extensionRegistry));
+ }
+
+ public MessageType parseDelimitedFrom(InputStream input)
+ throws InvalidProtocolBufferException {
+ return parseDelimitedFrom(input, EMPTY_REGISTRY);
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java b/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
index 1e81143a..d535efb9 100644
--- a/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
+++ b/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/main/java/com/google/protobuf/BlockingService.java b/java/src/main/java/com/google/protobuf/BlockingService.java
index ecc80096..d01f0b8f 100644
--- a/java/src/main/java/com/google/protobuf/BlockingService.java
+++ b/java/src/main/java/com/google/protobuf/BlockingService.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/main/java/com/google/protobuf/BoundedByteString.java b/java/src/main/java/com/google/protobuf/BoundedByteString.java
new file mode 100644
index 00000000..b4c3fb1b
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/BoundedByteString.java
@@ -0,0 +1,180 @@
+// 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;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.util.NoSuchElementException;
+
+/**
+ * This class is used to represent the substring of a {@link ByteString} over a
+ * single byte array. In terms of the public API of {@link ByteString}, you end
+ * up here by calling {@link ByteString#copyFrom(byte[])} followed by {@link
+ * ByteString#substring(int, int)}.
+ *
+ * <p>This class contains most of the overhead involved in creating a substring
+ * from a {@link LiteralByteString}. The overhead involves some range-checking
+ * and two extra fields.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+class BoundedByteString extends LiteralByteString {
+
+ private final int bytesOffset;
+ private final int bytesLength;
+
+ /**
+ * Creates a {@code BoundedByteString} backed by the sub-range of given array,
+ * without copying.
+ *
+ * @param bytes array to wrap
+ * @param offset index to first byte to use in bytes
+ * @param length number of bytes to use from bytes
+ * @throws IllegalArgumentException if {@code offset < 0}, {@code length < 0},
+ * or if {@code offset + length >
+ * bytes.length}.
+ */
+ BoundedByteString(byte[] bytes, int offset, int length) {
+ super(bytes);
+ if (offset < 0) {
+ throw new IllegalArgumentException("Offset too small: " + offset);
+ }
+ if (length < 0) {
+ throw new IllegalArgumentException("Length too small: " + offset);
+ }
+ if ((long) offset + length > bytes.length) {
+ throw new IllegalArgumentException(
+ "Offset+Length too large: " + offset + "+" + length);
+ }
+
+ this.bytesOffset = offset;
+ this.bytesLength = length;
+ }
+
+ /**
+ * Gets the byte at the given index.
+ * Throws {@link ArrayIndexOutOfBoundsException}
+ * for backwards-compatibility reasons although it would more properly be
+ * {@link IndexOutOfBoundsException}.
+ *
+ * @param index index of byte
+ * @return the value
+ * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
+ */
+ @Override
+ public byte byteAt(int index) {
+ // We must check the index ourselves as we cannot rely on Java array index
+ // checking for substrings.
+ if (index < 0) {
+ throw new ArrayIndexOutOfBoundsException("Index too small: " + index);
+ }
+ if (index >= size()) {
+ throw new ArrayIndexOutOfBoundsException(
+ "Index too large: " + index + ", " + size());
+ }
+
+ return bytes[bytesOffset + index];
+ }
+
+ @Override
+ public int size() {
+ return bytesLength;
+ }
+
+ @Override
+ protected int getOffsetIntoBytes() {
+ return bytesOffset;
+ }
+
+ // =================================================================
+ // ByteString -> byte[]
+
+ @Override
+ protected void copyToInternal(byte[] target, int sourceOffset,
+ int targetOffset, int numberToCopy) {
+ System.arraycopy(bytes, getOffsetIntoBytes() + sourceOffset, target,
+ targetOffset, numberToCopy);
+ }
+
+ // =================================================================
+ // Serializable
+
+ private static final long serialVersionUID = 1L;
+
+ Object writeReplace() {
+ return new LiteralByteString(toByteArray());
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException {
+ throw new InvalidObjectException(
+ "BoundedByteStream instances are not to be serialized directly");
+ }
+
+ // =================================================================
+ // ByteIterator
+
+ @Override
+ public ByteIterator iterator() {
+ return new BoundedByteIterator();
+ }
+
+ private class BoundedByteIterator implements ByteIterator {
+
+ private int position;
+ private final int limit;
+
+ private BoundedByteIterator() {
+ position = getOffsetIntoBytes();
+ limit = position + size();
+ }
+
+ public boolean hasNext() {
+ return (position < limit);
+ }
+
+ public Byte next() {
+ // Boxing calls Byte.valueOf(byte), which does not instantiate.
+ return nextByte();
+ }
+
+ public byte nextByte() {
+ if (position >= limit) {
+ throw new NoSuchElementException();
+ }
+ return bytes[position++];
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/ByteString.java b/java/src/main/java/com/google/protobuf/ByteString.java
index 91356357..9b0a524b 100644
--- a/java/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/src/main/java/com/google/protobuf/ByteString.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,140 +30,430 @@
package com.google.protobuf;
-import java.io.InputStream;
-import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
+import java.util.NoSuchElementException;
/**
- * Immutable array of bytes.
+ * Immutable sequence of bytes. Substring is supported by sharing the reference
+ * to the immutable underlying bytes, as with {@link String}. Concatenation is
+ * likewise supported without copying (long strings) by building a tree of
+ * pieces in {@link RopeByteString}.
+ * <p>
+ * Like {@link String}, the contents of a {@link ByteString} can never be
+ * observed to change, not even in the presence of a data race or incorrect
+ * API usage in the client code.
*
* @author crazybob@google.com Bob Lee
* @author kenton@google.com Kenton Varda
+ * @author carlanton@google.com Carl Haverl
+ * @author martinrb@google.com Martin Buchholz
*/
-public final class ByteString {
- private final byte[] bytes;
+public abstract class ByteString implements Iterable<Byte>, Serializable {
- private ByteString(final byte[] bytes) {
- this.bytes = bytes;
- }
+ /**
+ * When two strings to be concatenated have a combined length shorter than
+ * this, we just copy their bytes on {@link #concat(ByteString)}.
+ * The trade-off is copy size versus the overhead of creating tree nodes
+ * in {@link RopeByteString}.
+ */
+ static final int CONCATENATE_BY_COPY_SIZE = 128;
/**
- * Gets the byte at the given index.
+ * When copying an InputStream into a ByteString with .readFrom(),
+ * the chunks in the underlying rope start at 256 bytes, but double
+ * each iteration up to 8192 bytes.
+ */
+ static final int MIN_READ_FROM_CHUNK_SIZE = 0x100; // 256b
+ static final int MAX_READ_FROM_CHUNK_SIZE = 0x2000; // 8k
+
+ // Defined by java.nio.charset.Charset
+ protected static final String UTF_8 = "UTF-8";
+
+ /**
+ * Empty {@code ByteString}.
+ */
+ public static final ByteString EMPTY = new LiteralByteString(new byte[0]);
+
+ // This constructor is here to prevent subclassing outside of this package,
+ ByteString() {}
+
+ /**
+ * Gets the byte at the given index. This method should be used only for
+ * random access to individual bytes. To access bytes sequentially, use the
+ * {@link ByteIterator} returned by {@link #iterator()}, and call {@link
+ * #substring(int, int)} first if necessary.
*
+ * @param index index of byte
+ * @return the value
* @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
*/
- public byte byteAt(final int index) {
- return bytes[index];
+ public abstract byte byteAt(int index);
+
+ /**
+ * Return a {@link ByteString.ByteIterator} over the bytes in the ByteString.
+ * To avoid auto-boxing, you may get the iterator manually and call
+ * {@link ByteIterator#nextByte()}.
+ *
+ * @return the iterator
+ */
+ public abstract ByteIterator iterator();
+
+ /**
+ * This interface extends {@code Iterator<Byte>}, so that we can return an
+ * unboxed {@code byte}.
+ */
+ public interface ByteIterator extends Iterator<Byte> {
+ /**
+ * An alternative to {@link Iterator#next()} that returns an
+ * unboxed primitive {@code byte}.
+ *
+ * @return the next {@code byte} in the iteration
+ * @throws NoSuchElementException if the iteration has no more elements
+ */
+ byte nextByte();
}
/**
* Gets the number of bytes.
+ *
+ * @return size in bytes
*/
- public int size() {
- return bytes.length;
- }
+ public abstract int size();
/**
* Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
+ *
+ * @return true if this is zero bytes long
*/
public boolean isEmpty() {
- return bytes.length == 0;
+ return size() == 0;
}
// =================================================================
- // byte[] -> ByteString
+ // ByteString -> substring
+
+ /**
+ * Return the substring from {@code beginIndex}, inclusive, to the end of the
+ * string.
+ *
+ * @param beginIndex start at this index
+ * @return substring sharing underlying data
+ * @throws IndexOutOfBoundsException if {@code beginIndex < 0} or
+ * {@code beginIndex > size()}.
+ */
+ public ByteString substring(int beginIndex) {
+ return substring(beginIndex, size());
+ }
+
+ /**
+ * Return the substring from {@code beginIndex}, inclusive, to {@code
+ * endIndex}, exclusive.
+ *
+ * @param beginIndex start at this index
+ * @param endIndex the last character is the one before this index
+ * @return substring sharing underlying data
+ * @throws IndexOutOfBoundsException if {@code beginIndex < 0},
+ * {@code endIndex > size()}, or {@code beginIndex > endIndex}.
+ */
+ public abstract ByteString substring(int beginIndex, int endIndex);
/**
- * Empty ByteString.
+ * Tests if this bytestring starts with the specified prefix.
+ * Similar to {@link String#startsWith(String)}
+ *
+ * @param prefix the prefix.
+ * @return <code>true</code> if the byte sequence represented by the
+ * argument is a prefix of the byte sequence represented by
+ * this string; <code>false</code> otherwise.
*/
- public static final ByteString EMPTY = new ByteString(new byte[0]);
+ public boolean startsWith(ByteString prefix) {
+ return size() >= prefix.size() &&
+ substring(0, prefix.size()).equals(prefix);
+ }
+
+ /**
+ * Tests if this bytestring ends with the specified suffix.
+ * Similar to {@link String#endsWith(String)}
+ *
+ * @param suffix the suffix.
+ * @return <code>true</code> if the byte sequence represented by the
+ * argument is a suffix of the byte sequence represented by
+ * this string; <code>false</code> otherwise.
+ */
+ public boolean endsWith(ByteString suffix) {
+ return size() >= suffix.size() &&
+ substring(size() - suffix.size()).equals(suffix);
+ }
+
+ // =================================================================
+ // byte[] -> ByteString
/**
* Copies the given bytes into a {@code ByteString}.
+ *
+ * @param bytes source array
+ * @param offset offset in source array
+ * @param size number of bytes to copy
+ * @return new {@code ByteString}
*/
- public static ByteString copyFrom(final byte[] bytes, final int offset,
- final int size) {
- final byte[] copy = new byte[size];
+ public static ByteString copyFrom(byte[] bytes, int offset, int size) {
+ byte[] copy = new byte[size];
System.arraycopy(bytes, offset, copy, 0, size);
- return new ByteString(copy);
+ return new LiteralByteString(copy);
}
/**
* Copies the given bytes into a {@code ByteString}.
+ *
+ * @param bytes to copy
+ * @return new {@code ByteString}
*/
- public static ByteString copyFrom(final byte[] bytes) {
+ public static ByteString copyFrom(byte[] bytes) {
return copyFrom(bytes, 0, bytes.length);
}
/**
- * Copies {@code size} bytes from a {@code java.nio.ByteBuffer} into
+ * Copies the next {@code size} bytes from a {@code java.nio.ByteBuffer} into
* a {@code ByteString}.
+ *
+ * @param bytes source buffer
+ * @param size number of bytes to copy
+ * @return new {@code ByteString}
*/
- public static ByteString copyFrom(final ByteBuffer bytes, final int size) {
- final byte[] copy = new byte[size];
+ public static ByteString copyFrom(ByteBuffer bytes, int size) {
+ byte[] copy = new byte[size];
bytes.get(copy);
- return new ByteString(copy);
+ return new LiteralByteString(copy);
}
/**
* Copies the remaining bytes from a {@code java.nio.ByteBuffer} into
* a {@code ByteString}.
+ *
+ * @param bytes sourceBuffer
+ * @return new {@code ByteString}
*/
- public static ByteString copyFrom(final ByteBuffer bytes) {
+ public static ByteString copyFrom(ByteBuffer bytes) {
return copyFrom(bytes, bytes.remaining());
}
/**
* Encodes {@code text} into a sequence of bytes using the named charset
* and returns the result as a {@code ByteString}.
+ *
+ * @param text source string
+ * @param charsetName encoding to use
+ * @return new {@code ByteString}
+ * @throws UnsupportedEncodingException if the encoding isn't found
*/
- public static ByteString copyFrom(final String text, final String charsetName)
+ public static ByteString copyFrom(String text, String charsetName)
throws UnsupportedEncodingException {
- return new ByteString(text.getBytes(charsetName));
+ return new LiteralByteString(text.getBytes(charsetName));
}
/**
* Encodes {@code text} into a sequence of UTF-8 bytes and returns the
* result as a {@code ByteString}.
+ *
+ * @param text source string
+ * @return new {@code ByteString}
*/
- public static ByteString copyFromUtf8(final String text) {
+ public static ByteString copyFromUtf8(String text) {
try {
- return new ByteString(text.getBytes("UTF-8"));
+ return new LiteralByteString(text.getBytes(UTF_8));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 not supported?", e);
}
}
+ // =================================================================
+ // InputStream -> ByteString
+
+ /**
+ * Completely reads the given stream's bytes into a
+ * {@code ByteString}, blocking if necessary until all bytes are
+ * read through to the end of the stream.
+ *
+ * <b>Performance notes:</b> The returned {@code ByteString} is an
+ * immutable tree of byte arrays ("chunks") of the stream data. The
+ * first chunk is small, with subsequent chunks each being double
+ * the size, up to 8K. If the caller knows the precise length of
+ * the stream and wishes to avoid all unnecessary copies and
+ * allocations, consider using the two-argument version of this
+ * method, below.
+ *
+ * @param streamToDrain The source stream, which is read completely
+ * but not closed.
+ * @return A new {@code ByteString} which is made up of chunks of
+ * various sizes, depending on the behavior of the underlying
+ * stream.
+ * @throws IOException IOException is thrown if there is a problem
+ * reading the underlying stream.
+ */
+ public static ByteString readFrom(InputStream streamToDrain)
+ throws IOException {
+ return readFrom(
+ streamToDrain, MIN_READ_FROM_CHUNK_SIZE, MAX_READ_FROM_CHUNK_SIZE);
+ }
+
+ /**
+ * Completely reads the given stream's bytes into a
+ * {@code ByteString}, blocking if necessary until all bytes are
+ * read through to the end of the stream.
+ *
+ * <b>Performance notes:</b> The returned {@code ByteString} is an
+ * immutable tree of byte arrays ("chunks") of the stream data. The
+ * chunkSize parameter sets the size of these byte arrays. In
+ * particular, if the chunkSize is precisely the same as the length
+ * of the stream, unnecessary allocations and copies will be
+ * avoided. Otherwise, the chunks will be of the given size, except
+ * for the last chunk, which will be resized (via a reallocation and
+ * copy) to contain the remainder of the stream.
+ *
+ * @param streamToDrain The source stream, which is read completely
+ * but not closed.
+ * @param chunkSize The size of the chunks in which to read the
+ * stream.
+ * @return A new {@code ByteString} which is made up of chunks of
+ * the given size.
+ * @throws IOException IOException is thrown if there is a problem
+ * reading the underlying stream.
+ */
+ public static ByteString readFrom(InputStream streamToDrain, int chunkSize)
+ throws IOException {
+ return readFrom(streamToDrain, chunkSize, chunkSize);
+ }
+
+ // Helper method that takes the chunk size range as a parameter.
+ public static ByteString readFrom(InputStream streamToDrain, int minChunkSize,
+ int maxChunkSize) throws IOException {
+ Collection<ByteString> results = new ArrayList<ByteString>();
+
+ // copy the inbound bytes into a list of chunks; the chunk size
+ // grows exponentially to support both short and long streams.
+ int chunkSize = minChunkSize;
+ while (true) {
+ ByteString chunk = readChunk(streamToDrain, chunkSize);
+ if (chunk == null) {
+ break;
+ }
+ results.add(chunk);
+ chunkSize = Math.min(chunkSize * 2, maxChunkSize);
+ }
+
+ return ByteString.copyFrom(results);
+ }
+
+ /**
+ * Blocks until a chunk of the given size can be made from the
+ * stream, or EOF is reached. Calls read() repeatedly in case the
+ * given stream implementation doesn't completely fill the given
+ * buffer in one read() call.
+ *
+ * @return A chunk of the desired size, or else a chunk as large as
+ * was available when end of stream was reached. Returns null if the
+ * given stream had no more data in it.
+ */
+ private static ByteString readChunk(InputStream in, final int chunkSize)
+ throws IOException {
+ final byte[] buf = new byte[chunkSize];
+ int bytesRead = 0;
+ while (bytesRead < chunkSize) {
+ final int count = in.read(buf, bytesRead, chunkSize - bytesRead);
+ if (count == -1) {
+ break;
+ }
+ bytesRead += count;
+ }
+
+ if (bytesRead == 0) {
+ return null;
+ } else {
+ return ByteString.copyFrom(buf, 0, bytesRead);
+ }
+ }
+
+ // =================================================================
+ // Multiple ByteStrings -> One ByteString
+
+ /**
+ * Concatenate the given {@code ByteString} to this one. Short concatenations,
+ * of total size smaller than {@link ByteString#CONCATENATE_BY_COPY_SIZE}, are
+ * produced by copying the underlying bytes (as per Rope.java, <a
+ * href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
+ * BAP95 </a>. In general, the concatenate involves no copying.
+ *
+ * @param other string to concatenate
+ * @return a new {@code ByteString} instance
+ */
+ public ByteString concat(ByteString other) {
+ int thisSize = size();
+ int otherSize = other.size();
+ if ((long) thisSize + otherSize >= Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("ByteString would be too long: " +
+ thisSize + "+" + otherSize);
+ }
+
+ return RopeByteString.concatenate(this, other);
+ }
+
/**
- * Concatenates all byte strings in the list and returns the result.
+ * Concatenates all byte strings in the iterable and returns the result.
+ * This is designed to run in O(list size), not O(total bytes).
*
* <p>The returned {@code ByteString} is not necessarily a unique object.
* If the list is empty, the returned object is the singleton empty
* {@code ByteString}. If the list has only one element, that
* {@code ByteString} will be returned without copying.
+ *
+ * @param byteStrings strings to be concatenated
+ * @return new {@code ByteString}
*/
- public static ByteString copyFrom(List<ByteString> list) {
- if (list.size() == 0) {
- return EMPTY;
- } else if (list.size() == 1) {
- return list.get(0);
+ public static ByteString copyFrom(Iterable<ByteString> byteStrings) {
+ Collection<ByteString> collection;
+ if (!(byteStrings instanceof Collection)) {
+ collection = new ArrayList<ByteString>();
+ for (ByteString byteString : byteStrings) {
+ collection.add(byteString);
+ }
+ } else {
+ collection = (Collection<ByteString>) byteStrings;
}
-
- int size = 0;
- for (ByteString str : list) {
- size += str.size();
+ ByteString result;
+ if (collection.isEmpty()) {
+ result = EMPTY;
+ } else {
+ result = balancedConcat(collection.iterator(), collection.size());
}
- byte[] bytes = new byte[size];
- int pos = 0;
- for (ByteString str : list) {
- System.arraycopy(str.bytes, 0, bytes, pos, str.size());
- pos += str.size();
+ return result;
+ }
+
+ // Internal function used by copyFrom(Iterable<ByteString>).
+ // Create a balanced concatenation of the next "length" elements from the
+ // iterable.
+ private static ByteString balancedConcat(Iterator<ByteString> iterator,
+ int length) {
+ assert length >= 1;
+ ByteString result;
+ if (length == 1) {
+ result = iterator.next();
+ } else {
+ int halfLength = length >>> 1;
+ ByteString left = balancedConcat(iterator, halfLength);
+ ByteString right = balancedConcat(iterator, length - halfLength);
+ result = left.concat(right);
}
- return new ByteString(bytes);
+ return result;
}
// =================================================================
@@ -174,206 +464,493 @@ public final class ByteString {
*
* @param target buffer to copy into
* @param offset in the target buffer
+ * @throws IndexOutOfBoundsException if the offset is negative or too large
*/
- public void copyTo(final byte[] target, final int offset) {
- System.arraycopy(bytes, 0, target, offset, bytes.length);
+ public void copyTo(byte[] target, int offset) {
+ copyTo(target, 0, offset, size());
}
/**
* Copies bytes into a buffer.
*
- * @param target buffer to copy into
+ * @param target buffer to copy into
* @param sourceOffset offset within these bytes
* @param targetOffset offset within the target buffer
- * @param size number of bytes to copy
+ * @param numberToCopy number of bytes to copy
+ * @throws IndexOutOfBoundsException if an offset or size is negative or too
+ * large
*/
- public void copyTo(final byte[] target, final int sourceOffset,
- final int targetOffset,
- final int size) {
- System.arraycopy(bytes, sourceOffset, target, targetOffset, size);
+ public void copyTo(byte[] target, int sourceOffset, int targetOffset,
+ int numberToCopy) {
+ if (sourceOffset < 0) {
+ throw new IndexOutOfBoundsException("Source offset < 0: " + sourceOffset);
+ }
+ if (targetOffset < 0) {
+ throw new IndexOutOfBoundsException("Target offset < 0: " + targetOffset);
+ }
+ if (numberToCopy < 0) {
+ throw new IndexOutOfBoundsException("Length < 0: " + numberToCopy);
+ }
+ if (sourceOffset + numberToCopy > size()) {
+ throw new IndexOutOfBoundsException(
+ "Source end offset < 0: " + (sourceOffset + numberToCopy));
+ }
+ if (targetOffset + numberToCopy > target.length) {
+ throw new IndexOutOfBoundsException(
+ "Target end offset < 0: " + (targetOffset + numberToCopy));
+ }
+ if (numberToCopy > 0) {
+ copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
+ }
}
/**
+ * Internal (package private) implementation of
+ * {@link #copyTo(byte[],int,int,int)}.
+ * It assumes that all error checking has already been performed and that
+ * {@code numberToCopy > 0}.
+ */
+ protected abstract void copyToInternal(byte[] target, int sourceOffset,
+ int targetOffset, int numberToCopy);
+
+ /**
* Copies bytes into a ByteBuffer.
*
* @param target ByteBuffer to copy into.
- * @throws ReadOnlyBufferException if the {@code target} is read-only
- * @throws BufferOverflowException if the {@code target}'s remaining()
- * space is not large enough to hold the data.
+ * @throws java.nio.ReadOnlyBufferException if the {@code target} is read-only
+ * @throws java.nio.BufferOverflowException if the {@code target}'s
+ * remaining() space is not large enough to hold the data.
*/
- public void copyTo(ByteBuffer target) {
- target.put(bytes, 0, bytes.length);
- }
+ public abstract void copyTo(ByteBuffer target);
/**
* Copies bytes to a {@code byte[]}.
+ *
+ * @return copied bytes
*/
public byte[] toByteArray() {
- final int size = bytes.length;
- final byte[] copy = new byte[size];
- System.arraycopy(bytes, 0, copy, 0, size);
- return copy;
+ int size = size();
+ if (size == 0) {
+ return Internal.EMPTY_BYTE_ARRAY;
+ }
+ byte[] result = new byte[size];
+ copyToInternal(result, 0, 0, size);
+ return result;
}
/**
- * Constructs a new read-only {@code java.nio.ByteBuffer} with the
- * same backing byte array.
+ * Writes the complete contents of this byte string to
+ * the specified output stream argument.
+ *
+ * @param out the output stream to which to write the data.
+ * @throws IOException if an I/O error occurs.
+ */
+ public abstract void writeTo(OutputStream out) throws IOException;
+
+ /**
+ * Writes a specified part of this byte string to an output stream.
+ *
+ * @param out the output stream to which to write the data.
+ * @param sourceOffset offset within these bytes
+ * @param numberToWrite number of bytes to write
+ * @throws IOException if an I/O error occurs.
+ * @throws IndexOutOfBoundsException if an offset or size is negative or too
+ * large
*/
- public ByteBuffer asReadOnlyByteBuffer() {
- final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
- return byteBuffer.asReadOnlyBuffer();
+ void writeTo(OutputStream out, int sourceOffset, int numberToWrite)
+ throws IOException {
+ if (sourceOffset < 0) {
+ throw new IndexOutOfBoundsException("Source offset < 0: " + sourceOffset);
+ }
+ if (numberToWrite < 0) {
+ throw new IndexOutOfBoundsException("Length < 0: " + numberToWrite);
+ }
+ if (sourceOffset + numberToWrite > size()) {
+ throw new IndexOutOfBoundsException(
+ "Source end offset exceeded: " + (sourceOffset + numberToWrite));
+ }
+ if (numberToWrite > 0) {
+ writeToInternal(out, sourceOffset, numberToWrite);
+ }
+
}
/**
+ * Internal version of {@link #writeTo(OutputStream,int,int)} that assumes
+ * all error checking has already been done.
+ */
+ abstract void writeToInternal(OutputStream out, int sourceOffset,
+ int numberToWrite) throws IOException;
+
+ /**
+ * Constructs a read-only {@code java.nio.ByteBuffer} whose content
+ * is equal to the contents of this byte string.
+ * The result uses the same backing array as the byte string, if possible.
+ *
+ * @return wrapped bytes
+ */
+ public abstract ByteBuffer asReadOnlyByteBuffer();
+
+ /**
+ * Constructs a list of read-only {@code java.nio.ByteBuffer} objects
+ * such that the concatenation of their contents is equal to the contents
+ * of this byte string. The result uses the same backing arrays as the
+ * byte string.
+ * <p>
+ * By returning a list, implementations of this method may be able to avoid
+ * copying even when there are multiple backing arrays.
+ *
+ * @return a list of wrapped bytes
+ */
+ public abstract List<ByteBuffer> asReadOnlyByteBufferList();
+
+ /**
* Constructs a new {@code String} by decoding the bytes using the
* specified charset.
+ *
+ * @param charsetName encode using this charset
+ * @return new string
+ * @throws UnsupportedEncodingException if charset isn't recognized
*/
- public String toString(final String charsetName)
- throws UnsupportedEncodingException {
- return new String(bytes, charsetName);
- }
+ public abstract String toString(String charsetName)
+ throws UnsupportedEncodingException;
+
+ // =================================================================
+ // UTF-8 decoding
/**
* Constructs a new {@code String} by decoding the bytes as UTF-8.
+ *
+ * @return new string using UTF-8 encoding
*/
public String toStringUtf8() {
try {
- return new String(bytes, "UTF-8");
+ return toString(UTF_8);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 not supported?", e);
}
}
+ /**
+ * Tells whether this {@code ByteString} represents a well-formed UTF-8
+ * byte sequence, such that the original bytes can be converted to a
+ * String object and then round tripped back to bytes without loss.
+ *
+ * <p>More precisely, returns {@code true} whenever: <pre> {@code
+ * Arrays.equals(byteString.toByteArray(),
+ * new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
+ * }</pre>
+ *
+ * <p>This method returns {@code false} for "overlong" byte sequences,
+ * as well as for 3-byte sequences that would map to a surrogate
+ * character, in accordance with the restricted definition of UTF-8
+ * introduced in Unicode 3.1. Note that the UTF-8 decoder included in
+ * Oracle's JDK has been modified to also reject "overlong" byte
+ * sequences, but (as of 2011) still accepts 3-byte surrogate
+ * character byte sequences.
+ *
+ * <p>See the Unicode Standard,</br>
+ * Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
+ * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
+ *
+ * @return whether the bytes in this {@code ByteString} are a
+ * well-formed UTF-8 byte sequence
+ */
+ public abstract boolean isValidUtf8();
+
+ /**
+ * Tells whether the given byte sequence is a well-formed, malformed, or
+ * incomplete UTF-8 byte sequence. This method accepts and returns a partial
+ * state result, allowing the bytes for a complete UTF-8 byte sequence to be
+ * composed from multiple {@code ByteString} segments.
+ *
+ * @param state either {@code 0} (if this is the initial decoding operation)
+ * or the value returned from a call to a partial decoding method for the
+ * previous bytes
+ * @param offset offset of the first byte to check
+ * @param length number of bytes to check
+ *
+ * @return {@code -1} if the partial byte sequence is definitely malformed,
+ * {@code 0} if it is well-formed (no additional input needed), or, if the
+ * byte sequence is "incomplete", i.e. apparently terminated in the middle of
+ * a character, an opaque integer "state" value containing enough information
+ * to decode the character when passed to a subsequent invocation of a
+ * partial decoding method.
+ */
+ protected abstract int partialIsValidUtf8(int state, int offset, int length);
+
// =================================================================
// equals() and hashCode()
@Override
- public boolean equals(final Object o) {
- if (o == this) {
- return true;
- }
-
- if (!(o instanceof ByteString)) {
- return false;
- }
-
- final ByteString other = (ByteString) o;
- final int size = bytes.length;
- if (size != other.bytes.length) {
- return false;
- }
-
- final byte[] thisBytes = bytes;
- final byte[] otherBytes = other.bytes;
- for (int i = 0; i < size; i++) {
- if (thisBytes[i] != otherBytes[i]) {
- return false;
- }
- }
-
- return true;
- }
-
- private volatile int hash = 0;
+ public abstract boolean equals(Object o);
+ /**
+ * Return a non-zero hashCode depending only on the sequence of bytes
+ * in this ByteString.
+ *
+ * @return hashCode value for this object
+ */
@Override
- public int hashCode() {
- int h = hash;
-
- if (h == 0) {
- final byte[] thisBytes = bytes;
- final int size = bytes.length;
-
- h = size;
- for (int i = 0; i < size; i++) {
- h = h * 31 + thisBytes[i];
- }
- if (h == 0) {
- h = 1;
- }
-
- hash = h;
- }
-
- return h;
- }
+ public abstract int hashCode();
// =================================================================
// Input stream
/**
* Creates an {@code InputStream} which can be used to read the bytes.
+ * <p>
+ * The {@link InputStream} returned by this method is guaranteed to be
+ * completely non-blocking. The method {@link InputStream#available()}
+ * returns the number of bytes remaining in the stream. The methods
+ * {@link InputStream#read(byte[])}, {@link InputStream#read(byte[],int,int)}
+ * and {@link InputStream#skip(long)} will read/skip as many bytes as are
+ * available.
+ * <p>
+ * The methods in the returned {@link InputStream} might <b>not</b> be
+ * thread safe.
+ *
+ * @return an input stream that returns the bytes of this byte string.
*/
- public InputStream newInput() {
- return new ByteArrayInputStream(bytes);
- }
+ public abstract InputStream newInput();
/**
* Creates a {@link CodedInputStream} which can be used to read the bytes.
- * Using this is more efficient than creating a {@link CodedInputStream}
- * wrapping the result of {@link #newInput()}.
+ * Using this is often more efficient than creating a {@link CodedInputStream}
+ * that wraps the result of {@link #newInput()}.
+ *
+ * @return stream based on wrapped data
*/
- public CodedInputStream newCodedInput() {
- // We trust CodedInputStream not to modify the bytes, or to give anyone
- // else access to them.
- return CodedInputStream.newInstance(bytes);
- }
+ public abstract CodedInputStream newCodedInput();
// =================================================================
// Output stream
/**
- * Creates a new {@link Output} with the given initial capacity.
+ * Creates a new {@link Output} with the given initial capacity. Call {@link
+ * Output#toByteString()} to create the {@code ByteString} instance.
+ * <p>
+ * A {@link ByteString.Output} offers the same functionality as a
+ * {@link ByteArrayOutputStream}, except that it returns a {@link ByteString}
+ * rather than a {@code byte} array.
+ *
+ * @param initialCapacity estimate of number of bytes to be written
+ * @return {@code OutputStream} for building a {@code ByteString}
*/
- public static Output newOutput(final int initialCapacity) {
- return new Output(new ByteArrayOutputStream(initialCapacity));
+ public static Output newOutput(int initialCapacity) {
+ return new Output(initialCapacity);
}
/**
- * Creates a new {@link Output}.
+ * Creates a new {@link Output}. Call {@link Output#toByteString()} to create
+ * the {@code ByteString} instance.
+ * <p>
+ * A {@link ByteString.Output} offers the same functionality as a
+ * {@link ByteArrayOutputStream}, except that it returns a {@link ByteString}
+ * rather than a {@code byte array}.
+ *
+ * @return {@code OutputStream} for building a {@code ByteString}
*/
public static Output newOutput() {
- return newOutput(32);
+ return new Output(CONCATENATE_BY_COPY_SIZE);
}
/**
* Outputs to a {@code ByteString} instance. Call {@link #toByteString()} to
* create the {@code ByteString} instance.
*/
- public static final class Output extends FilterOutputStream {
- private final ByteArrayOutputStream bout;
+ public static final class Output extends OutputStream {
+ // Implementation note.
+ // The public methods of this class must be synchronized. ByteStrings
+ // are guaranteed to be immutable. Without some sort of locking, it could
+ // be possible for one thread to call toByteSring(), while another thread
+ // is still modifying the underlying byte array.
+
+ private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+ // argument passed by user, indicating initial capacity.
+ private final int initialCapacity;
+ // ByteStrings to be concatenated to create the result
+ private final ArrayList<ByteString> flushedBuffers;
+ // Total number of bytes in the ByteStrings of flushedBuffers
+ private int flushedBuffersTotalBytes;
+ // Current buffer to which we are writing
+ private byte[] buffer;
+ // Location in buffer[] to which we write the next byte.
+ private int bufferPos;
/**
- * Constructs a new output with the given initial capacity.
+ * Creates a new ByteString output stream with the specified
+ * initial capacity.
+ *
+ * @param initialCapacity the initial capacity of the output stream.
*/
- private Output(final ByteArrayOutputStream bout) {
- super(bout);
- this.bout = bout;
+ Output(int initialCapacity) {
+ if (initialCapacity < 0) {
+ throw new IllegalArgumentException("Buffer size < 0");
+ }
+ this.initialCapacity = initialCapacity;
+ this.flushedBuffers = new ArrayList<ByteString>();
+ this.buffer = new byte[initialCapacity];
+ }
+
+ @Override
+ public synchronized void write(int b) {
+ if (bufferPos == buffer.length) {
+ flushFullBuffer(1);
+ }
+ buffer[bufferPos++] = (byte)b;
+ }
+
+ @Override
+ public synchronized void write(byte[] b, int offset, int length) {
+ if (length <= buffer.length - bufferPos) {
+ // The bytes can fit into the current buffer.
+ System.arraycopy(b, offset, buffer, bufferPos, length);
+ bufferPos += length;
+ } else {
+ // Use up the current buffer
+ int copySize = buffer.length - bufferPos;
+ System.arraycopy(b, offset, buffer, bufferPos, copySize);
+ offset += copySize;
+ length -= copySize;
+ // Flush the buffer, and get a new buffer at least big enough to cover
+ // what we still need to output
+ flushFullBuffer(length);
+ System.arraycopy(b, offset, buffer, 0 /* count */, length);
+ bufferPos = length;
+ }
}
/**
- * Creates a {@code ByteString} instance from this {@code Output}.
+ * Creates a byte string. Its size is the current size of this output
+ * stream and its output has been copied to it.
+ *
+ * @return the current contents of this output stream, as a byte string.
*/
- public ByteString toByteString() {
- final byte[] byteArray = bout.toByteArray();
- return new ByteString(byteArray);
+ public synchronized ByteString toByteString() {
+ flushLastBuffer();
+ return ByteString.copyFrom(flushedBuffers);
+ }
+
+ /**
+ * Implement java.util.Arrays.copyOf() for jdk 1.5.
+ */
+ private byte[] copyArray(byte[] buffer, int length) {
+ byte[] result = new byte[length];
+ System.arraycopy(buffer, 0, result, 0, Math.min(buffer.length, length));
+ return result;
+ }
+
+ /**
+ * Writes the complete contents of this byte array output stream to
+ * the specified output stream argument.
+ *
+ * @param out the output stream to which to write the data.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ ByteString[] cachedFlushBuffers;
+ byte[] cachedBuffer;
+ int cachedBufferPos;
+ synchronized (this) {
+ // Copy the information we need into local variables so as to hold
+ // the lock for as short a time as possible.
+ cachedFlushBuffers =
+ flushedBuffers.toArray(new ByteString[flushedBuffers.size()]);
+ cachedBuffer = buffer;
+ cachedBufferPos = bufferPos;
+ }
+ for (ByteString byteString : cachedFlushBuffers) {
+ byteString.writeTo(out);
+ }
+
+ out.write(copyArray(cachedBuffer, cachedBufferPos));
+ }
+
+ /**
+ * Returns the current size of the output stream.
+ *
+ * @return the current size of the output stream
+ */
+ public synchronized int size() {
+ return flushedBuffersTotalBytes + bufferPos;
+ }
+
+ /**
+ * Resets this stream, so that all currently accumulated output in the
+ * output stream is discarded. The output stream can be used again,
+ * reusing the already allocated buffer space.
+ */
+ public synchronized void reset() {
+ flushedBuffers.clear();
+ flushedBuffersTotalBytes = 0;
+ bufferPos = 0;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("<ByteString.Output@%s size=%d>",
+ Integer.toHexString(System.identityHashCode(this)), size());
+ }
+
+ /**
+ * Internal function used by writers. The current buffer is full, and the
+ * writer needs a new buffer whose size is at least the specified minimum
+ * size.
+ */
+ private void flushFullBuffer(int minSize) {
+ flushedBuffers.add(new LiteralByteString(buffer));
+ flushedBuffersTotalBytes += buffer.length;
+ // We want to increase our total capacity by 50%, but as a minimum,
+ // the new buffer should also at least be >= minSize and
+ // >= initial Capacity.
+ int newSize = Math.max(initialCapacity,
+ Math.max(minSize, flushedBuffersTotalBytes >>> 1));
+ buffer = new byte[newSize];
+ bufferPos = 0;
+ }
+
+ /**
+ * Internal function used by {@link #toByteString()}. The current buffer may
+ * or may not be full, but it needs to be flushed.
+ */
+ private void flushLastBuffer() {
+ if (bufferPos < buffer.length) {
+ if (bufferPos > 0) {
+ byte[] bufferCopy = copyArray(buffer, bufferPos);
+ flushedBuffers.add(new LiteralByteString(bufferCopy));
+ }
+ // We reuse this buffer for further writes.
+ } else {
+ // Buffer is completely full. Huzzah.
+ flushedBuffers.add(new LiteralByteString(buffer));
+ // 99% of the time, we're not going to use this OutputStream again.
+ // We set buffer to an empty byte stream so that we're handling this
+ // case without wasting space. In the rare case that more writes
+ // *do* occur, this empty buffer will be flushed and an appropriately
+ // sized new buffer will be created.
+ buffer = EMPTY_BYTE_ARRAY;
+ }
+ flushedBuffersTotalBytes += bufferPos;
+ bufferPos = 0;
}
}
/**
- * Constructs a new ByteString builder, which allows you to efficiently
- * construct a {@code ByteString} by writing to a {@link CodedOutputStream}.
- * Using this is much more efficient than calling {@code newOutput()} and
- * wrapping that in a {@code CodedOutputStream}.
+ * Constructs a new {@code ByteString} builder, which allows you to
+ * efficiently construct a {@code ByteString} by writing to a {@link
+ * CodedOutputStream}. Using this is much more efficient than calling {@code
+ * newOutput()} and wrapping that in a {@code CodedOutputStream}.
*
* <p>This is package-private because it's a somewhat confusing interface.
* Users can call {@link Message#toByteString()} instead of calling this
* directly.
*
- * @param size The target byte size of the {@code ByteString}. You must
- * write exactly this many bytes before building the result.
+ * @param size The target byte size of the {@code ByteString}. You must write
+ * exactly this many bytes before building the result.
+ * @return the builder
*/
- static CodedBuilder newCodedBuilder(final int size) {
+ static CodedBuilder newCodedBuilder(int size) {
return new CodedBuilder(size);
}
@@ -382,7 +959,7 @@ public final class ByteString {
private final CodedOutputStream output;
private final byte[] buffer;
- private CodedBuilder(final int size) {
+ private CodedBuilder(int size) {
buffer = new byte[size];
output = CodedOutputStream.newInstance(buffer);
}
@@ -393,11 +970,57 @@ public final class ByteString {
// We can be confident that the CodedOutputStream will not modify the
// underlying bytes anymore because it already wrote all of them. So,
// no need to make a copy.
- return new ByteString(buffer);
+ return new LiteralByteString(buffer);
}
public CodedOutputStream getCodedOutput() {
return output;
}
}
+
+ // =================================================================
+ // Methods {@link RopeByteString} needs on instances, which aren't part of the
+ // public API.
+
+ /**
+ * Return the depth of the tree representing this {@code ByteString}, if any,
+ * whose root is this node. If this is a leaf node, return 0.
+ *
+ * @return tree depth or zero
+ */
+ protected abstract int getTreeDepth();
+
+ /**
+ * Return {@code true} if this ByteString is literal (a leaf node) or a
+ * flat-enough tree in the sense of {@link RopeByteString}.
+ *
+ * @return true if the tree is flat enough
+ */
+ protected abstract boolean isBalanced();
+
+ /**
+ * Return the cached hash code if available.
+ *
+ * @return value of cached hash code or 0 if not computed yet
+ */
+ protected abstract int peekCachedHashCode();
+
+ /**
+ * Compute the hash across the value bytes starting with the given hash, and
+ * return the result. This is used to compute the hash across strings
+ * represented as a set of pieces by allowing the hash computation to be
+ * continued from piece to piece.
+ *
+ * @param h starting hash value
+ * @param offset offset into this value to start looking at data values
+ * @param length number of data values to include in the hash computation
+ * @return ending hash value
+ */
+ protected abstract int partialHash(int h, int offset, int length);
+
+ @Override
+ public String toString() {
+ return String.format("<ByteString@%s size=%d>",
+ Integer.toHexString(System.identityHashCode(this)), size());
+ }
}
diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/src/main/java/com/google/protobuf/CodedInputStream.java
index b3e08555..0ca00bab 100644
--- a/java/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,9 +30,12 @@
package com.google.protobuf;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -88,6 +91,53 @@ public final class CodedInputStream {
return result;
}
+ /**
+ * Create a new CodedInputStream wrapping the given ByteBuffer. The data
+ * starting from the ByteBuffer's current position to its limit will be read.
+ * The returned CodedInputStream may or may not share the underlying data
+ * in the ByteBuffer, therefore the ByteBuffer cannot be changed while the
+ * CodedInputStream is in use.
+ * Note that the ByteBuffer's position won't be changed by this function.
+ * Concurrent calls with the same ByteBuffer object are safe if no other
+ * thread is trying to alter the ByteBuffer's status.
+ */
+ public static CodedInputStream newInstance(ByteBuffer buf) {
+ if (buf.hasArray()) {
+ return newInstance(buf.array(), buf.arrayOffset() + buf.position(),
+ buf.remaining());
+ } else {
+ ByteBuffer temp = buf.duplicate();
+ byte[] buffer = new byte[temp.remaining()];
+ temp.get(buffer);
+ return newInstance(buffer);
+ }
+ }
+
+ /**
+ * Create a new CodedInputStream wrapping a LiteralByteString.
+ */
+ static CodedInputStream newInstance(LiteralByteString byteString) {
+ CodedInputStream result = new CodedInputStream(byteString);
+ try {
+ // Some uses of CodedInputStream can be more efficient if they know
+ // exactly how many bytes are available. By pushing the end point of the
+ // buffer as a limit, we allow them to get this information via
+ // getBytesUntilLimit(). Pushing a limit that we know is at the end of
+ // the stream can never hurt, since we can never past that point anyway.
+ result.pushLimit(byteString.size());
+ } catch (InvalidProtocolBufferException ex) {
+ // The only reason pushLimit() might throw an exception here is if len
+ // is negative. Normally pushLimit()'s parameter comes directly off the
+ // wire, so it's important to catch exceptions in case of corrupt or
+ // malicious data. However, in this case, we expect that len is not a
+ // user-supplied value, so we can assume that it being negative indicates
+ // a programming error. Therefore, throwing an unchecked exception is
+ // appropriate.
+ throw new IllegalArgumentException(ex);
+ }
+ return result;
+ }
+
// -----------------------------------------------------------------
/**
@@ -125,6 +175,10 @@ public final class CodedInputStream {
}
}
+ public int getLastTag() {
+ return lastTag;
+ }
+
/**
* Reads and discards a single field, given its tag value.
*
@@ -134,10 +188,10 @@ public final class CodedInputStream {
public boolean skipField(final int tag) throws IOException {
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
- readInt32();
+ skipRawVarint();
return true;
case WireFormat.WIRETYPE_FIXED64:
- readRawLittleEndian64();
+ skipRawBytes(8);
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32());
@@ -151,8 +205,59 @@ public final class CodedInputStream {
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
- readRawLittleEndian32();
+ skipRawBytes(4);
+ return true;
+ default:
+ throw InvalidProtocolBufferException.invalidWireType();
+ }
+ }
+
+ /**
+ * Reads a single field and writes it to output in wire format,
+ * given its tag value.
+ *
+ * @return {@code false} if the tag is an endgroup tag, in which case
+ * nothing is skipped. Otherwise, returns {@code true}.
+ */
+ public boolean skipField(final int tag, final CodedOutputStream output)
+ throws IOException {
+ switch (WireFormat.getTagWireType(tag)) {
+ case WireFormat.WIRETYPE_VARINT: {
+ long value = readInt64();
+ output.writeRawVarint32(tag);
+ output.writeUInt64NoTag(value);
+ return true;
+ }
+ case WireFormat.WIRETYPE_FIXED64: {
+ long value = readRawLittleEndian64();
+ output.writeRawVarint32(tag);
+ output.writeFixed64NoTag(value);
+ return true;
+ }
+ case WireFormat.WIRETYPE_LENGTH_DELIMITED: {
+ ByteString value = readBytes();
+ output.writeRawVarint32(tag);
+ output.writeBytesNoTag(value);
return true;
+ }
+ case WireFormat.WIRETYPE_START_GROUP: {
+ output.writeRawVarint32(tag);
+ skipMessage(output);
+ int endtag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
+ WireFormat.WIRETYPE_END_GROUP);
+ checkLastTagWas(endtag);
+ output.writeRawVarint32(endtag);
+ return true;
+ }
+ case WireFormat.WIRETYPE_END_GROUP: {
+ return false;
+ }
+ case WireFormat.WIRETYPE_FIXED32: {
+ int value = readRawLittleEndian32();
+ output.writeRawVarint32(tag);
+ output.writeFixed32NoTag(value);
+ return true;
+ }
default:
throw InvalidProtocolBufferException.invalidWireType();
}
@@ -171,6 +276,51 @@ public final class CodedInputStream {
}
}
+ /**
+ * Reads an entire message and writes it to output in wire format.
+ * This will read either until EOF or until an endgroup tag,
+ * whichever comes first.
+ */
+ public void skipMessage(CodedOutputStream output) throws IOException {
+ while (true) {
+ final int tag = readTag();
+ if (tag == 0 || !skipField(tag, output)) {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Collects the bytes skipped and returns the data in a ByteBuffer.
+ */
+ private class SkippedDataSink implements RefillCallback {
+ private int lastPos = bufferPos;
+ private ByteArrayOutputStream byteArrayStream;
+
+ @Override
+ public void onRefill() {
+ if (byteArrayStream == null) {
+ byteArrayStream = new ByteArrayOutputStream();
+ }
+ byteArrayStream.write(buffer, lastPos, bufferPos - lastPos);
+ lastPos = 0;
+ }
+
+ /**
+ * Gets skipped data in a ByteBuffer. This method should only be
+ * called once.
+ */
+ ByteBuffer getSkippedData() {
+ if (byteArrayStream == null) {
+ return ByteBuffer.wrap(buffer, lastPos, bufferPos - lastPos);
+ } else {
+ byteArrayStream.write(buffer, lastPos, bufferPos);
+ return ByteBuffer.wrap(byteArrayStream.toByteArray());
+ }
+ }
+ }
+
+
// -----------------------------------------------------------------
/** Read a {@code double} field value from the stream. */
@@ -210,10 +360,14 @@ public final class CodedInputStream {
/** Read a {@code bool} field value from the stream. */
public boolean readBool() throws IOException {
- return readRawVarint32() != 0;
+ return readRawVarint64() != 0;
}
- /** Read a {@code string} field value from the stream. */
+ /**
+ * Read a {@code string} field value from the stream.
+ * If the stream contains malformed UTF-8,
+ * replace the offending bytes with the standard UTF-8 replacement character.
+ */
public String readString() throws IOException {
final int size = readRawVarint32();
if (size <= (bufferSize - bufferPos) && size > 0) {
@@ -222,12 +376,42 @@ public final class CodedInputStream {
final String result = new String(buffer, bufferPos, size, "UTF-8");
bufferPos += size;
return result;
+ } else if (size == 0) {
+ return "";
} else {
// Slow path: Build a byte array first then copy it.
- return new String(readRawBytes(size), "UTF-8");
+ return new String(readRawBytesSlowPath(size), "UTF-8");
}
}
+ /**
+ * Read a {@code string} field value from the stream.
+ * If the stream contains malformed UTF-8,
+ * throw exception {@link InvalidProtocolBufferException}.
+ */
+ public String readStringRequireUtf8() throws IOException {
+ final int size = readRawVarint32();
+ final byte[] bytes;
+ int pos = bufferPos;
+ if (size <= (bufferSize - pos) && size > 0) {
+ // Fast path: We already have the bytes in a contiguous buffer, so
+ // just copy directly from it.
+ bytes = buffer;
+ bufferPos = pos + size;
+ } else if (size == 0) {
+ return "";
+ } else {
+ // Slow path: Build a byte array first then copy it.
+ bytes = readRawBytesSlowPath(size);
+ pos = 0;
+ }
+ // TODO(martinrb): We could save a pass by validating while decoding.
+ if (!Utf8.isValidUtf8(bytes, pos, pos + size)) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ return new String(bytes, pos, size, "UTF-8");
+ }
+
/** Read a {@code group} field value from the stream. */
public void readGroup(final int fieldNumber,
final MessageLite.Builder builder,
@@ -243,6 +427,24 @@ public final class CodedInputStream {
--recursionDepth;
}
+
+ /** Read a {@code group} field value from the stream. */
+ public <T extends MessageLite> T readGroup(
+ final int fieldNumber,
+ final Parser<T> parser,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ ++recursionDepth;
+ T result = parser.parsePartialFrom(this, extensionRegistry);
+ checkLastTagWas(
+ WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+ --recursionDepth;
+ return result;
+ }
+
/**
* Reads a {@code group} field value from the stream and merges it into the
* given {@link UnknownFieldSet}.
@@ -278,20 +480,80 @@ public final class CodedInputStream {
popLimit(oldLimit);
}
+
+ /** Read an embedded message field value from the stream. */
+ public <T extends MessageLite> T readMessage(
+ final Parser<T> parser,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ int length = readRawVarint32();
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ final int oldLimit = pushLimit(length);
+ ++recursionDepth;
+ T result = parser.parsePartialFrom(this, extensionRegistry);
+ checkLastTagWas(0);
+ --recursionDepth;
+ popLimit(oldLimit);
+ return result;
+ }
+
/** Read a {@code bytes} field value from the stream. */
public ByteString readBytes() throws IOException {
final int size = readRawVarint32();
- if (size == 0) {
- return ByteString.EMPTY;
- } else if (size <= (bufferSize - bufferPos) && size > 0) {
+ if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
- final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
+ final ByteString result = bufferIsImmutable && enableAliasing
+ ? new BoundedByteString(buffer, bufferPos, size)
+ : ByteString.copyFrom(buffer, bufferPos, size);
bufferPos += size;
return result;
+ } else if (size == 0) {
+ return ByteString.EMPTY;
} else {
// Slow path: Build a byte array first then copy it.
- return ByteString.copyFrom(readRawBytes(size));
+ return new LiteralByteString(readRawBytesSlowPath(size));
+ }
+ }
+
+ /** Read a {@code bytes} field value from the stream. */
+ public byte[] readByteArray() throws IOException {
+ final int size = readRawVarint32();
+ if (size <= (bufferSize - bufferPos) && size > 0) {
+ // Fast path: We already have the bytes in a contiguous buffer, so
+ // just copy directly from it.
+ final byte[] result =
+ Arrays.copyOfRange(buffer, bufferPos, bufferPos + size);
+ bufferPos += size;
+ return result;
+ } else {
+ // Slow path: Build a byte array first then copy it.
+ return readRawBytesSlowPath(size);
+ }
+ }
+
+ /** Read a {@code bytes} field value from the stream. */
+ public ByteBuffer readByteBuffer() throws IOException {
+ final int size = readRawVarint32();
+ if (size <= (bufferSize - bufferPos) && size > 0) {
+ // Fast path: We already have the bytes in a contiguous buffer.
+ // When aliasing is enabled, we can return a ByteBuffer pointing directly
+ // into the underlying byte array without copy if the CodedInputStream is
+ // constructed from a byte array. If aliasing is disabled or the input is
+ // from an InputStream or ByteString, we have to make a copy of the bytes.
+ ByteBuffer result = input == null && !bufferIsImmutable && enableAliasing
+ ? ByteBuffer.wrap(buffer, bufferPos, size).slice()
+ : ByteBuffer.wrap(Arrays.copyOfRange(
+ buffer, bufferPos, bufferPos + size));
+ bufferPos += size;
+ return result;
+ } else if (size == 0) {
+ return Internal.EMPTY_BYTE_BUFFER;
+ } else {
+ // Slow path: Build a byte array first then copy it.
+ return ByteBuffer.wrap(readRawBytesSlowPath(size));
}
}
@@ -335,37 +597,67 @@ public final class CodedInputStream {
* upper bits.
*/
public int readRawVarint32() throws IOException {
- byte tmp = readRawByte();
- if (tmp >= 0) {
- return tmp;
- }
- int result = tmp & 0x7f;
- if ((tmp = readRawByte()) >= 0) {
- result |= tmp << 7;
- } else {
- result |= (tmp & 0x7f) << 7;
- if ((tmp = readRawByte()) >= 0) {
- result |= tmp << 14;
+ // See implementation notes for readRawVarint64
+ fastpath: {
+ int pos = bufferPos;
+
+ if (bufferSize == pos) {
+ break fastpath;
+ }
+
+ final byte[] buffer = this.buffer;
+ int x;
+ if ((x = buffer[pos++]) >= 0) {
+ bufferPos = pos;
+ return x;
+ } else if (bufferSize - pos < 9) {
+ break fastpath;
+ } 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 {
- result |= (tmp & 0x7f) << 14;
- if ((tmp = readRawByte()) >= 0) {
- result |= tmp << 21;
- } else {
- result |= (tmp & 0x7f) << 21;
- result |= (tmp = readRawByte()) << 28;
- if (tmp < 0) {
- // Discard upper 32 bits.
- for (int i = 0; i < 5; i++) {
- if (readRawByte() >= 0) {
- return result;
- }
- }
- throw InvalidProtocolBufferException.malformedVarint();
- }
+ int y = buffer[pos++];
+ x ^= y << 28;
+ x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28);
+ if (y < 0 &&
+ buffer[pos++] < 0 &&
+ buffer[pos++] < 0 &&
+ buffer[pos++] < 0 &&
+ buffer[pos++] < 0 &&
+ buffer[pos++] < 0) {
+ break fastpath; // Will throw malformedVarint()
}
}
+ bufferPos = pos;
+ return x;
}
- return result;
+ return (int) readRawVarint64SlowPath();
+ }
+
+ private void skipRawVarint() throws IOException {
+ if (bufferSize - bufferPos >= 10) {
+ final byte[] buffer = this.buffer;
+ int pos = bufferPos;
+ for (int i = 0; i < 10; i++) {
+ if (buffer[pos++] >= 0) {
+ bufferPos = pos;
+ return;
+ }
+ }
+ }
+ skipRawVarintSlowPath();
+ }
+
+ private void skipRawVarintSlowPath() throws IOException {
+ for (int i = 0; i < 10; i++) {
+ if (readRawByte() >= 0) {
+ return;
+ }
+ }
+ throw InvalidProtocolBufferException.malformedVarint();
}
/**
@@ -421,49 +713,115 @@ public final class CodedInputStream {
/** Read a raw Varint from the stream. */
public long readRawVarint64() throws IOException {
- int shift = 0;
+ // Implementation notes:
+ //
+ // Optimized for one-byte values, expected to be common.
+ // The particular code below was selected from various candidates
+ // empirically, by winning VarintBenchmark.
+ //
+ // Sign extension of (signed) Java bytes is usually a nuisance, but
+ // we exploit it here to more easily obtain the sign of bytes read.
+ // Instead of cleaning up the sign extension bits by masking eagerly,
+ // we delay until we find the final (positive) byte, when we clear all
+ // accumulated bits with one xor. We depend on javac to constant fold.
+ fastpath: {
+ int pos = bufferPos;
+
+ if (bufferSize == pos) {
+ break fastpath;
+ }
+
+ final byte[] buffer = this.buffer;
+ long x;
+ int y;
+ if ((y = buffer[pos++]) >= 0) {
+ bufferPos = pos;
+ return y;
+ } else if (bufferSize - pos < 9) {
+ break fastpath;
+ } 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);
+ } else if ((x ^= ((long) buffer[pos++] << 42)) >= 0L) {
+ x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
+ } else if ((x ^= ((long) buffer[pos++] << 49)) < 0L) {
+ x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
+ ^ (~0L << 49);
+ } else {
+ x ^= ((long) buffer[pos++] << 56);
+ x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
+ ^ (~0L << 49) ^ (~0L << 56);
+ if (x < 0L) {
+ if (buffer[pos++] < 0L) {
+ break fastpath; // Will throw malformedVarint()
+ }
+ }
+ }
+ bufferPos = pos;
+ return x;
+ }
+ return readRawVarint64SlowPath();
+ }
+
+ /** Variant of readRawVarint64 for when uncomfortably close to the limit. */
+ /* Visible for testing */
+ long readRawVarint64SlowPath() throws IOException {
long result = 0;
- while (shift < 64) {
+ for (int shift = 0; shift < 64; shift += 7) {
final byte b = readRawByte();
- result |= (long)(b & 0x7F) << shift;
+ result |= (long) (b & 0x7F) << shift;
if ((b & 0x80) == 0) {
return result;
}
- shift += 7;
}
throw InvalidProtocolBufferException.malformedVarint();
}
/** Read a 32-bit little-endian integer from the stream. */
public int readRawLittleEndian32() throws IOException {
- final byte b1 = readRawByte();
- final byte b2 = readRawByte();
- final byte b3 = readRawByte();
- final byte b4 = readRawByte();
- return (((int)b1 & 0xff) ) |
- (((int)b2 & 0xff) << 8) |
- (((int)b3 & 0xff) << 16) |
- (((int)b4 & 0xff) << 24);
+ int pos = bufferPos;
+
+ // hand-inlined ensureAvailable(4);
+ if (bufferSize - pos < 4) {
+ refillBuffer(4);
+ pos = bufferPos;
+ }
+
+ final byte[] buffer = this.buffer;
+ bufferPos = pos + 4;
+ return (((buffer[pos] & 0xff)) |
+ ((buffer[pos + 1] & 0xff) << 8) |
+ ((buffer[pos + 2] & 0xff) << 16) |
+ ((buffer[pos + 3] & 0xff) << 24));
}
/** Read a 64-bit little-endian integer from the stream. */
public long readRawLittleEndian64() throws IOException {
- final byte b1 = readRawByte();
- final byte b2 = readRawByte();
- final byte b3 = readRawByte();
- final byte b4 = readRawByte();
- final byte b5 = readRawByte();
- final byte b6 = readRawByte();
- final byte b7 = readRawByte();
- final byte b8 = readRawByte();
- return (((long)b1 & 0xff) ) |
- (((long)b2 & 0xff) << 8) |
- (((long)b3 & 0xff) << 16) |
- (((long)b4 & 0xff) << 24) |
- (((long)b5 & 0xff) << 32) |
- (((long)b6 & 0xff) << 40) |
- (((long)b7 & 0xff) << 48) |
- (((long)b8 & 0xff) << 56);
+ int pos = bufferPos;
+
+ // hand-inlined ensureAvailable(8);
+ if (bufferSize - pos < 8) {
+ refillBuffer(8);
+ pos = bufferPos;
+ }
+
+ final byte[] buffer = this.buffer;
+ bufferPos = pos + 8;
+ return ((((long) buffer[pos] & 0xffL)) |
+ (((long) buffer[pos + 1] & 0xffL) << 8) |
+ (((long) buffer[pos + 2] & 0xffL) << 16) |
+ (((long) buffer[pos + 3] & 0xffL) << 24) |
+ (((long) buffer[pos + 4] & 0xffL) << 32) |
+ (((long) buffer[pos + 5] & 0xffL) << 40) |
+ (((long) buffer[pos + 6] & 0xffL) << 48) |
+ (((long) buffer[pos + 7] & 0xffL) << 56));
}
/**
@@ -497,11 +855,13 @@ public final class CodedInputStream {
// -----------------------------------------------------------------
private final byte[] buffer;
+ private final boolean bufferIsImmutable;
private int bufferSize;
private int bufferSizeAfterLimit;
private int bufferPos;
private final InputStream input;
private int lastTag;
+ private boolean enableAliasing = false;
/**
* The total number of bytes read before the current buffer. The total
@@ -522,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;
@@ -532,6 +892,7 @@ public final class CodedInputStream {
bufferPos = off;
totalBytesRetired = -off;
input = null;
+ bufferIsImmutable = false;
}
private CodedInputStream(final InputStream input) {
@@ -540,6 +901,20 @@ public final class CodedInputStream {
bufferPos = 0;
totalBytesRetired = 0;
this.input = input;
+ bufferIsImmutable = false;
+ }
+
+ private CodedInputStream(final LiteralByteString byteString) {
+ buffer = byteString.bytes;
+ bufferPos = byteString.getOffsetIntoBytes();
+ bufferSize = bufferPos + byteString.size();
+ totalBytesRetired = -bufferPos;
+ input = null;
+ bufferIsImmutable = true;
+ }
+
+ public void enableAliasing(boolean enabled) {
+ this.enableAliasing = enabled;
}
/**
@@ -601,7 +976,7 @@ public final class CodedInputStream {
* refreshing its buffer. If you need to prevent reading past a certain
* point in the underlying {@code InputStream} (e.g. because you expect it to
* contain more data after the end of the message which you need to handle
- * differently) then you must place a wrapper around you {@code InputStream}
+ * differently) then you must place a wrapper around your {@code InputStream}
* which limits the amount of data that can be read from it.
*
* @return the old limit.
@@ -663,7 +1038,7 @@ public final class CodedInputStream {
* if the stream has reached a limit created using {@link #pushLimit(int)}.
*/
public boolean isAtEnd() throws IOException {
- return bufferPos == bufferSize && !refillBuffer(false);
+ return bufferPos == bufferSize && !tryRefillBuffer(1);
}
/**
@@ -674,53 +1049,93 @@ public final class CodedInputStream {
return totalBytesRetired + bufferPos;
}
+ private interface RefillCallback {
+ void onRefill();
+ }
+
+ private RefillCallback refillCallback = null;
+
/**
- * Called with {@code this.buffer} is empty to read more bytes from the
- * input. If {@code mustSucceed} is true, refillBuffer() gurantees that
- * either there will be at least one byte in the buffer when it returns
- * or it will throw an exception. If {@code mustSucceed} is false,
- * refillBuffer() returns false if no more bytes were available.
+ * Ensures that at least {@code n} bytes are available in the buffer, reading
+ * more bytes from the input if necessary to make it so. Caller must ensure
+ * that the requested space is less than BUFFER_SIZE.
+ *
+ * @throws InvalidProtocolBufferException The end of the stream or the current
+ * limit was reached.
*/
- private boolean refillBuffer(final boolean mustSucceed) throws IOException {
- if (bufferPos < bufferSize) {
+ private void ensureAvailable(int n) throws IOException {
+ if (bufferSize - bufferPos < n) {
+ refillBuffer(n);
+ }
+ }
+
+ /**
+ * Reads more bytes from the input, making at least {@code n} bytes available
+ * in the buffer. Caller must ensure that the requested space is not yet
+ * available, and that the requested space is less than BUFFER_SIZE.
+ *
+ * @throws InvalidProtocolBufferException The end of the stream or the current
+ * limit was reached.
+ */
+ private void refillBuffer(int n) throws IOException {
+ if (!tryRefillBuffer(n)) {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+ }
+
+ /**
+ * Tries to read more bytes from the input, making at least {@code n} bytes
+ * available in the buffer. Caller must ensure that the requested space is
+ * not yet available, and that the requested space is less than BUFFER_SIZE.
+ *
+ * @return {@code true} if the bytes could be made available; {@code false}
+ * if the end of the stream or the current limit was reached.
+ */
+ private boolean tryRefillBuffer(int n) throws IOException {
+ if (bufferPos + n <= bufferSize) {
throw new IllegalStateException(
- "refillBuffer() called when buffer wasn't empty.");
+ "refillBuffer() called when " + n +
+ " bytes were already available in buffer");
}
- if (totalBytesRetired + bufferSize == currentLimit) {
+ if (totalBytesRetired + bufferPos + n > currentLimit) {
// Oops, we hit a limit.
- if (mustSucceed) {
- throw InvalidProtocolBufferException.truncatedMessage();
- } else {
- return false;
- }
+ return false;
}
- totalBytesRetired += bufferSize;
-
- bufferPos = 0;
- bufferSize = (input == null) ? -1 : input.read(buffer);
- if (bufferSize == 0 || bufferSize < -1) {
- throw new IllegalStateException(
- "InputStream#read(byte[]) returned invalid result: " + bufferSize +
- "\nThe InputStream implementation is buggy.");
+ if (refillCallback != null) {
+ refillCallback.onRefill();
}
- if (bufferSize == -1) {
- bufferSize = 0;
- if (mustSucceed) {
- throw InvalidProtocolBufferException.truncatedMessage();
- } else {
- return false;
+
+ if (input != null) {
+ int pos = bufferPos;
+ if (pos > 0) {
+ if (bufferSize > pos) {
+ System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos);
+ }
+ totalBytesRetired += pos;
+ bufferSize -= pos;
+ bufferPos = 0;
}
- } else {
- recomputeBufferSizeAfterLimit();
- final int totalBytesRead =
- totalBytesRetired + bufferSize + bufferSizeAfterLimit;
- if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
- throw InvalidProtocolBufferException.sizeLimitExceeded();
+
+ int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize);
+ if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
+ throw new IllegalStateException(
+ "InputStream#read(byte[]) returned invalid result: " + bytesRead +
+ "\nThe InputStream implementation is buggy.");
+ }
+ if (bytesRead > 0) {
+ bufferSize += bytesRead;
+ // Integer-overflow-conscious check against sizeLimit
+ if (totalBytesRetired + n - sizeLimit > 0) {
+ throw InvalidProtocolBufferException.sizeLimitExceeded();
+ }
+ recomputeBufferSizeAfterLimit();
+ return (bufferSize >= n) ? true : tryRefillBuffer(n);
}
- return true;
}
+
+ return false;
}
/**
@@ -731,7 +1146,7 @@ public final class CodedInputStream {
*/
public byte readRawByte() throws IOException {
if (bufferPos == bufferSize) {
- refillBuffer(true);
+ refillBuffer(1);
}
return buffer[bufferPos++];
}
@@ -743,8 +1158,26 @@ public final class CodedInputStream {
* limit was reached.
*/
public byte[] readRawBytes(final int size) throws IOException {
- if (size < 0) {
- throw InvalidProtocolBufferException.negativeSize();
+ final int pos = bufferPos;
+ if (size <= (bufferSize - pos) && size > 0) {
+ bufferPos = pos + size;
+ return Arrays.copyOfRange(buffer, pos, pos + size);
+ } else {
+ return readRawBytesSlowPath(size);
+ }
+ }
+
+ /**
+ * Exactly like readRawBytes, but caller must have already checked the fast
+ * path: (size <= (bufferSize - pos) && size > 0)
+ */
+ private byte[] readRawBytesSlowPath(final int size) throws IOException {
+ if (size <= 0) {
+ if (size == 0) {
+ return Internal.EMPTY_BYTE_ARRAY;
+ } else {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
}
if (totalBytesRetired + bufferPos + size > currentLimit) {
@@ -754,13 +1187,7 @@ public final class CodedInputStream {
throw InvalidProtocolBufferException.truncatedMessage();
}
- if (size <= bufferSize - bufferPos) {
- // We have all the bytes we need already.
- final byte[] bytes = new byte[size];
- System.arraycopy(buffer, bufferPos, bytes, 0, size);
- bufferPos += size;
- return bytes;
- } else if (size < BUFFER_SIZE) {
+ if (size < BUFFER_SIZE) {
// Reading more bytes than are in the buffer, but not an excessive number
// of bytes. We can safely allocate the resulting array ahead of time.
@@ -770,18 +1197,10 @@ public final class CodedInputStream {
System.arraycopy(buffer, bufferPos, bytes, 0, pos);
bufferPos = bufferSize;
- // We want to use refillBuffer() and then copy from the buffer into our
+ // We want to refill the buffer and then copy from the buffer into our
// byte array rather than reading directly into our byte array because
// the input may be unbuffered.
- refillBuffer(true);
-
- while (size - pos > bufferSize) {
- System.arraycopy(buffer, 0, bytes, pos, bufferSize);
- pos += bufferSize;
- bufferPos = bufferSize;
- refillBuffer(true);
- }
-
+ ensureAvailable(size - pos);
System.arraycopy(buffer, 0, bytes, pos, size - pos);
bufferPos = size - pos;
@@ -850,6 +1269,19 @@ public final class CodedInputStream {
* limit was reached.
*/
public void skipRawBytes(final int size) throws IOException {
+ if (size <= (bufferSize - bufferPos) && size >= 0) {
+ // We have all the bytes we need already.
+ bufferPos += size;
+ } else {
+ skipRawBytesSlowPath(size);
+ }
+ }
+
+ /**
+ * Exactly like skipRawBytes, but caller must have already checked the fast
+ * path: (size <= (bufferSize - pos) && size >= 0)
+ */
+ private void skipRawBytesSlowPath(final int size) throws IOException {
if (size < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
@@ -861,25 +1293,19 @@ public final class CodedInputStream {
throw InvalidProtocolBufferException.truncatedMessage();
}
- if (size <= bufferSize - bufferPos) {
- // We have all the bytes we need already.
- bufferPos += size;
- } else {
- // Skipping more bytes than are in the buffer. First skip what we have.
- int pos = bufferSize - bufferPos;
- bufferPos = bufferSize;
+ // Skipping more bytes than are in the buffer. First skip what we have.
+ int pos = bufferSize - bufferPos;
+ bufferPos = bufferSize;
- // Keep refilling the buffer until we get to the point we wanted to skip
- // to. This has the side effect of ensuring the limits are updated
- // correctly.
- refillBuffer(true);
- while (size - pos > bufferSize) {
- pos += bufferSize;
- bufferPos = bufferSize;
- refillBuffer(true);
- }
-
- bufferPos = size - pos;
+ // Keep refilling the buffer until we get to the point we wanted to skip to.
+ // This has the side effect of ensuring the limits are updated correctly.
+ refillBuffer(1);
+ while (size - pos > bufferSize) {
+ pos += bufferSize;
+ bufferPos = bufferSize;
+ refillBuffer(1);
}
+
+ bufferPos = size - pos;
}
}
diff --git a/java/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/src/main/java/com/google/protobuf/CodedOutputStream.java
index ac5f2d30..fafe0356 100644
--- a/java/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,10 +30,10 @@
package com.google.protobuf;
-import java.io.OutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
-import java.io.InputStream;
+import java.nio.ByteBuffer;
/**
* Encodes and writes protocol message fields.
@@ -53,6 +53,7 @@ public final class CodedOutputStream {
private final byte[] buffer;
private final int limit;
private int position;
+ private int totalBytesWritten = 0;
private final OutputStream output;
@@ -129,6 +130,38 @@ public final class CodedOutputStream {
return new CodedOutputStream(flatArray, offset, length);
}
+ /**
+ * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
+ */
+ public static CodedOutputStream newInstance(ByteBuffer byteBuffer) {
+ return newInstance(byteBuffer, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
+ */
+ public static CodedOutputStream newInstance(ByteBuffer byteBuffer,
+ int bufferSize) {
+ return newInstance(new ByteBufferOutputStream(byteBuffer), bufferSize);
+ }
+
+ private static class ByteBufferOutputStream extends OutputStream {
+ private final ByteBuffer byteBuffer;
+ public ByteBufferOutputStream(ByteBuffer byteBuffer) {
+ this.byteBuffer = byteBuffer;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ byteBuffer.put((byte) b);
+ }
+
+ @Override
+ public void write(byte[] data, int offset, int length) throws IOException {
+ byteBuffer.put(data, offset, length);
+ }
+ }
+
// -----------------------------------------------------------------
/** Write a {@code double} field, including tag, to the stream. */
@@ -202,6 +235,7 @@ public final class CodedOutputStream {
writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
}
+
/**
* Write a group represented by an {@link UnknownFieldSet}.
*
@@ -222,6 +256,7 @@ public final class CodedOutputStream {
writeMessageNoTag(value);
}
+
/** Write a {@code bytes} field, including tag, to the stream. */
public void writeBytes(final int fieldNumber, final ByteString value)
throws IOException {
@@ -229,6 +264,39 @@ public final class CodedOutputStream {
writeBytesNoTag(value);
}
+ /** Write a {@code bytes} field, including tag, to the stream. */
+ public void writeByteArray(final int fieldNumber, final byte[] value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeByteArrayNoTag(value);
+ }
+
+ /** Write a {@code bytes} field, including tag, to the stream. */
+ public void writeByteArray(final int fieldNumber,
+ final byte[] value,
+ final int offset,
+ final int length)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeByteArrayNoTag(value, offset, length);
+ }
+
+ /**
+ * Write a {@code bytes} field, including tag, to the stream.
+ * This method will write all content of the ByteBuffer regardless of the
+ * current position and limit (i.e., the number of bytes to be written is
+ * value.capacity(), not value.remaining()). Furthermore, this method doesn't
+ * alter the state of the passed-in ByteBuffer. Its position, limit, mark,
+ * etc. will remain unchanged. If you only want to write the remaining bytes
+ * of a ByteBuffer, you can call
+ * {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}.
+ */
+ public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeByteBufferNoTag(value);
+ }
+
/** Write a {@code uint32} field, including tag, to the stream. */
public void writeUInt32(final int fieldNumber, final int value)
throws IOException {
@@ -362,6 +430,7 @@ public final class CodedOutputStream {
value.writeTo(this);
}
+
/**
* Write a group represented by an {@link UnknownFieldSet}.
*
@@ -380,12 +449,41 @@ public final class CodedOutputStream {
value.writeTo(this);
}
+
/** Write a {@code bytes} field to the stream. */
public void writeBytesNoTag(final ByteString value) throws IOException {
writeRawVarint32(value.size());
writeRawBytes(value);
}
+ /** Write a {@code bytes} field to the stream. */
+ public void writeByteArrayNoTag(final byte[] value) throws IOException {
+ writeRawVarint32(value.length);
+ writeRawBytes(value);
+ }
+
+ /** Write a {@code bytes} field to the stream. */
+ public void writeByteArrayNoTag(final byte[] value,
+ final int offset,
+ final int length) throws IOException {
+ writeRawVarint32(length);
+ writeRawBytes(value, offset, length);
+ }
+
+ /**
+ * Write a {@code bytes} field to the stream. This method will write all
+ * content of the ByteBuffer regardless of the current position and limit
+ * (i.e., the number of bytes to be written is value.capacity(), not
+ * value.remaining()). Furthermore, this method doesn't alter the state of
+ * the passed-in ByteBuffer. Its position, limit, mark, etc. will remain
+ * unchanged. If you only want to write the remaining bytes of a ByteBuffer,
+ * you can call {@code writeByteBufferNoTag(byteBuffer.slice())}.
+ */
+ public void writeByteBufferNoTag(final ByteBuffer value) throws IOException {
+ writeRawVarint32(value.capacity());
+ writeRawBytes(value);
+ }
+
/** Write a {@code uint32} field to the stream. */
public void writeUInt32NoTag(final int value) throws IOException {
writeRawVarint32(value);
@@ -541,6 +639,33 @@ public final class CodedOutputStream {
/**
* Compute the number of bytes that would be needed to encode a
+ * {@code bytes} field, including tag.
+ */
+ public static int computeByteArraySize(final int fieldNumber,
+ final byte[] value) {
+ return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bytes} field, including tag.
+ */
+ public static int computeByteBufferSize(final int fieldNumber,
+ final ByteBuffer value) {
+ return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * embedded message in lazy field, including tag.
+ */
+ public static int computeLazyFieldSize(final int fieldNumber,
+ final LazyFieldLite value) {
+ return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
* {@code uint32} field, including tag.
*/
public static int computeUInt32Size(final int fieldNumber, final int value) {
@@ -614,6 +739,18 @@ public final class CodedOutputStream {
computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
}
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * lazily parsed MessageSet extension field to the stream. For
+ * historical reasons, the wire format differs from normal fields.
+ */
+ public static int computeLazyFieldMessageSetExtensionSize(
+ final int fieldNumber, final LazyFieldLite value) {
+ return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
+ computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
+ computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+ }
+
// -----------------------------------------------------------------
/**
@@ -730,6 +867,15 @@ public final class CodedOutputStream {
}
/**
+ * Compute the number of bytes that would be needed to encode an embedded
+ * message stored in lazy field.
+ */
+ public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) {
+ final int size = value.getSerializedSize();
+ return computeRawVarint32Size(size) + size;
+ }
+
+ /**
* Compute the number of bytes that would be needed to encode a
* {@code bytes} field.
*/
@@ -740,6 +886,22 @@ public final class CodedOutputStream {
/**
* Compute the number of bytes that would be needed to encode a
+ * {@code bytes} field.
+ */
+ public static int computeByteArraySizeNoTag(final byte[] value) {
+ return computeRawVarint32Size(value.length) + value.length;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bytes} field.
+ */
+ public static int computeByteBufferSizeNoTag(final ByteBuffer value) {
+ return computeRawVarint32Size(value.capacity()) + value.capacity();
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
* {@code uint32} field.
*/
public static int computeUInt32SizeNoTag(final int value) {
@@ -856,6 +1018,15 @@ public final class CodedOutputStream {
}
}
+ /**
+ * Get the total number of bytes successfully written to this stream. The
+ * returned value is not guaranteed to be accurate if exceptions have been
+ * found in the middle of writing.
+ */
+ public int getTotalBytesWritten() {
+ return totalBytesWritten;
+ }
+
/** Write a single byte. */
public void writeRawByte(final byte value) throws IOException {
if (position == limit) {
@@ -863,6 +1034,7 @@ public final class CodedOutputStream {
}
buffer[position++] = value;
+ ++totalBytesWritten;
}
/** Write a single byte, represented by an integer value. */
@@ -880,6 +1052,61 @@ public final class CodedOutputStream {
writeRawBytes(value, 0, value.length);
}
+ /**
+ * Write a ByteBuffer. This method will write all content of the ByteBuffer
+ * regardless of the current position and limit (i.e., the number of bytes
+ * to be written is value.capacity(), not value.remaining()). Furthermore,
+ * this method doesn't alter the state of the passed-in ByteBuffer. Its
+ * position, limit, mark, etc. will remain unchanged. If you only want to
+ * write the remaining bytes of a ByteBuffer, you can call
+ * {@code writeRawBytes(byteBuffer.slice())}.
+ */
+ public void writeRawBytes(final ByteBuffer value) throws IOException {
+ if (value.hasArray()) {
+ writeRawBytes(value.array(), value.arrayOffset(), value.capacity());
+ } else {
+ ByteBuffer duplicated = value.duplicate();
+ duplicated.clear();
+ writeRawBytesInternal(duplicated);
+ }
+ }
+
+ /** Write a ByteBuffer that isn't backed by an array. */
+ private void writeRawBytesInternal(final ByteBuffer value)
+ throws IOException {
+ int length = value.remaining();
+ if (limit - position >= length) {
+ // We have room in the current buffer.
+ value.get(buffer, position, length);
+ position += length;
+ totalBytesWritten += length;
+ } else {
+ // Write extends past current buffer. Fill the rest of this buffer and
+ // flush.
+ final int bytesWritten = limit - position;
+ value.get(buffer, position, bytesWritten);
+ length -= bytesWritten;
+ position = limit;
+ totalBytesWritten += bytesWritten;
+ refreshBuffer();
+
+ // Now deal with the rest.
+ // Since we have an output stream, this is our buffer
+ // and buffer offset == 0
+ while (length > limit) {
+ // Copy data into the buffer before writing it to OutputStream.
+ // TODO(xiaofeng): Introduce ZeroCopyOutputStream to avoid this copy.
+ value.get(buffer, 0, limit);
+ output.write(buffer, 0, limit);
+ length -= limit;
+ totalBytesWritten += limit;
+ }
+ value.get(buffer, 0, length);
+ position = length;
+ totalBytesWritten += length;
+ }
+ }
+
/** Write part of an array of bytes. */
public void writeRawBytes(final byte[] value, int offset, int length)
throws IOException {
@@ -887,6 +1114,7 @@ public final class CodedOutputStream {
// We have room in the current buffer.
System.arraycopy(value, offset, buffer, position, length);
position += length;
+ totalBytesWritten += length;
} else {
// Write extends past current buffer. Fill the rest of this buffer and
// flush.
@@ -895,6 +1123,7 @@ public final class CodedOutputStream {
offset += bytesWritten;
length -= bytesWritten;
position = limit;
+ totalBytesWritten += bytesWritten;
refreshBuffer();
// Now deal with the rest.
@@ -908,6 +1137,7 @@ public final class CodedOutputStream {
// Write is very big. Let's do it all at once.
output.write(value, offset, length);
}
+ totalBytesWritten += length;
}
}
@@ -918,6 +1148,7 @@ public final class CodedOutputStream {
// We have room in the current buffer.
value.copyTo(buffer, offset, position, length);
position += length;
+ totalBytesWritten += length;
} else {
// Write extends past current buffer. Fill the rest of this buffer and
// flush.
@@ -926,6 +1157,7 @@ public final class CodedOutputStream {
offset += bytesWritten;
length -= bytesWritten;
position = limit;
+ totalBytesWritten += bytesWritten;
refreshBuffer();
// Now deal with the rest.
@@ -936,25 +1168,9 @@ public final class CodedOutputStream {
value.copyTo(buffer, offset, 0, length);
position = length;
} else {
- // Write is very big, but we can't do it all at once without allocating
- // an a copy of the byte array since ByteString does not give us access
- // to the underlying bytes. Use the InputStream interface on the
- // ByteString and our buffer to copy between the two.
- InputStream inputStreamFrom = value.newInput();
- if (offset != inputStreamFrom.skip(offset)) {
- throw new IllegalStateException("Skip failed? Should never happen.");
- }
- // Use the buffer as the temporary buffer to avoid allocating memory.
- while (length > 0) {
- int bytesToRead = Math.min(length, limit);
- int bytesRead = inputStreamFrom.read(buffer, 0, bytesToRead);
- if (bytesRead != bytesToRead) {
- throw new IllegalStateException("Read failed? Should never happen");
- }
- output.write(buffer, 0, bytesRead);
- length -= bytesRead;
- }
+ value.writeTo(output, offset, length);
}
+ totalBytesWritten += length;
}
}
diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java
index 2ee84594..806f46c1 100644
--- a/java/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/src/main/java/com/google/protobuf/Descriptors.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,11 +32,17 @@ 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;
import java.util.HashMap;
+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;
/**
@@ -58,19 +64,27 @@ import java.io.UnsupportedEncodingException;
* @author kenton@google.com Kenton Varda
*/
public final class Descriptors {
+ private static final Logger logger =
+ Logger.getLogger(Descriptors.class.getName());
/**
* Describes a {@code .proto} file, including everything defined within.
* That includes, in particular, descriptors for all the messages and
* file descriptors for all other imported {@code .proto} files
* (dependencies).
*/
- public static final class FileDescriptor {
+ public static final class FileDescriptor extends GenericDescriptor {
/** Convert the descriptor to its protocol message representation. */
public FileDescriptorProto toProto() { return proto; }
/** Get the file name. */
public String getName() { return proto.getName(); }
+ /** Returns this object. */
+ public FileDescriptor getFile() { return this; }
+
+ /** Returns the same as getName(). */
+ public String getFullName() { return proto.getName(); }
+
/**
* Get the proto package name. This is the package name given by the
* {@code package} statement in the {@code .proto} file, which differs
@@ -106,6 +120,31 @@ public final class Descriptors {
return Collections.unmodifiableList(Arrays.asList(dependencies));
}
+ /** Get a list of this file's public dependencies (public imports). */
+ public List<FileDescriptor> getPublicDependencies() {
+ 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.
*
@@ -206,8 +245,7 @@ public final class Descriptors {
*
* @param proto The protocol message form of the FileDescriptor.
* @param dependencies {@code FileDescriptor}s corresponding to all of
- * the file's dependencies, in the exact order listed
- * in {@code proto}.
+ * the file's dependencies.
* @throws DescriptorValidationException {@code proto} is not a valid
* descriptor. This can occur for a number of reasons, e.g.
* because a field has an undefined type or because two messages
@@ -216,7 +254,29 @@ public final class Descriptors {
public static FileDescriptor buildFrom(final FileDescriptorProto proto,
final FileDescriptor[] dependencies)
throws DescriptorValidationException {
- // Building decsriptors involves two steps: translating and linking.
+ return buildFrom(proto, dependencies, false);
+ }
+
+
+ /**
+ * Construct a {@code FileDescriptor}.
+ *
+ * @param proto The protocol message form of the FileDescriptor.
+ * @param dependencies {@code FileDescriptor}s corresponding to all of
+ * the file's dependencies.
+ * @param allowUnknownDependencies If true, non-exist dependenncies will be
+ * ignored and undefined message types will be replaced with a
+ * placeholder type.
+ * @throws DescriptorValidationException {@code proto} is not a valid
+ * descriptor. This can occur for a number of reasons, e.g.
+ * because a field has an undefined type or because two messages
+ * were defined with the same name.
+ */
+ private static FileDescriptor buildFrom(
+ final FileDescriptorProto proto, final FileDescriptor[] dependencies,
+ final boolean allowUnknownDependencies)
+ throws DescriptorValidationException {
+ // Building descriptors involves two steps: translating and linking.
// In the translation step (implemented by FileDescriptor's
// constructor), we build an object tree mirroring the
// FileDescriptorProto's tree and put all of the descriptors into the
@@ -225,23 +285,10 @@ public final class Descriptors {
// FieldDescriptor for an embedded message contains a pointer directly
// to the Descriptor for that message's type. We also detect undefined
// types in the linking step.
- final DescriptorPool pool = new DescriptorPool(dependencies);
- final FileDescriptor result =
- new FileDescriptor(proto, dependencies, pool);
-
- if (dependencies.length != proto.getDependencyCount()) {
- throw new DescriptorValidationException(result,
- "Dependencies passed to FileDescriptor.buildFrom() don't match " +
- "those listed in the FileDescriptorProto.");
- }
- for (int i = 0; i < proto.getDependencyCount(); i++) {
- if (!dependencies[i].getName().equals(proto.getDependency(i))) {
- throw new DescriptorValidationException(result,
- "Dependencies passed to FileDescriptor.buildFrom() don't match " +
- "those listed in the FileDescriptorProto.");
- }
- }
-
+ final DescriptorPool pool = new DescriptorPool(
+ dependencies, allowUnknownDependencies);
+ final FileDescriptor result = new FileDescriptor(
+ proto, dependencies, pool, allowUnknownDependencies);
result.crossLink();
return result;
}
@@ -289,7 +336,9 @@ public final class Descriptors {
final FileDescriptor result;
try {
- result = buildFrom(proto, dependencies);
+ // When building descriptors for generated code, we allow unknown
+ // dependencies by default.
+ result = buildFrom(proto, dependencies, true);
} catch (DescriptorValidationException e) {
throw new IllegalArgumentException(
"Invalid embedded descriptor for \"" + proto.getName() + "\".", e);
@@ -313,16 +362,66 @@ public final class Descriptors {
}
/**
+ * This method is to be called by generated code only. It uses Java
+ * reflection to load the dependencies' descriptors.
+ */
+ public static void internalBuildGeneratedFileFrom(
+ final String[] descriptorDataParts,
+ final Class<?> descriptorOuterClass,
+ final String[] dependencies,
+ final String[] dependencyFileNames,
+ final InternalDescriptorAssigner descriptorAssigner) {
+ List<FileDescriptor> descriptors = new ArrayList<FileDescriptor>();
+ for (int i = 0; i < dependencies.length; i++) {
+ try {
+ Class<?> clazz =
+ descriptorOuterClass.getClassLoader().loadClass(dependencies[i]);
+ descriptors.add(
+ (FileDescriptor) clazz.getField("descriptor").get(null));
+ } catch (Exception e) {
+ // We allow unknown dependencies by default. If a dependency cannot
+ // be found we only generate a warning.
+ logger.warning("Descriptors for \"" + dependencyFileNames[i] +
+ "\" can not be found.");
+ }
+ }
+ FileDescriptor[] descriptorArray = new FileDescriptor[descriptors.size()];
+ descriptors.toArray(descriptorArray);
+ internalBuildGeneratedFileFrom(
+ descriptorDataParts, descriptorArray, descriptorAssigner);
+ }
+
+ /**
+ * This method is to be called by generated code only. It is used to
+ * update the FileDescriptorProto associated with the descriptor by
+ * parsing it again with the given ExtensionRegistry. This is needed to
+ * recognize custom options.
+ */
+ public static void internalUpdateFileDescriptor(
+ final FileDescriptor descriptor,
+ final ExtensionRegistry registry) {
+ ByteString bytes = descriptor.proto.toByteString();
+ FileDescriptorProto proto;
+ try {
+ proto = FileDescriptorProto.parseFrom(bytes, registry);
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalArgumentException(
+ "Failed to parse protocol buffer descriptor for generated code.", e);
+ }
+ descriptor.setProto(proto);
+ }
+
+ /**
* This class should be used by generated code only. When calling
* {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
* provides a callback implementing this interface. The callback is called
* after the FileDescriptor has been constructed, in order to assign all
- * the global variales defined in the generated code which point at parts
+ * the global variables defined in the generated code which point at parts
* of the FileDescriptor. The callback returns an ExtensionRegistry which
* contains any extensions which might be used in the descriptor -- that
* is, extensions of the various "Options" messages defined in
* descriptor.proto. The callback may also return null to indicate that
- * no extensions are used in the decsriptor.
+ * no extensions are used in the descriptor.
*/
public interface InternalDescriptorAssigner {
ExtensionRegistry assignDescriptors(FileDescriptor root);
@@ -334,15 +433,43 @@ public final class Descriptors {
private final ServiceDescriptor[] services;
private final FieldDescriptor[] extensions;
private final FileDescriptor[] dependencies;
+ private final FileDescriptor[] publicDependencies;
private final DescriptorPool pool;
private FileDescriptor(final FileDescriptorProto proto,
final FileDescriptor[] dependencies,
- final DescriptorPool pool)
+ final DescriptorPool pool,
+ boolean allowUnknownDependencies)
throws DescriptorValidationException {
this.pool = pool;
this.proto = proto;
this.dependencies = dependencies.clone();
+ HashMap<String, FileDescriptor> nameToFileMap =
+ new HashMap<String, FileDescriptor>();
+ for (FileDescriptor file : dependencies) {
+ nameToFileMap.put(file.getName(), file);
+ }
+ List<FileDescriptor> publicDependencies = new ArrayList<FileDescriptor>();
+ for (int i = 0; i < proto.getPublicDependencyCount(); i++) {
+ int index = proto.getPublicDependency(i);
+ if (index < 0 || index >= proto.getDependencyCount()) {
+ throw new DescriptorValidationException(this,
+ "Invalid public dependency index.");
+ }
+ String name = proto.getDependency(index);
+ FileDescriptor file = nameToFileMap.get(name);
+ if (file == null) {
+ if (!allowUnknownDependencies) {
+ throw new DescriptorValidationException(this,
+ "Invalid public dependency: " + name);
+ }
+ // Ignore unknown dependencies.
+ } else {
+ publicDependencies.add(file);
+ }
+ }
+ this.publicDependencies = new FileDescriptor[publicDependencies.size()];
+ publicDependencies.toArray(this.publicDependencies);
pool.addPackage(getPackage(), this);
@@ -368,6 +495,27 @@ public final class Descriptors {
proto.getExtension(i), this, null, i, true);
}
}
+
+ /**
+ * Create a placeholder FileDescriptor for a message Descriptor.
+ */
+ FileDescriptor(String packageName, Descriptor message)
+ throws DescriptorValidationException {
+ this.pool = new DescriptorPool(new FileDescriptor[0], true);
+ this.proto = FileDescriptorProto.newBuilder()
+ .setName(message.getFullName() + ".placeholder.proto")
+ .setPackage(packageName).addMessageType(message.toProto()).build();
+ this.dependencies = new FileDescriptor[0];
+ this.publicDependencies = new FileDescriptor[0];
+
+ messageTypes = new Descriptor[] {message};
+ enumTypes = new EnumDescriptor[0];
+ services = new ServiceDescriptor[0];
+ extensions = new FieldDescriptor[0];
+
+ pool.addPackage(packageName, this);
+ pool.addSymbol(message);
+ }
/** Look up and cross-link all field types, etc. */
private void crossLink() throws DescriptorValidationException {
@@ -390,7 +538,7 @@ public final class Descriptors {
* in the original. This method is needed for bootstrapping when a file
* defines custom options. The options may be defined in the file itself,
* so we can't actually parse them until we've constructed the descriptors,
- * but to construct the decsriptors we have to have parsed the descriptor
+ * but to construct the descriptors we have to have parsed the descriptor
* protos. So, we have to parse the descriptor protos a second time after
* constructing the descriptors.
*/
@@ -413,12 +561,16 @@ public final class Descriptors {
extensions[i].setProto(proto.getExtension(i));
}
}
+
+ boolean supportsUnknownEnumValue() {
+ return getSyntax() == Syntax.PROTO3;
+ }
}
// =================================================================
/** Describes a message type. */
- public static final class Descriptor implements GenericDescriptor {
+ public static final class Descriptor extends GenericDescriptor {
/**
* Get the index of this descriptor within its parent. In other words,
* given a {@link FileDescriptor} {@code file}, the following is true:
@@ -467,6 +619,11 @@ public final class Descriptors {
return Collections.unmodifiableList(Arrays.asList(fields));
}
+ /** Get a list of this message type's oneofs. */
+ public List<OneofDescriptor> getOneofs() {
+ return Collections.unmodifiableList(Arrays.asList(oneofs));
+ }
+
/** Get a list of this message type's extensions. */
public List<FieldDescriptor> getExtensions() {
return Collections.unmodifiableList(Arrays.asList(extensions));
@@ -494,6 +651,14 @@ public final class Descriptors {
}
/**
+ * Indicates whether the message can be extended. That is, whether it has
+ * any "extensions x to y" ranges declared on it.
+ */
+ public boolean isExtendable() {
+ return proto.getExtensionRangeList().size() != 0;
+ }
+
+ /**
* Finds a field by name.
* @param name The unqualified name of the field (e.g. "foo").
* @return The field's descriptor, or {@code null} if not found.
@@ -557,6 +722,33 @@ public final class Descriptors {
private final EnumDescriptor[] enumTypes;
private final FieldDescriptor[] fields;
private final FieldDescriptor[] extensions;
+ private final OneofDescriptor[] oneofs;
+
+ // Used to create a placeholder when the type cannot be found.
+ Descriptor(final String fullname) throws DescriptorValidationException {
+ String name = fullname;
+ String packageName = "";
+ int pos = fullname.lastIndexOf('.');
+ if (pos != -1) {
+ name = fullname.substring(pos + 1);
+ packageName = fullname.substring(0, pos);
+ }
+ this.index = 0;
+ this.proto = DescriptorProto.newBuilder().setName(name).addExtensionRange(
+ DescriptorProto.ExtensionRange.newBuilder().setStart(1)
+ .setEnd(536870912).build()).build();
+ this.fullName = fullname;
+ this.containingType = null;
+
+ this.nestedTypes = new Descriptor[0];
+ this.enumTypes = new EnumDescriptor[0];
+ this.fields = new FieldDescriptor[0];
+ this.extensions = new FieldDescriptor[0];
+ this.oneofs = new OneofDescriptor[0];
+
+ // Create a placeholder FileDescriptor to hold this message.
+ this.file = new FileDescriptor(packageName, this);
+ }
private Descriptor(final DescriptorProto proto,
final FileDescriptor file,
@@ -569,6 +761,12 @@ public final class Descriptors {
this.file = file;
containingType = parent;
+ oneofs = new OneofDescriptor[proto.getOneofDeclCount()];
+ for (int i = 0; i < proto.getOneofDeclCount(); i++) {
+ oneofs[i] = new OneofDescriptor(
+ proto.getOneofDecl(i), file, this, i);
+ }
+
nestedTypes = new Descriptor[proto.getNestedTypeCount()];
for (int i = 0; i < proto.getNestedTypeCount(); i++) {
nestedTypes[i] = new Descriptor(
@@ -593,6 +791,17 @@ public final class Descriptors {
proto.getExtension(i), file, this, i, true);
}
+ for (int i = 0; i < proto.getOneofDeclCount(); i++) {
+ oneofs[i].fields = new FieldDescriptor[oneofs[i].getFieldCount()];
+ oneofs[i].fieldCount = 0;
+ }
+ for (int i = 0; i < proto.getFieldCount(); i++) {
+ OneofDescriptor oneofDescriptor = fields[i].getContainingOneof();
+ if (oneofDescriptor != null) {
+ oneofDescriptor.fields[oneofDescriptor.fieldCount++] = fields[i];
+ }
+ }
+
file.pool.addSymbol(this);
}
@@ -637,11 +846,12 @@ public final class Descriptors {
/** Describes a field of a message type. */
public static final class FieldDescriptor
- implements GenericDescriptor, Comparable<FieldDescriptor>,
+ extends GenericDescriptor
+ implements Comparable<FieldDescriptor>,
FieldSet.FieldDescriptorLite<FieldDescriptor> {
/**
* Get the index of this descriptor within its parent.
- * @see Descriptor#getIndex()
+ * @see Descriptors.Descriptor#getIndex()
*/
public int getIndex() { return index; }
@@ -656,7 +866,7 @@ public final class Descriptors {
/**
* Get the field's fully-qualified name.
- * @see Descriptor#getFullName()
+ * @see Descriptors.Descriptor#getFullName()
*/
public String getFullName() { return fullName; }
@@ -681,6 +891,17 @@ public final class Descriptors {
public WireFormat.FieldType getLiteType() {
return table[type.ordinal()];
}
+
+ /** For internal use only. */
+ public boolean needsUtf8Check() {
+ return (type == Type.STRING) && (getFile().getOptions().getJavaStringCheckUtf8());
+ }
+
+ public 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.
@@ -742,6 +963,9 @@ public final class Descriptors {
*/
public Descriptor getContainingType() { return containingType; }
+ /** Get the field's containing oneof. */
+ public OneofDescriptor getContainingOneof() { return containingOneof; }
+
/**
* For extensions defined nested within message types, gets the outer
* type. Not valid for non-extension fields. For example, consider
@@ -808,6 +1032,11 @@ public final class Descriptors {
return getNumber() - other.getNumber();
}
+ @Override
+ public String toString() {
+ return getFullName();
+ }
+
private final int index;
private FieldDescriptorProto proto;
@@ -819,6 +1048,7 @@ public final class Descriptors {
private Type type;
private Descriptor containingType;
private Descriptor messageType;
+ private OneofDescriptor containingOneof;
private EnumDescriptor enumType;
private Object defaultValue;
@@ -909,13 +1139,6 @@ public final class Descriptors {
"Field numbers must be positive integers.");
}
- // Only repeated primitive fields may be packed.
- if (proto.getOptions().getPacked() && !isPackable()) {
- throw new DescriptorValidationException(this,
- "[packed = true] can only be specified for repeated primitive " +
- "fields.");
- }
-
if (isExtension) {
if (!proto.hasExtendee()) {
throw new DescriptorValidationException(this,
@@ -927,12 +1150,31 @@ public final class Descriptors {
} else {
extensionScope = null;
}
+
+ if (proto.hasOneofIndex()) {
+ throw new DescriptorValidationException(this,
+ "FieldDescriptorProto.oneof_index set for extension field.");
+ }
+ containingOneof = null;
} else {
if (proto.hasExtendee()) {
throw new DescriptorValidationException(this,
"FieldDescriptorProto.extendee set for non-extension field.");
}
containingType = parent;
+
+ if (proto.hasOneofIndex()) {
+ if (proto.getOneofIndex() < 0 ||
+ proto.getOneofIndex() >= parent.toProto().getOneofDeclCount()) {
+ throw new DescriptorValidationException(this,
+ "FieldDescriptorProto.oneof_index is out of range for type "
+ + parent.getName());
+ }
+ containingOneof = parent.getOneofs().get(proto.getOneofIndex());
+ containingOneof.fieldCount++;
+ } else {
+ containingOneof = null;
+ }
extensionScope = null;
}
@@ -943,7 +1185,8 @@ public final class Descriptors {
private void crossLink() throws DescriptorValidationException {
if (proto.hasExtendee()) {
final GenericDescriptor extendee =
- file.pool.lookupSymbol(proto.getExtendee(), this);
+ file.pool.lookupSymbol(proto.getExtendee(), this,
+ DescriptorPool.SearchFilter.TYPES_ONLY);
if (!(extendee instanceof Descriptor)) {
throw new DescriptorValidationException(this,
'\"' + proto.getExtendee() + "\" is not a message type.");
@@ -960,7 +1203,8 @@ public final class Descriptors {
if (proto.hasTypeName()) {
final GenericDescriptor typeDescriptor =
- file.pool.lookupSymbol(proto.getTypeName(), this);
+ file.pool.lookupSymbol(proto.getTypeName(), this,
+ DescriptorPool.SearchFilter.TYPES_ONLY);
if (!proto.hasType()) {
// Choose field type based on symbol.
@@ -1003,6 +1247,13 @@ public final class Descriptors {
}
}
+ // Only repeated primitive fields may be packed.
+ if (proto.getOptions().getPacked() && !isPackable()) {
+ throw new DescriptorValidationException(this,
+ "[packed = true] can only be specified for repeated primitive " +
+ "fields.");
+ }
+
// We don't attempt to parse the default value until here because for
// enums we need the enum type's descriptor.
if (proto.hasDefaultValue()) {
@@ -1140,16 +1391,17 @@ public final class Descriptors {
// down-cast and call mergeFrom directly.
return ((Message.Builder) to).mergeFrom((Message) from);
}
+
}
// =================================================================
/** Describes an enum type. */
- public static final class EnumDescriptor
- implements GenericDescriptor, Internal.EnumLiteMap<EnumValueDescriptor> {
+ public static final class EnumDescriptor extends GenericDescriptor
+ implements Internal.EnumLiteMap<EnumValueDescriptor> {
/**
* Get the index of this descriptor within its parent.
- * @see Descriptor#getIndex()
+ * @see Descriptors.Descriptor#getIndex()
*/
public int getIndex() { return index; }
@@ -1161,7 +1413,7 @@ public final class Descriptors {
/**
* Get the type's fully-qualified name.
- * @see Descriptor#getFullName()
+ * @see Descriptors.Descriptor#getFullName()
*/
public String getFullName() { return fullName; }
@@ -1182,7 +1434,7 @@ public final class Descriptors {
/**
* Find an enum value by name.
* @param name The unqualified name of the value (e.g. "FOO").
- * @return the value's decsriptor, or {@code null} if not found.
+ * @return the value's descriptor, or {@code null} if not found.
*/
public EnumValueDescriptor findValueByName(final String name) {
final GenericDescriptor result =
@@ -1198,12 +1450,70 @@ public final class Descriptors {
* Find an enum value by number. If multiple enum values have the same
* number, this returns the first defined value with that number.
* @param number The value's number.
- * @return the value's decsriptor, or {@code null} if not found.
+ * @return the value's descriptor, or {@code null} if not found.
*/
public EnumValueDescriptor findValueByNumber(final int number) {
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<EnumValueDescriptor> reference = unknownValues.get(key);
+ if (reference != null) {
+ result = reference.get();
+ }
+ if (result == null) {
+ result = new EnumValueDescriptor(file, this, key);
+ unknownValues.put(key, new WeakReference<EnumValueDescriptor>(result));
+ }
+ }
+ return result;
+ }
+
+ // Used in tests only.
+ int getUnknownEnumValueDescriptorCount() {
+ return unknownValues.size();
+ }
private final int index;
private EnumDescriptorProto proto;
@@ -1211,6 +1521,8 @@ public final class Descriptors {
private final FileDescriptor file;
private final Descriptor containingType;
private EnumValueDescriptor[] values;
+ private final WeakHashMap<Integer, WeakReference<EnumValueDescriptor>> unknownValues =
+ new WeakHashMap<Integer, WeakReference<EnumValueDescriptor>>();
private EnumDescriptor(final EnumDescriptorProto proto,
final FileDescriptor file,
@@ -1257,11 +1569,11 @@ public final class Descriptors {
* with the same number after the first become aliases of the first.
* However, they still have independent EnumValueDescriptors.
*/
- public static final class EnumValueDescriptor
- implements GenericDescriptor, Internal.EnumLite {
+ public static final class EnumValueDescriptor extends GenericDescriptor
+ implements Internal.EnumLite {
/**
* Get the index of this descriptor within its parent.
- * @see Descriptor#getIndex()
+ * @see Descriptors.Descriptor#getIndex()
*/
public int getIndex() { return index; }
@@ -1273,10 +1585,13 @@ public final class Descriptors {
/** Get the value's number. */
public int getNumber() { return proto.getNumber(); }
+
+ @Override
+ public String toString() { return proto.getName(); }
/**
* Get the value's fully-qualified name.
- * @see Descriptor#getFullName()
+ * @see Descriptors.Descriptor#getFullName()
*/
public String getFullName() { return fullName; }
@@ -1312,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) {
@@ -1322,7 +1656,7 @@ public final class Descriptors {
// =================================================================
/** Describes a service type. */
- public static final class ServiceDescriptor implements GenericDescriptor {
+ public static final class ServiceDescriptor extends GenericDescriptor {
/**
* Get the index of this descriptor within its parent.
* * @see Descriptors.Descriptor#getIndex()
@@ -1337,7 +1671,7 @@ public final class Descriptors {
/**
* Get the type's fully-qualified name.
- * @see Descriptor#getFullName()
+ * @see Descriptors.Descriptor#getFullName()
*/
public String getFullName() { return fullName; }
@@ -1355,7 +1689,7 @@ public final class Descriptors {
/**
* Find a method by name.
* @param name The unqualified name of the method (e.g. "Foo").
- * @return the method's decsriptor, or {@code null} if not found.
+ * @return the method's descriptor, or {@code null} if not found.
*/
public MethodDescriptor findMethodByName(final String name) {
final GenericDescriptor result =
@@ -1412,7 +1746,7 @@ public final class Descriptors {
/**
* Describes one method within a service type.
*/
- public static final class MethodDescriptor implements GenericDescriptor {
+ public static final class MethodDescriptor extends GenericDescriptor {
/**
* Get the index of this descriptor within its parent.
* * @see Descriptors.Descriptor#getIndex()
@@ -1427,7 +1761,7 @@ public final class Descriptors {
/**
* Get the method's fully-qualified name.
- * @see Descriptor#getFullName()
+ * @see Descriptors.Descriptor#getFullName()
*/
public String getFullName() { return fullName; }
@@ -1475,7 +1809,8 @@ public final class Descriptors {
private void crossLink() throws DescriptorValidationException {
final GenericDescriptor input =
- file.pool.lookupSymbol(proto.getInputType(), this);
+ file.pool.lookupSymbol(proto.getInputType(), this,
+ DescriptorPool.SearchFilter.TYPES_ONLY);
if (!(input instanceof Descriptor)) {
throw new DescriptorValidationException(this,
'\"' + proto.getInputType() + "\" is not a message type.");
@@ -1483,7 +1818,8 @@ public final class Descriptors {
inputType = (Descriptor)input;
final GenericDescriptor output =
- file.pool.lookupSymbol(proto.getOutputType(), this);
+ file.pool.lookupSymbol(proto.getOutputType(), this,
+ DescriptorPool.SearchFilter.TYPES_ONLY);
if (!(output instanceof Descriptor)) {
throw new DescriptorValidationException(this,
'\"' + proto.getOutputType() + "\" is not a message type.");
@@ -1514,14 +1850,18 @@ public final class Descriptors {
// =================================================================
/**
- * All descriptors except {@code FileDescriptor} implement this to make
- * {@code DescriptorPool}'s life easier.
+ * All descriptors implement this to make it easier to implement tools like
+ * {@code DescriptorPool}.<p>
+ *
+ * This class is public so that the methods it exposes can be called from
+ * outside of this package. However, it should only be subclassed from
+ * nested classes of Descriptors.
*/
- private interface GenericDescriptor {
- Message toProto();
- String getName();
- String getFullName();
- FileDescriptor getFile();
+ public abstract static class GenericDescriptor {
+ public abstract Message toProto();
+ public abstract String getName();
+ public abstract String getFullName();
+ public abstract FileDescriptor getFile();
}
/**
@@ -1535,7 +1875,7 @@ public final class Descriptors {
public String getProblemSymbolName() { return name; }
/**
- * Gets the the protocol message representation of the invalid descriptor.
+ * Gets the protocol message representation of the invalid descriptor.
*/
public Message getProblemProto() { return proto; }
@@ -1590,14 +1930,24 @@ public final class Descriptors {
* descriptors defined in a particular file.
*/
private static final class DescriptorPool {
- DescriptorPool(final FileDescriptor[] dependencies) {
- this.dependencies = new DescriptorPool[dependencies.length];
+
+ /** Defines what subclass of descriptors to search in the descriptor pool.
+ */
+ enum SearchFilter {
+ TYPES_ONLY, AGGREGATES_ONLY, ALL_SYMBOLS
+ }
+
+ DescriptorPool(final FileDescriptor[] dependencies,
+ boolean allowUnknownDependencies) {
+ this.dependencies = new HashSet<FileDescriptor>();
+ this.allowUnknownDependencies = allowUnknownDependencies;
- for (int i = 0; i < dependencies.length; i++) {
- this.dependencies[i] = dependencies[i].pool;
+ for (int i = 0; i < dependencies.length; i++) {
+ this.dependencies.add(dependencies[i]);
+ importPublicDependencies(dependencies[i]);
}
- for (final FileDescriptor dependency : dependencies) {
+ for (final FileDescriptor dependency : this.dependencies) {
try {
addPackage(dependency.getPackage(), dependency);
} catch (DescriptorValidationException e) {
@@ -1609,7 +1959,17 @@ public final class Descriptors {
}
}
- private final DescriptorPool[] dependencies;
+ /** Find and put public dependencies of the file into dependencies set.*/
+ private void importPublicDependencies(final FileDescriptor file) {
+ for (FileDescriptor dependency : file.getPublicDependencies()) {
+ if (dependencies.add(dependency)) {
+ importPublicDependencies(dependency);
+ }
+ }
+ }
+
+ private final Set<FileDescriptor> dependencies;
+ private boolean allowUnknownDependencies;
private final Map<String, GenericDescriptor> descriptorsByName =
new HashMap<String, GenericDescriptor>();
@@ -1620,39 +1980,83 @@ public final class Descriptors {
/** Find a generic descriptor by fully-qualified name. */
GenericDescriptor findSymbol(final String fullName) {
+ return findSymbol(fullName, SearchFilter.ALL_SYMBOLS);
+ }
+
+ /** Find a descriptor by fully-qualified name and given option to only
+ * search valid field type descriptors.
+ */
+ GenericDescriptor findSymbol(final String fullName,
+ final SearchFilter filter) {
GenericDescriptor result = descriptorsByName.get(fullName);
if (result != null) {
- return result;
+ if ((filter==SearchFilter.ALL_SYMBOLS) ||
+ ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
+ ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
+ return result;
+ }
}
- for (final DescriptorPool dependency : dependencies) {
- result = dependency.descriptorsByName.get(fullName);
+ for (final FileDescriptor dependency : dependencies) {
+ result = dependency.pool.descriptorsByName.get(fullName);
if (result != null) {
- return result;
+ if ((filter==SearchFilter.ALL_SYMBOLS) ||
+ ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
+ ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
+ return result;
+ }
}
}
return null;
}
+ /** Checks if the descriptor is a valid type for a message field. */
+ boolean isType(GenericDescriptor descriptor) {
+ return (descriptor instanceof Descriptor) ||
+ (descriptor instanceof EnumDescriptor);
+ }
+
+ /** Checks if the descriptor is a valid namespace type. */
+ boolean isAggregate(GenericDescriptor descriptor) {
+ return (descriptor instanceof Descriptor) ||
+ (descriptor instanceof EnumDescriptor) ||
+ (descriptor instanceof PackageDescriptor) ||
+ (descriptor instanceof ServiceDescriptor);
+ }
+
/**
- * Look up a descriptor by name, relative to some other descriptor.
+ * Look up a type descriptor by name, relative to some other descriptor.
* The name may be fully-qualified (with a leading '.'),
* partially-qualified, or unqualified. C++-like name lookup semantics
* are used to search for the matching descriptor.
*/
GenericDescriptor lookupSymbol(final String name,
- final GenericDescriptor relativeTo)
+ final GenericDescriptor relativeTo,
+ final DescriptorPool.SearchFilter filter)
throws DescriptorValidationException {
// TODO(kenton): This could be optimized in a number of ways.
GenericDescriptor result;
+ String fullname;
if (name.startsWith(".")) {
// Fully-qualified name.
- result = findSymbol(name.substring(1));
+ fullname = name.substring(1);
+ result = findSymbol(fullname, filter);
} else {
// If "name" is a compound identifier, we want to search for the
// first component of it, then search within it for the rest.
+ // If name is something like "Foo.Bar.baz", and symbols named "Foo" are
+ // defined in multiple parent scopes, we only want to find "Bar.baz" in
+ // the innermost one. E.g., the following should produce an error:
+ // message Bar { message Baz {} }
+ // message Foo {
+ // message Bar {
+ // }
+ // optional Bar.Baz baz = 1;
+ // }
+ // So, we look for just "Foo" first, then look for "Bar.baz" within it
+ // if found.
final int firstPartLength = name.indexOf('.');
final String firstPart;
if (firstPartLength == -1) {
@@ -1670,14 +2074,16 @@ public final class Descriptors {
// Chop off the last component of the scope.
final int dotpos = scopeToTry.lastIndexOf(".");
if (dotpos == -1) {
- result = findSymbol(name);
+ fullname = name;
+ result = findSymbol(name, filter);
break;
} else {
scopeToTry.setLength(dotpos + 1);
- // Append firstPart and try to find.
+ // Append firstPart and try to find
scopeToTry.append(firstPart);
- result = findSymbol(scopeToTry.toString());
+ result = findSymbol(scopeToTry.toString(),
+ DescriptorPool.SearchFilter.AGGREGATES_ONLY);
if (result != null) {
if (firstPartLength != -1) {
@@ -1686,8 +2092,9 @@ public final class Descriptors {
// searching parent scopes.
scopeToTry.setLength(dotpos + 1);
scopeToTry.append(name);
- result = findSymbol(scopeToTry.toString());
+ result = findSymbol(scopeToTry.toString(), filter);
}
+ fullname = scopeToTry.toString();
break;
}
@@ -1698,8 +2105,24 @@ public final class Descriptors {
}
if (result == null) {
- throw new DescriptorValidationException(relativeTo,
- '\"' + name + "\" is not defined.");
+ if (allowUnknownDependencies && filter == SearchFilter.TYPES_ONLY) {
+ logger.warning("The descriptor for message type \"" + name +
+ "\" can not be found and a placeholder is created for it");
+ // We create a dummy message descriptor here regardless of the
+ // expected type. If the type should be message, this dummy
+ // descriptor will work well and if the type should be enum, a
+ // DescriptorValidationException will be thrown latter. In either
+ // case, the code works as expected: we allow unknown message types
+ // but not unknwon enum types.
+ result = new Descriptor(fullname);
+ // Add the placeholder file as a dependency so we can find the
+ // placeholder symbol when resolving other references.
+ this.dependencies.add(result.getFile());
+ return result;
+ } else {
+ throw new DescriptorValidationException(relativeTo,
+ '\"' + name + "\" is not defined.");
+ }
} else {
return result;
}
@@ -1743,7 +2166,7 @@ public final class Descriptors {
* just as placeholders so that someone cannot define, say, a message type
* that has the same name as an existing package.
*/
- private static final class PackageDescriptor implements GenericDescriptor {
+ private static final class PackageDescriptor extends GenericDescriptor {
public Message toProto() { return file.toProto(); }
public String getName() { return name; }
public String getFullName() { return fullName; }
@@ -1817,7 +2240,7 @@ public final class Descriptors {
/**
* Adds a field to the fieldsByNumber table. Throws an exception if a
- * field with hte same containing type and number already exists.
+ * field with the same containing type and number already exists.
*/
void addFieldByNumber(final FieldDescriptor field)
throws DescriptorValidationException {
@@ -1828,7 +2251,7 @@ public final class Descriptors {
fieldsByNumber.put(key, old);
throw new DescriptorValidationException(field,
"Field number " + field.getNumber() +
- "has already been used in \"" +
+ " has already been used in \"" +
field.getContainingType().getFullName() +
"\" by field \"" + old.getName() + "\".");
}
@@ -1884,4 +2307,47 @@ public final class Descriptors {
}
}
}
+
+ /** Describes an oneof of a message type. */
+ public static final class OneofDescriptor {
+ /** Get the index of this descriptor within its parent. */
+ public int getIndex() { return index; }
+
+ public String getName() { return proto.getName(); }
+
+ public FileDescriptor getFile() { return file; }
+
+ public String getFullName() { return fullName; }
+
+ public Descriptor getContainingType() { return containingType; }
+
+ public int getFieldCount() { return fieldCount; }
+
+ public FieldDescriptor getField(int index) {
+ return fields[index];
+ }
+
+ private OneofDescriptor(final OneofDescriptorProto proto,
+ final FileDescriptor file,
+ final Descriptor parent,
+ final int index)
+ throws DescriptorValidationException {
+ this.proto = proto;
+ fullName = computeFullName(file, parent, proto.getName());
+ this.file = file;
+ this.index = index;
+
+ containingType = parent;
+ fieldCount = 0;
+ }
+
+ private final int index;
+ private OneofDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+
+ private Descriptor containingType;
+ private int fieldCount;
+ private FieldDescriptor[] fields;
+ }
}
diff --git a/java/src/main/java/com/google/protobuf/DynamicMessage.java b/java/src/main/java/com/google/protobuf/DynamicMessage.java
index c106b662..3ea1b688 100644
--- a/java/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -31,10 +31,14 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
import java.util.Map;
/**
@@ -46,16 +50,25 @@ import java.util.Map;
public final class DynamicMessage extends AbstractMessage {
private final Descriptor type;
private final FieldSet<FieldDescriptor> fields;
+ private final FieldDescriptor[] oneofCases;
private final UnknownFieldSet unknownFields;
private int memoizedSize = -1;
/**
* Construct a {@code DynamicMessage} using the given {@code FieldSet}.
+ * oneofCases stores the FieldDescriptor for each oneof to indicate
+ * which field is set. Caller should make sure the array is immutable.
+ *
+ * This constructor is package private and will be used in
+ * {@code DynamicMutableMessage} to convert a mutable message to an immutable
+ * message.
*/
- private DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
- UnknownFieldSet unknownFields) {
+ DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
+ FieldDescriptor[] oneofCases,
+ UnknownFieldSet unknownFields) {
this.type = type;
this.fields = fields;
+ this.oneofCases = oneofCases;
this.unknownFields = unknownFields;
}
@@ -64,10 +77,14 @@ public final class DynamicMessage extends AbstractMessage {
* given type.
*/
public static DynamicMessage getDefaultInstance(Descriptor type) {
+ int oneofDeclCount = type.toProto().getOneofDeclCount();
+ FieldDescriptor[] oneofCases = new FieldDescriptor[oneofDeclCount];
return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
+ oneofCases,
UnknownFieldSet.getDefaultInstance());
}
+
/** Parse a message of the given type from the given input stream. */
public static DynamicMessage parseFrom(Descriptor type,
CodedInputStream input)
@@ -151,6 +168,20 @@ public final class DynamicMessage extends AbstractMessage {
return fields.getAllFields();
}
+ public boolean hasOneof(OneofDescriptor oneof) {
+ verifyOneofContainingType(oneof);
+ FieldDescriptor field = oneofCases[oneof.getIndex()];
+ if (field == null) {
+ return false;
+ }
+ return true;
+ }
+
+ public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+ verifyOneofContainingType(oneof);
+ return oneofCases[oneof.getIndex()];
+ }
+
public boolean hasField(FieldDescriptor field) {
verifyContainingType(field);
return fields.hasField(field);
@@ -160,7 +191,9 @@ public final class DynamicMessage extends AbstractMessage {
verifyContainingType(field);
Object result = fields.getField(field);
if (result == null) {
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ result = Collections.emptyList();
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
result = getDefaultInstance(field.getMessageType());
} else {
result = field.getDefaultValue();
@@ -183,8 +216,8 @@ public final class DynamicMessage extends AbstractMessage {
return unknownFields;
}
- private static boolean isInitialized(Descriptor type,
- FieldSet<FieldDescriptor> fields) {
+ static boolean isInitialized(Descriptor type,
+ FieldSet<FieldDescriptor> fields) {
// Check that all required fields are present.
for (final FieldDescriptor field : type.getFields()) {
if (field.isRequired()) {
@@ -198,10 +231,12 @@ public final class DynamicMessage extends AbstractMessage {
return fields.isInitialized();
}
+ @Override
public boolean isInitialized() {
return isInitialized(type, fields);
}
+ @Override
public void writeTo(CodedOutputStream output) throws IOException {
if (type.getOptions().getMessageSetWireFormat()) {
fields.writeMessageSetTo(output);
@@ -212,6 +247,7 @@ public final class DynamicMessage extends AbstractMessage {
}
}
+ @Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
@@ -236,6 +272,26 @@ public final class DynamicMessage extends AbstractMessage {
return newBuilderForType().mergeFrom(this);
}
+ public Parser<DynamicMessage> getParserForType() {
+ return new AbstractParser<DynamicMessage>() {
+ public DynamicMessage parsePartialFrom(
+ CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ Builder builder = newBuilder(type);
+ try {
+ builder.mergeFrom(input, extensionRegistry);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(builder.buildPartial());
+ } catch (IOException e) {
+ throw new InvalidProtocolBufferException(e.getMessage())
+ .setUnfinishedMessage(builder.buildPartial());
+ }
+ return builder.buildPartial();
+ }
+ };
+ }
+
/** Verifies that the field is a field of this message. */
private void verifyContainingType(FieldDescriptor field) {
if (field.getContainingType() != type) {
@@ -244,6 +300,14 @@ public final class DynamicMessage extends AbstractMessage {
}
}
+ /** Verifies that the oneof is an oneof of this message. */
+ private void verifyOneofContainingType(OneofDescriptor oneof) {
+ if (oneof.getContainingType() != type) {
+ throw new IllegalArgumentException(
+ "OneofDescriptor does not match message type.");
+ }
+ }
+
// =================================================================
/**
@@ -252,6 +316,7 @@ public final class DynamicMessage extends AbstractMessage {
public static final class Builder extends AbstractMessage.Builder<Builder> {
private final Descriptor type;
private FieldSet<FieldDescriptor> fields;
+ private final FieldDescriptor[] oneofCases;
private UnknownFieldSet unknownFields;
/** Construct a {@code Builder} for the given type. */
@@ -259,19 +324,24 @@ public final class DynamicMessage extends AbstractMessage {
this.type = type;
this.fields = FieldSet.newFieldSet();
this.unknownFields = UnknownFieldSet.getDefaultInstance();
+ this.oneofCases = new FieldDescriptor[type.toProto().getOneofDeclCount()];
}
// ---------------------------------------------------------------
// Implementation of Message.Builder interface.
+ @Override
public Builder clear() {
- if (fields == null) {
- throw new IllegalStateException("Cannot call clear() after build().");
+ if (fields.isImmutable()) {
+ fields = FieldSet.newFieldSet();
+ } else {
+ fields.clear();
}
- fields.clear();
+ unknownFields = UnknownFieldSet.getDefaultInstance();
return this;
}
+ @Override
public Builder mergeFrom(Message other) {
if (other instanceof DynamicMessage) {
// This should be somewhat faster than calling super.mergeFrom().
@@ -280,8 +350,20 @@ public final class DynamicMessage extends AbstractMessage {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
}
+ ensureIsMutable();
fields.mergeFrom(otherDynamicMessage.fields);
mergeUnknownFields(otherDynamicMessage.unknownFields);
+ for (int i = 0; i < oneofCases.length; i++) {
+ if (oneofCases[i] == null) {
+ oneofCases[i] = otherDynamicMessage.oneofCases[i];
+ } else {
+ if ((otherDynamicMessage.oneofCases[i] != null)
+ && (oneofCases[i] != otherDynamicMessage.oneofCases[i])) {
+ fields.clearField(oneofCases[i]);
+ oneofCases[i] = otherDynamicMessage.oneofCases[i];
+ }
+ }
+ }
return this;
} else {
return super.mergeFrom(other);
@@ -289,10 +371,10 @@ public final class DynamicMessage extends AbstractMessage {
}
public DynamicMessage build() {
- // If fields == null, we'll throw an appropriate exception later.
- if (fields != null && !isInitialized()) {
+ if (!isInitialized()) {
throw newUninitializedMessageException(
- new DynamicMessage(type, fields, unknownFields));
+ new DynamicMessage(type, fields,
+ java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields));
}
return buildPartial();
}
@@ -305,28 +387,27 @@ public final class DynamicMessage extends AbstractMessage {
private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
if (!isInitialized()) {
throw newUninitializedMessageException(
- new DynamicMessage(type, fields, unknownFields))
+ new DynamicMessage(type, fields,
+ java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields))
.asInvalidProtocolBufferException();
}
return buildPartial();
}
public DynamicMessage buildPartial() {
- if (fields == null) {
- throw new IllegalStateException(
- "build() has already been called on this Builder.");
- }
fields.makeImmutable();
DynamicMessage result =
- new DynamicMessage(type, fields, unknownFields);
- fields = null;
- unknownFields = null;
+ new DynamicMessage(type, fields,
+ java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
return result;
}
+ @Override
public Builder clone() {
Builder result = new Builder(type);
result.fields.mergeFrom(fields);
+ result.mergeUnknownFields(unknownFields);
+ System.arraycopy(oneofCases, 0, result.oneofCases, 0 , oneofCases.length);
return result;
}
@@ -357,6 +438,29 @@ public final class DynamicMessage extends AbstractMessage {
return new Builder(field.getMessageType());
}
+ public boolean hasOneof(OneofDescriptor oneof) {
+ verifyOneofContainingType(oneof);
+ FieldDescriptor field = oneofCases[oneof.getIndex()];
+ if (field == null) {
+ return false;
+ }
+ return true;
+ }
+
+ public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+ verifyOneofContainingType(oneof);
+ return oneofCases[oneof.getIndex()];
+ }
+
+ public Builder clearOneof(OneofDescriptor oneof) {
+ verifyOneofContainingType(oneof);
+ FieldDescriptor field = oneofCases[oneof.getIndex()];
+ if (field != null) {
+ clearField(field);
+ }
+ return this;
+ }
+
public boolean hasField(FieldDescriptor field) {
verifyContainingType(field);
return fields.hasField(field);
@@ -366,7 +470,9 @@ public final class DynamicMessage extends AbstractMessage {
verifyContainingType(field);
Object result = fields.getField(field);
if (result == null) {
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ result = Collections.emptyList();
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
result = getDefaultInstance(field.getMessageType());
} else {
result = field.getDefaultValue();
@@ -377,12 +483,38 @@ public final class DynamicMessage extends AbstractMessage {
public Builder setField(FieldDescriptor field, Object value) {
verifyContainingType(field);
+ ensureIsMutable();
+ // TODO(xiaofeng): This check should really be put in FieldSet.setField()
+ // where all other such checks are done. However, currently
+ // FieldSet.setField() permits Integer value for enum fields probably
+ // because of some internal features we support. Should figure it out
+ // and move this check to a more appropriate place.
+ if (field.getType() == FieldDescriptor.Type.ENUM) {
+ ensureEnumValueDescriptor(field, value);
+ }
+ OneofDescriptor oneofDescriptor = field.getContainingOneof();
+ if (oneofDescriptor != null) {
+ int index = oneofDescriptor.getIndex();
+ FieldDescriptor oldField = oneofCases[index];
+ if ((oldField != null) && (oldField != field)) {
+ fields.clearField(oldField);
+ }
+ oneofCases[index] = field;
+ }
fields.setField(field, value);
return this;
}
public Builder clearField(FieldDescriptor field) {
verifyContainingType(field);
+ ensureIsMutable();
+ OneofDescriptor oneofDescriptor = field.getContainingOneof();
+ if (oneofDescriptor != null) {
+ int index = oneofDescriptor.getIndex();
+ if (oneofCases[index] == field) {
+ oneofCases[index] = null;
+ }
+ }
fields.clearField(field);
return this;
}
@@ -400,12 +532,14 @@ public final class DynamicMessage extends AbstractMessage {
public Builder setRepeatedField(FieldDescriptor field,
int index, Object value) {
verifyContainingType(field);
+ ensureIsMutable();
fields.setRepeatedField(field, index, value);
return this;
}
public Builder addRepeatedField(FieldDescriptor field, Object value) {
verifyContainingType(field);
+ ensureIsMutable();
fields.addRepeatedField(field, value);
return this;
}
@@ -415,11 +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)
@@ -434,5 +579,66 @@ public final class DynamicMessage extends AbstractMessage {
"FieldDescriptor does not match message type.");
}
}
+
+ /** Verifies that the oneof is an oneof of this message. */
+ private void verifyOneofContainingType(OneofDescriptor oneof) {
+ if (oneof.getContainingType() != type) {
+ throw new IllegalArgumentException(
+ "OneofDescriptor does not match message type.");
+ }
+ }
+
+ /** Verifies that the value is EnumValueDescriptor and matches Enum Type. */
+ private void ensureSingularEnumValueDescriptor(
+ FieldDescriptor field, Object value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ if (!(value instanceof EnumValueDescriptor)) {
+ throw new IllegalArgumentException(
+ "DynamicMessage should use EnumValueDescriptor to set Enum Value.");
+ }
+ // TODO(xiaofeng): Re-enable this check after Orgstore is fixed to not
+ // set incorrect EnumValueDescriptors.
+ // EnumDescriptor fieldType = field.getEnumType();
+ // EnumDescriptor fieldValueType = ((EnumValueDescriptor) value).getType();
+ // if (fieldType != fieldValueType) {
+ // throw new IllegalArgumentException(String.format(
+ // "EnumDescriptor %s of field doesn't match EnumDescriptor %s of field value",
+ // fieldType.getFullName(), fieldValueType.getFullName()));
+ // }
+ }
+
+ /** Verifies the value for an enum field. */
+ private void ensureEnumValueDescriptor(
+ FieldDescriptor field, Object value) {
+ if (field.isRepeated()) {
+ for (Object item : (List) value) {
+ ensureSingularEnumValueDescriptor(field, item);
+ }
+ } else {
+ ensureSingularEnumValueDescriptor(field, value);
+ }
+ }
+
+ private void ensureIsMutable() {
+ if (fields.isImmutable()) {
+ fields = fields.clone();
+ }
+ }
+
+ @Override
+ public com.google.protobuf.Message.Builder getFieldBuilder(FieldDescriptor field) {
+ // TODO(xiangl): need implementation for dynamic message
+ 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
new file mode 100644
index 00000000..68d29f33
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Extension.java
@@ -0,0 +1,85 @@
+// 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;
+
+/**
+ * Interface that generated extensions implement.
+ *
+ * @author liujisi@google.com (Jisi Liu)
+ */
+public abstract class Extension<ContainingType extends MessageLite, Type>
+ extends ExtensionLite<ContainingType, Type> {
+
+ /** Returns the descriptor of the extension. */
+ public abstract Descriptors.FieldDescriptor getDescriptor();
+
+ /** Returns whether or not this extension is a Lite Extension. */
+ final boolean isLite() {
+ return false;
+ }
+
+ // All the methods below are extension implementation details.
+
+ /**
+ * The API type that the extension is used for.
+ */
+ protected enum ExtensionType {
+ IMMUTABLE,
+ MUTABLE,
+ PROTO1,
+ }
+
+ protected ExtensionType getExtensionType() {
+ // TODO(liujisi): make this abstract after we fix proto1.
+ return ExtensionType.IMMUTABLE;
+ }
+
+ /**
+ * Type of a message extension.
+ */
+ public enum MessageType {
+ PROTO1,
+ PROTO2,
+ }
+
+ /**
+ * If the extension is a message extension (i.e., getLiteType() == MESSAGE),
+ * returns the type of the message, otherwise undefined.
+ */
+ public MessageType getMessageType() {
+ return MessageType.PROTO2;
+ }
+
+ protected abstract Object fromReflectionType(Object value);
+ protected abstract Object singularFromReflectionType(Object value);
+ protected abstract Object toReflectionType(Object value);
+ protected abstract Object singularToReflectionType(Object value);
+}
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.
+ * <p>
+ * Methods are for use by generated code only. You can hold a reference to
+ * extensions using this type name.
+ */
+public abstract class ExtensionLite<ContainingType extends MessageLite, Type> {
+
+ /** 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/ExtensionRegistry.java b/java/src/main/java/com/google/protobuf/ExtensionRegistry.java
index d4f6ba9e..0067392f 100644
--- a/java/src/main/java/com/google/protobuf/ExtensionRegistry.java
+++ b/java/src/main/java/com/google/protobuf/ExtensionRegistry.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,9 +33,12 @@ package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
/**
* A table of known extensions, searchable by name or field number. When
@@ -90,7 +93,7 @@ import java.util.Map;
*
* @author kenton@google.com Kenton Varda
*/
-public final class ExtensionRegistry extends ExtensionRegistryLite {
+public class ExtensionRegistry extends ExtensionRegistryLite {
/** Construct a new, empty instance. */
public static ExtensionRegistry newInstance() {
return new ExtensionRegistry();
@@ -101,6 +104,7 @@ public final class ExtensionRegistry extends ExtensionRegistryLite {
return EMPTY;
}
+
/** Returns an unmodifiable view of the registry. */
@Override
public ExtensionRegistry getUnmodifiable() {
@@ -130,42 +134,127 @@ public final class ExtensionRegistry extends ExtensionRegistryLite {
}
/**
- * Find an extension by fully-qualified field name, in the proto namespace.
- * I.e. {@code result.descriptor.fullName()} will match {@code fullName} if
- * a match is found.
+ * Deprecated. Use {@link #findImmutableExtensionByName(String)} instead.
+ */
+ public ExtensionInfo findExtensionByName(final String fullName) {
+ return findImmutableExtensionByName(fullName);
+ }
+
+ /**
+ * Find an extension for immutable APIs by fully-qualified field name,
+ * in the proto namespace. i.e. {@code result.descriptor.fullName()} will
+ * match {@code fullName} if a match is found.
*
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
- public ExtensionInfo findExtensionByName(final String fullName) {
- return extensionsByName.get(fullName);
+ public ExtensionInfo findImmutableExtensionByName(final String fullName) {
+ return immutableExtensionsByName.get(fullName);
+ }
+
+ /**
+ * Find an extension for mutable APIs by fully-qualified field name,
+ * in the proto namespace. i.e. {@code result.descriptor.fullName()} will
+ * match {@code fullName} if a match is found.
+ *
+ * @return Information about the extension if found, or {@code null}
+ * otherwise.
+ */
+ public ExtensionInfo findMutableExtensionByName(final String fullName) {
+ return mutableExtensionsByName.get(fullName);
}
/**
- * Find an extension by containing type and field number.
+ * Deprecated. Use {@link #findImmutableExtensionByNumber(
+ * Descriptors.Descriptor, int)}
+ */
+ public ExtensionInfo findExtensionByNumber(
+ final Descriptor containingType, final int fieldNumber) {
+ return findImmutableExtensionByNumber(containingType, fieldNumber);
+ }
+
+ /**
+ * Find an extension by containing type and field number for immutable APIs.
*
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
- public ExtensionInfo findExtensionByNumber(final Descriptor containingType,
- final int fieldNumber) {
- return extensionsByNumber.get(
+ public ExtensionInfo findImmutableExtensionByNumber(
+ final Descriptor containingType, final int fieldNumber) {
+ return immutableExtensionsByNumber.get(
new DescriptorIntPair(containingType, fieldNumber));
}
+ /**
+ * Find an extension by containing type and field number for mutable APIs.
+ *
+ * @return Information about the extension if found, or {@code null}
+ * otherwise.
+ */
+ public ExtensionInfo findMutableExtensionByNumber(
+ final Descriptor containingType, final int fieldNumber) {
+ return mutableExtensionsByNumber.get(
+ new DescriptorIntPair(containingType, fieldNumber));
+ }
+
+ /**
+ * Find all extensions for mutable APIs by fully-qualified name of
+ * extended class. Note that this method is more computationally expensive
+ * than getting a single extension by name or number.
+ *
+ * @return Information about the extensions found, or {@code null} if there
+ * are none.
+ */
+ public Set<ExtensionInfo> getAllMutableExtensionsByExtendedType(final String fullName) {
+ HashSet<ExtensionInfo> extensions = new HashSet<ExtensionInfo>();
+ for (DescriptorIntPair pair : mutableExtensionsByNumber.keySet()) {
+ if (pair.descriptor.getFullName().equals(fullName)) {
+ extensions.add(mutableExtensionsByNumber.get(pair));
+ }
+ }
+ return extensions;
+ }
+
+ /**
+ * Find all extensions for immutable APIs by fully-qualified name of
+ * extended class. Note that this method is more computationally expensive
+ * than getting a single extension by name or number.
+ *
+ * @return Information about the extensions found, or {@code null} if there
+ * are none.
+ */
+ public Set<ExtensionInfo> getAllImmutableExtensionsByExtendedType(final String fullName) {
+ HashSet<ExtensionInfo> extensions = new HashSet<ExtensionInfo>();
+ for (DescriptorIntPair pair : immutableExtensionsByNumber.keySet()) {
+ if (pair.descriptor.getFullName().equals(fullName)) {
+ extensions.add(immutableExtensionsByNumber.get(pair));
+ }
+ }
+ return extensions;
+ }
+
/** Add an extension from a generated file to the registry. */
- public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
+ public void add(final Extension<?, ?> extension) {
+ if (extension.getExtensionType() != Extension.ExtensionType.IMMUTABLE &&
+ extension.getExtensionType() != Extension.ExtensionType.MUTABLE) {
+ // do not support other extension types. ignore
+ return;
+ }
+ add(newExtensionInfo(extension), extension.getExtensionType());
+ }
+
+ static ExtensionInfo newExtensionInfo(final Extension<?, ?> extension) {
if (extension.getDescriptor().getJavaType() ==
FieldDescriptor.JavaType.MESSAGE) {
if (extension.getMessageDefaultInstance() == null) {
throw new IllegalStateException(
"Registered message-type extension had null default instance: " +
- extension.getDescriptor().getFullName());
+ extension.getDescriptor().getFullName());
}
- add(new ExtensionInfo(extension.getDescriptor(),
- extension.getMessageDefaultInstance()));
+ return new ExtensionInfo(extension.getDescriptor(),
+ (Message) extension.getMessageDefaultInstance());
} else {
- add(new ExtensionInfo(extension.getDescriptor(), null));
+ return new ExtensionInfo(extension.getDescriptor(), null);
}
}
@@ -176,7 +265,9 @@ public final class ExtensionRegistry extends ExtensionRegistryLite {
"ExtensionRegistry.add() must be provided a default instance when " +
"adding an embedded message extension.");
}
- add(new ExtensionInfo(type, null));
+ ExtensionInfo info = new ExtensionInfo(type, null);
+ add(info, Extension.ExtensionType.IMMUTABLE);
+ add(info, Extension.ExtensionType.MUTABLE);
}
/** Add a message-type extension to the registry by descriptor. */
@@ -186,40 +277,75 @@ public final class ExtensionRegistry extends ExtensionRegistryLite {
"ExtensionRegistry.add() provided a default instance for a " +
"non-message extension.");
}
- add(new ExtensionInfo(type, defaultInstance));
+ add(new ExtensionInfo(type, defaultInstance),
+ Extension.ExtensionType.IMMUTABLE);
}
// =================================================================
// Private stuff.
private ExtensionRegistry() {
- this.extensionsByName = new HashMap<String, ExtensionInfo>();
- this.extensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
+ this.immutableExtensionsByName = new HashMap<String, ExtensionInfo>();
+ this.mutableExtensionsByName = new HashMap<String, ExtensionInfo>();
+ this.immutableExtensionsByNumber =
+ new HashMap<DescriptorIntPair, ExtensionInfo>();
+ this.mutableExtensionsByNumber =
+ new HashMap<DescriptorIntPair, ExtensionInfo>();
}
private ExtensionRegistry(ExtensionRegistry other) {
super(other);
- this.extensionsByName = Collections.unmodifiableMap(other.extensionsByName);
- this.extensionsByNumber =
- Collections.unmodifiableMap(other.extensionsByNumber);
+ this.immutableExtensionsByName =
+ Collections.unmodifiableMap(other.immutableExtensionsByName);
+ this.mutableExtensionsByName =
+ Collections.unmodifiableMap(other.mutableExtensionsByName);
+ this.immutableExtensionsByNumber =
+ Collections.unmodifiableMap(other.immutableExtensionsByNumber);
+ this.mutableExtensionsByNumber =
+ Collections.unmodifiableMap(other.mutableExtensionsByNumber);
}
- private final Map<String, ExtensionInfo> extensionsByName;
- private final Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
+ private final Map<String, ExtensionInfo> immutableExtensionsByName;
+ private final Map<String, ExtensionInfo> mutableExtensionsByName;
+ private final Map<DescriptorIntPair, ExtensionInfo> immutableExtensionsByNumber;
+ private final Map<DescriptorIntPair, ExtensionInfo> mutableExtensionsByNumber;
- private ExtensionRegistry(boolean empty) {
+ ExtensionRegistry(boolean empty) {
super(ExtensionRegistryLite.getEmptyRegistry());
- this.extensionsByName = Collections.<String, ExtensionInfo>emptyMap();
- this.extensionsByNumber =
+ this.immutableExtensionsByName =
+ Collections.<String, ExtensionInfo>emptyMap();
+ this.mutableExtensionsByName =
+ Collections.<String, ExtensionInfo>emptyMap();
+ this.immutableExtensionsByNumber =
Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
+ this.mutableExtensionsByNumber =
+ Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
}
private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
- private void add(final ExtensionInfo extension) {
+ private void add(
+ final ExtensionInfo extension,
+ final Extension.ExtensionType extensionType) {
if (!extension.descriptor.isExtension()) {
throw new IllegalArgumentException(
- "ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
- "(non-extension) field.");
+ "ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
+ "(non-extension) field.");
+ }
+
+ Map<String, ExtensionInfo> extensionsByName;
+ Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
+ switch (extensionType) {
+ case IMMUTABLE:
+ extensionsByName = immutableExtensionsByName;
+ extensionsByNumber = immutableExtensionsByNumber;
+ break;
+ case MUTABLE:
+ extensionsByName = mutableExtensionsByName;
+ extensionsByNumber = mutableExtensionsByNumber;
+ break;
+ default:
+ // Ignore the unknown supported type.
+ return;
}
extensionsByName.put(extension.descriptor.getFullName(), extension);
diff --git a/java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java b/java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
index d5288dd8..65cf7385 100644
--- a/java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
+++ b/java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -43,7 +43,7 @@ import java.util.Map;
* make sense to mix the two, since if you have any regular types in your
* program, you then require the full runtime and lose all the benefits of
* the lite runtime, so you might as well make all your types be regular types.
- * However, in some cases (e.g. when depending on multiple third-patry libraries
+ * However, in some cases (e.g. when depending on multiple third-party libraries
* where one uses lite types and one uses regular), you may find yourself
* wanting to mix the two. In this case things get more complicated.
* <p>
@@ -71,6 +71,22 @@ import java.util.Map;
* @author kenton@google.com Kenton Varda
*/
public class ExtensionRegistryLite {
+
+ // Set true to enable lazy parsing feature for MessageSet.
+ //
+ // TODO(xiangl): Now we use a global flag to control whether enable lazy
+ // parsing feature for MessageSet, which may be too crude for some
+ // applications. Need to support this feature on smaller granularity.
+ private static volatile boolean eagerlyParseMessageSets = false;
+
+ public static boolean isEagerlyParseMessageSets() {
+ return eagerlyParseMessageSets;
+ }
+
+ public static void setEagerlyParseMessageSets(boolean isEagerlyParse) {
+ eagerlyParseMessageSets = isEagerlyParse;
+ }
+
/** Construct a new, empty instance. */
public static ExtensionRegistryLite newInstance() {
return new ExtensionRegistryLite();
diff --git a/java/src/main/java/com/google/protobuf/FieldSet.java b/java/src/main/java/com/google/protobuf/FieldSet.java
index a85dbaa6..47924b65 100644
--- a/java/src/main/java/com/google/protobuf/FieldSet.java
+++ b/java/src/main/java/com/google/protobuf/FieldSet.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,12 +30,14 @@
package com.google.protobuf;
+import com.google.protobuf.LazyField.LazyIterator;
+
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.io.IOException;
/**
* A class which represents an arbitrary set of fields of some message type.
@@ -68,6 +70,7 @@ final class FieldSet<FieldDescriptorType extends
private final SmallSortedMap<FieldDescriptorType, Object> fields;
private boolean isImmutable;
+ private boolean hasLazyField = false;
/** Construct a new FieldSet. */
private FieldSet() {
@@ -95,7 +98,7 @@ final class FieldSet<FieldDescriptorType extends
FieldSet<T> emptySet() {
return DEFAULT_INSTANCE;
}
- @SuppressWarnings("unchecked")
+ @SuppressWarnings("rawtypes")
private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
/** Make this FieldSet immutable from this point forward. */
@@ -109,7 +112,7 @@ final class FieldSet<FieldDescriptorType extends
}
/**
- * Retuns whether the FieldSet is immutable. This is true if it is the
+ * Returns whether the FieldSet is immutable. This is true if it is the
* {@link #emptySet} or if {@link #makeImmutable} were called.
*
* @return whether the FieldSet is immutable.
@@ -139,29 +142,62 @@ final class FieldSet<FieldDescriptorType extends
FieldDescriptorType descriptor = entry.getKey();
clone.setField(descriptor, entry.getValue());
}
+ clone.hasLazyField = hasLazyField;
return clone;
}
+
// =================================================================
/** See {@link Message.Builder#clear()}. */
public void clear() {
fields.clear();
+ hasLazyField = false;
}
/**
* Get a simple map containing all the fields.
*/
public Map<FieldDescriptorType, Object> getAllFields() {
+ if (hasLazyField) {
+ SmallSortedMap<FieldDescriptorType, Object> result =
+ SmallSortedMap.newFieldMap(16);
+ for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+ cloneFieldEntry(result, fields.getArrayEntryAt(i));
+ }
+ for (Map.Entry<FieldDescriptorType, Object> entry :
+ fields.getOverflowEntries()) {
+ cloneFieldEntry(result, entry);
+ }
+ if (fields.isImmutable()) {
+ result.makeImmutable();
+ }
+ return result;
+ }
return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
}
+ private void cloneFieldEntry(Map<FieldDescriptorType, Object> map,
+ Map.Entry<FieldDescriptorType, Object> entry) {
+ FieldDescriptorType key = entry.getKey();
+ Object value = entry.getValue();
+ if (value instanceof LazyField) {
+ map.put(key, ((LazyField) value).getValue());
+ } else {
+ map.put(key, value);
+ }
+ }
+
/**
* Get an iterator to the field map. This iterator should not be leaked out
- * of the protobuf library as it is not protected from mutation when
- * fields is not immutable.
+ * of the protobuf library as it is not protected from mutation when fields
+ * is not immutable.
*/
public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
+ if (hasLazyField) {
+ return new LazyIterator<FieldDescriptorType>(
+ fields.entrySet().iterator());
+ }
return fields.entrySet().iterator();
}
@@ -185,14 +221,18 @@ final class FieldSet<FieldDescriptorType extends
* to the caller to fetch the field's default value.
*/
public Object getField(final FieldDescriptorType descriptor) {
- return fields.get(descriptor);
+ Object o = fields.get(descriptor);
+ if (o instanceof LazyField) {
+ return ((LazyField) o).getValue();
+ }
+ return o;
}
/**
* Useful for implementing
* {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
*/
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({"unchecked", "rawtypes"})
public void setField(final FieldDescriptorType descriptor,
Object value) {
if (descriptor.isRepeated()) {
@@ -204,7 +244,7 @@ final class FieldSet<FieldDescriptorType extends
// Wrap the contents in a new list so that the caller cannot change
// the list's contents after setting it.
final List newList = new ArrayList();
- newList.addAll((List)value);
+ newList.addAll((List) value);
for (final Object element : newList) {
verifyType(descriptor.getLiteType(), element);
}
@@ -213,6 +253,9 @@ final class FieldSet<FieldDescriptorType extends
verifyType(descriptor.getLiteType(), value);
}
+ if (value instanceof LazyField) {
+ hasLazyField = true;
+ }
fields.put(descriptor, value);
}
@@ -222,6 +265,9 @@ final class FieldSet<FieldDescriptorType extends
*/
public void clearField(final FieldDescriptorType descriptor) {
fields.remove(descriptor);
+ if (fields.isEmpty()) {
+ hasLazyField = false;
+ }
}
/**
@@ -234,7 +280,7 @@ final class FieldSet<FieldDescriptorType extends
"getRepeatedField() can only be called on repeated fields.");
}
- final Object value = fields.get(descriptor);
+ final Object value = getField(descriptor);
if (value == null) {
return 0;
} else {
@@ -253,7 +299,7 @@ final class FieldSet<FieldDescriptorType extends
"getRepeatedField() can only be called on repeated fields.");
}
- final Object value = fields.get(descriptor);
+ final Object value = getField(descriptor);
if (value == null) {
throw new IndexOutOfBoundsException();
@@ -275,13 +321,13 @@ final class FieldSet<FieldDescriptorType extends
"getRepeatedField() can only be called on repeated fields.");
}
- final Object list = fields.get(descriptor);
+ final Object list = getField(descriptor);
if (list == null) {
throw new IndexOutOfBoundsException();
}
verifyType(descriptor.getLiteType(), value);
- ((List) list).set(index, value);
+ ((List<Object>) list).set(index, value);
}
/**
@@ -298,13 +344,13 @@ final class FieldSet<FieldDescriptorType extends
verifyType(descriptor.getLiteType(), value);
- final Object existingValue = fields.get(descriptor);
- List list;
+ final Object existingValue = getField(descriptor);
+ List<Object> list;
if (existingValue == null) {
- list = new ArrayList();
+ list = new ArrayList<Object>();
fields.put(descriptor, list);
} else {
- list = (List) existingValue;
+ list = (List<Object>) existingValue;
}
list.add(value);
@@ -331,14 +377,18 @@ final class FieldSet<FieldDescriptorType extends
case DOUBLE: isValid = value instanceof Double ; break;
case BOOLEAN: isValid = value instanceof Boolean ; break;
case STRING: isValid = value instanceof String ; break;
- case BYTE_STRING: isValid = value instanceof ByteString; break;
+ case BYTE_STRING:
+ isValid = value instanceof ByteString || value instanceof byte[];
+ break;
case ENUM:
// TODO(kenton): Caller must do type checking here, I guess.
- isValid = value instanceof Internal.EnumLite;
+ isValid =
+ (value instanceof Integer || value instanceof Internal.EnumLite);
break;
case MESSAGE:
// TODO(kenton): Caller must do type checking here, I guess.
- isValid = value instanceof MessageLite;
+ isValid =
+ (value instanceof MessageLite) || (value instanceof LazyField);
break;
}
@@ -392,8 +442,16 @@ final class FieldSet<FieldDescriptorType extends
}
}
} else {
- if (!((MessageLite) entry.getValue()).isInitialized()) {
- return false;
+ Object value = entry.getValue();
+ if (value instanceof MessageLite) {
+ if (!((MessageLite) value).isInitialized()) {
+ return false;
+ }
+ } else if (value instanceof LazyField) {
+ return true;
+ } else {
+ throw new IllegalArgumentException(
+ "Wrong object type used with protocol message reflection.");
}
}
}
@@ -416,7 +474,8 @@ final class FieldSet<FieldDescriptorType extends
}
/**
- * Like {@link #mergeFrom(Message)}, but merges from another {@link FieldSet}.
+ * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another
+ * {@link FieldSet}.
*/
public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
@@ -428,38 +487,49 @@ final class FieldSet<FieldDescriptorType extends
}
}
- @SuppressWarnings("unchecked")
+ private Object cloneIfMutable(Object value) {
+ if (value instanceof byte[]) {
+ byte[] bytes = (byte[]) value;
+ byte[] copy = new byte[bytes.length];
+ System.arraycopy(bytes, 0, copy, 0, bytes.length);
+ return copy;
+ } else {
+ return value;
+ }
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
private void mergeFromField(
final Map.Entry<FieldDescriptorType, Object> entry) {
final FieldDescriptorType descriptor = entry.getKey();
- final Object otherValue = entry.getValue();
+ Object otherValue = entry.getValue();
+ if (otherValue instanceof LazyField) {
+ otherValue = ((LazyField) otherValue).getValue();
+ }
if (descriptor.isRepeated()) {
- Object value = fields.get(descriptor);
+ Object value = getField(descriptor);
if (value == null) {
- // Our list is empty, but we still need to make a defensive copy of
- // the other list since we don't know if the other FieldSet is still
- // mutable.
- fields.put(descriptor, new ArrayList((List) otherValue));
- } else {
- // Concatenate the lists.
- ((List) value).addAll((List) otherValue);
+ value = new ArrayList();
}
+ for (Object element : (List) otherValue) {
+ ((List) value).add(cloneIfMutable(element));
+ }
+ fields.put(descriptor, value);
} else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
- Object value = fields.get(descriptor);
+ Object value = getField(descriptor);
if (value == null) {
- fields.put(descriptor, otherValue);
+ fields.put(descriptor, cloneIfMutable(otherValue));
} else {
// Merge the messages.
- fields.put(
- descriptor,
- descriptor.internalMergeFrom(
+ value = descriptor.internalMergeFrom(
((MessageLite) value).toBuilder(), (MessageLite) otherValue)
- .build());
- }
+ .build();
+ fields.put(descriptor, value);
+ }
} else {
- fields.put(descriptor, otherValue);
+ fields.put(descriptor, cloneIfMutable(otherValue));
}
}
@@ -467,11 +537,13 @@ final class FieldSet<FieldDescriptorType extends
// other class. Probably WireFormat.
/**
- * Read a field of any primitive type from a CodedInputStream. Enums,
- * groups, and embedded messages are not handled by this method.
+ * Read a field of any primitive type for immutable messages from a
+ * CodedInputStream. Enums, groups, and embedded messages are not handled by
+ * this method.
*
* @param input The stream from which to read.
* @param type Declared type of the field.
+ * @param checkUtf8 When true, check that the input is valid utf8.
* @return An object representing the field's value, of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
@@ -479,41 +551,18 @@ final class FieldSet<FieldDescriptorType extends
*/
public static Object readPrimitiveField(
CodedInputStream input,
- final WireFormat.FieldType type) throws IOException {
- switch (type) {
- case DOUBLE : return input.readDouble ();
- case FLOAT : return input.readFloat ();
- case INT64 : return input.readInt64 ();
- case UINT64 : return input.readUInt64 ();
- case INT32 : return input.readInt32 ();
- case FIXED64 : return input.readFixed64 ();
- case FIXED32 : return input.readFixed32 ();
- case BOOL : return input.readBool ();
- case STRING : return input.readString ();
- case BYTES : return input.readBytes ();
- case UINT32 : return input.readUInt32 ();
- case SFIXED32: return input.readSFixed32();
- case SFIXED64: return input.readSFixed64();
- case SINT32 : return input.readSInt32 ();
- case SINT64 : return input.readSInt64 ();
-
- case GROUP:
- throw new IllegalArgumentException(
- "readPrimitiveField() cannot handle nested groups.");
- case MESSAGE:
- throw new IllegalArgumentException(
- "readPrimitiveField() cannot handle embedded messages.");
- case ENUM:
- // We don't handle enums because we don't know what to do if the
- // value is not recognized.
- throw new IllegalArgumentException(
- "readPrimitiveField() cannot handle enums.");
+ final WireFormat.FieldType type,
+ boolean checkUtf8) throws IOException {
+ if (checkUtf8) {
+ return WireFormat.readPrimitiveField(input, type,
+ WireFormat.Utf8Validation.STRICT);
+ } else {
+ return WireFormat.readPrimitiveField(input, type,
+ WireFormat.Utf8Validation.LOOSE);
}
-
- throw new RuntimeException(
- "There is no way to get here, but the compiler thinks otherwise.");
}
+
/** See {@link Message#writeTo(CodedOutputStream)}. */
public void writeTo(final CodedOutputStream output)
throws IOException {
@@ -548,8 +597,12 @@ final class FieldSet<FieldDescriptorType extends
final FieldDescriptorType descriptor = entry.getKey();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
!descriptor.isRepeated() && !descriptor.isPacked()) {
+ Object value = entry.getValue();
+ if (value instanceof LazyField) {
+ value = ((LazyField) value).getValue();
+ }
output.writeMessageSetExtension(entry.getKey().getNumber(),
- (MessageLite) entry.getValue());
+ (MessageLite) value);
} else {
writeField(descriptor, entry.getValue(), output);
}
@@ -573,7 +626,7 @@ final class FieldSet<FieldDescriptorType extends
// Special case for groups, which need a start and end tag; other fields
// can just use writeTag() and writeFieldNoTag().
if (type == WireFormat.FieldType.GROUP) {
- output.writeGroup(number, (MessageLite) value);
+ output.writeGroup(number, (MessageLite) value);
} else {
output.writeTag(number, getWireFormatForFieldType(type, false));
writeElementNoTag(output, type, value);
@@ -590,7 +643,7 @@ final class FieldSet<FieldDescriptorType extends
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
- private static void writeElementNoTag(
+ static void writeElementNoTag(
final CodedOutputStream output,
final WireFormat.FieldType type,
final Object value) throws IOException {
@@ -603,10 +656,22 @@ final class FieldSet<FieldDescriptorType extends
case FIXED64 : output.writeFixed64NoTag ((Long ) value); break;
case FIXED32 : output.writeFixed32NoTag ((Integer ) value); break;
case BOOL : output.writeBoolNoTag ((Boolean ) value); break;
- case STRING : output.writeStringNoTag ((String ) value); break;
case GROUP : output.writeGroupNoTag ((MessageLite) value); break;
case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
- case BYTES : output.writeBytesNoTag ((ByteString ) value); break;
+ case STRING:
+ if (value instanceof ByteString) {
+ output.writeBytesNoTag((ByteString) value);
+ } else {
+ output.writeStringNoTag((String) value);
+ }
+ break;
+ case BYTES:
+ if (value instanceof ByteString) {
+ output.writeBytesNoTag((ByteString) value);
+ } else {
+ output.writeByteArrayNoTag((byte[]) value);
+ }
+ break;
case UINT32 : output.writeUInt32NoTag ((Integer ) value); break;
case SFIXED32: output.writeSFixed32NoTag((Integer ) value); break;
case SFIXED64: output.writeSFixed64NoTag((Long ) value); break;
@@ -614,7 +679,11 @@ final class FieldSet<FieldDescriptorType extends
case SINT64 : output.writeSInt64NoTag ((Long ) value); break;
case ENUM:
- output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
+ if (value instanceof Internal.EnumLite) {
+ output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
+ } else {
+ output.writeEnumNoTag(((Integer) value).intValue());
+ }
break;
}
}
@@ -646,7 +715,11 @@ final class FieldSet<FieldDescriptorType extends
}
}
} else {
- writeElement(output, type, number, value);
+ if (value instanceof LazyField) {
+ writeElement(output, type, number, ((LazyField) value).getValue());
+ } else {
+ writeElement(output, type, number, value);
+ }
}
}
@@ -686,12 +759,18 @@ final class FieldSet<FieldDescriptorType extends
private int getMessageSetSerializedSize(
final Map.Entry<FieldDescriptorType, Object> entry) {
final FieldDescriptorType descriptor = entry.getKey();
- if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
- !descriptor.isRepeated() && !descriptor.isPacked()) {
- return CodedOutputStream.computeMessageSetExtensionSize(
- entry.getKey().getNumber(), (MessageLite) entry.getValue());
+ Object value = entry.getValue();
+ if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
+ && !descriptor.isRepeated() && !descriptor.isPacked()) {
+ if (value instanceof LazyField) {
+ return CodedOutputStream.computeLazyFieldMessageSetExtensionSize(
+ entry.getKey().getNumber(), (LazyField) value);
+ } else {
+ return CodedOutputStream.computeMessageSetExtensionSize(
+ entry.getKey().getNumber(), (MessageLite) value);
+ }
} else {
- return computeFieldSize(descriptor, entry.getValue());
+ return computeFieldSize(descriptor, value);
}
}
@@ -711,7 +790,9 @@ final class FieldSet<FieldDescriptorType extends
final int number, final Object value) {
int tagSize = CodedOutputStream.computeTagSize(number);
if (type == WireFormat.FieldType.GROUP) {
- tagSize *= 2;
+ // Only count the end group tag for proto2 messages as for proto1 the end
+ // group tag will be counted as a part of getSerializedSize().
+ tagSize *= 2;
}
return tagSize + computeElementSizeNoTag(type, value);
}
@@ -726,7 +807,7 @@ final class FieldSet<FieldDescriptorType extends
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
- private static int computeElementSizeNoTag(
+ static int computeElementSizeNoTag(
final WireFormat.FieldType type, final Object value) {
switch (type) {
// Note: Minor violation of 80-char limit rule here because this would
@@ -739,19 +820,39 @@ final class FieldSet<FieldDescriptorType extends
case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long )value);
case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer )value);
case BOOL : return CodedOutputStream.computeBoolSizeNoTag ((Boolean )value);
- case STRING : return CodedOutputStream.computeStringSizeNoTag ((String )value);
case GROUP : return CodedOutputStream.computeGroupSizeNoTag ((MessageLite)value);
- case MESSAGE : return CodedOutputStream.computeMessageSizeNoTag ((MessageLite)value);
- case BYTES : return CodedOutputStream.computeBytesSizeNoTag ((ByteString )value);
+ case BYTES :
+ if (value instanceof ByteString) {
+ return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
+ } else {
+ return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value);
+ }
+ case STRING :
+ if (value instanceof ByteString) {
+ return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
+ } else {
+ return CodedOutputStream.computeStringSizeNoTag((String) value);
+ }
case UINT32 : return CodedOutputStream.computeUInt32SizeNoTag ((Integer )value);
case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer )value);
case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long )value);
case SINT32 : return CodedOutputStream.computeSInt32SizeNoTag ((Integer )value);
case SINT64 : return CodedOutputStream.computeSInt64SizeNoTag ((Long )value);
+ case MESSAGE:
+ if (value instanceof LazyField) {
+ return CodedOutputStream.computeLazyFieldSizeNoTag((LazyField) value);
+ } else {
+ return CodedOutputStream.computeMessageSizeNoTag((MessageLite) value);
+ }
+
case ENUM:
- return CodedOutputStream.computeEnumSizeNoTag(
- ((Internal.EnumLite) value).getNumber());
+ if (value instanceof Internal.EnumLite) {
+ return CodedOutputStream.computeEnumSizeNoTag(
+ ((Internal.EnumLite) value).getNumber());
+ } else {
+ return CodedOutputStream.computeEnumSizeNoTag((Integer) value);
+ }
}
throw new RuntimeException(
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
index b5eaded5..9457d999 100644
--- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -31,14 +31,20 @@
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.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+import com.google.protobuf.GeneratedMessageLite.ExtendableMessage;
+import com.google.protobuf.GeneratedMessageLite.GeneratedExtension;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -58,8 +64,6 @@ public abstract class GeneratedMessage extends AbstractMessage
implements Serializable {
private static final long serialVersionUID = 1L;
- private final UnknownFieldSet unknownFields;
-
/**
* For testing. Allows a test to disable the optimization that avoids using
* field builders for nested messages until they are requested. By disabling
@@ -67,12 +71,20 @@ public abstract class GeneratedMessage extends AbstractMessage
*/
protected static boolean alwaysUseFieldBuilders = false;
+ /** For use by generated code only. */
+ protected UnknownFieldSet unknownFields;
+
protected GeneratedMessage() {
- this.unknownFields = UnknownFieldSet.getDefaultInstance();
+ unknownFields = UnknownFieldSet.getDefaultInstance();
}
protected GeneratedMessage(Builder<?> builder) {
- this.unknownFields = builder.getUnknownFields();
+ unknownFields = builder.getUnknownFields();
+ }
+
+ public Parser<? extends GeneratedMessage> getParserForType() {
+ throw new UnsupportedOperationException(
+ "This is supposed to be overridden by subclasses.");
}
/**
@@ -97,8 +109,15 @@ public abstract class GeneratedMessage extends AbstractMessage
return internalGetFieldAccessorTable().descriptor;
}
- /** Internal helper which returns a mutable map. */
- private Map<FieldDescriptor, Object> getAllFieldsMutable() {
+ /**
+ * Internal helper to return a modifiable map containing all the fields.
+ * The returned Map is modifialbe so that the caller can add additional
+ * extension fields to implement {@link #getAllFields()}.
+ *
+ * @param getBytesForString whether to generate ByteString for string fields
+ */
+ private Map<FieldDescriptor, Object> getAllFieldsMutable(
+ boolean getBytesForString) {
final TreeMap<FieldDescriptor, Object> result =
new TreeMap<FieldDescriptor, Object>();
final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
@@ -110,7 +129,12 @@ public abstract class GeneratedMessage extends AbstractMessage
}
} else {
if (hasField(field)) {
- result.put(field, getField(field));
+ if (getBytesForString
+ && field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+ result.put(field, getFieldRaw(field));
+ } else {
+ result.put(field, getField(field));
+ }
}
}
}
@@ -149,7 +173,33 @@ public abstract class GeneratedMessage extends AbstractMessage
//@Override (Java 1.6 override semantics, but we must support 1.5)
public Map<FieldDescriptor, Object> getAllFields() {
- return Collections.unmodifiableMap(getAllFieldsMutable());
+ return Collections.unmodifiableMap(
+ getAllFieldsMutable(/* getBytesForString = */ false));
+ }
+
+ /**
+ * Returns a collection of all the fields in this message which are set
+ * and their corresponding values. A singular ("required" or "optional")
+ * field is set iff hasField() returns true for that field. A "repeated"
+ * field is set iff getRepeatedFieldCount() is greater than zero. The
+ * values are exactly what would be returned by calling
+ * {@link #getFieldRaw(Descriptors.FieldDescriptor)} for each field. The map
+ * is guaranteed to be a sorted map, so iterating over it will return fields
+ * in order by field number.
+ */
+ Map<FieldDescriptor, Object> getAllFieldsRaw() {
+ return Collections.unmodifiableMap(
+ getAllFieldsMutable(/* getBytesForString = */ true));
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public boolean hasOneof(final OneofDescriptor oneof) {
+ return internalGetFieldAccessorTable().getOneof(oneof).has(this);
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+ return internalGetFieldAccessorTable().getOneof(oneof).get(this);
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
@@ -162,6 +212,18 @@ public abstract class GeneratedMessage extends AbstractMessage
return internalGetFieldAccessorTable().getField(field).get(this);
}
+ /**
+ * Obtains the value of the given field, or the default value if it is
+ * not set. For primitive fields, the boxed primitive value is returned.
+ * For enum fields, the EnumValueDescriptor for the value is returned. For
+ * embedded message fields, the sub-message is returned. For repeated
+ * fields, a java.util.List is returned. For present string fields, a
+ * ByteString is returned representing the bytes that the field contains.
+ */
+ Object getFieldRaw(final FieldDescriptor field) {
+ return internalGetFieldAccessorTable().getField(field).getRaw(this);
+ }
+
//@Override (Java 1.6 override semantics, but we must support 1.5)
public int getRepeatedFieldCount(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field)
@@ -175,8 +237,47 @@ public abstract class GeneratedMessage extends AbstractMessage
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
- public final UnknownFieldSet getUnknownFields() {
- return unknownFields;
+ public UnknownFieldSet getUnknownFields() {
+ throw new UnsupportedOperationException(
+ "This is supposed to be overridden by subclasses.");
+ }
+
+ /**
+ * Called by subclasses to parse an unknown field.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ protected boolean parseUnknownField(
+ CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistryLite extensionRegistry,
+ int tag) throws IOException {
+ return unknownFields.mergeFieldFrom(tag, input);
+ }
+
+ @Override
+ public void writeTo(final CodedOutputStream output) throws IOException {
+ MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false);
+ }
+
+ @Override
+ public int getSerializedSize() {
+ int size = memoizedSize;
+ if (size != -1) {
+ return size;
+ }
+
+ memoizedSize = MessageReflection.getSerializedSize(
+ this, getAllFieldsRaw());
+ return memoizedSize;
+ }
+
+
+
+ /**
+ * Used by parsing constructors in generated classes.
+ */
+ protected void makeExtensionsImmutable() {
+ // Noop for messages without extensions.
}
protected abstract Message.Builder newBuilderForType(BuilderParent parent);
@@ -257,13 +358,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;
}
/**
@@ -319,6 +419,28 @@ public abstract class GeneratedMessage extends AbstractMessage
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
+ public Message.Builder getFieldBuilder(final FieldDescriptor field) {
+ 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);
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+ return internalGetFieldAccessorTable().getOneof(oneof).get(this);
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
public boolean hasField(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field).has(this);
}
@@ -348,6 +470,12 @@ public abstract class GeneratedMessage extends AbstractMessage
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
+ public BuilderType clearOneof(final OneofDescriptor oneof) {
+ internalGetFieldAccessorTable().getOneof(oneof).clear(this);
+ return (BuilderType) this;
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
public int getRepeatedFieldCount(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field)
.getRepeatedCount(this);
@@ -373,7 +501,7 @@ public abstract class GeneratedMessage extends AbstractMessage
return (BuilderType) this;
}
- public final BuilderType setUnknownFields(
+ public BuilderType setUnknownFields(
final UnknownFieldSet unknownFields) {
this.unknownFields = unknownFields;
onChanged();
@@ -381,7 +509,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
@Override
- public final BuilderType mergeUnknownFields(
+ public BuilderType mergeUnknownFields(
final UnknownFieldSet unknownFields) {
this.unknownFields =
UnknownFieldSet.newBuilder(this.unknownFields)
@@ -474,6 +602,34 @@ 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());
+ }
+
+ /** Like {@link internalGetMapField} but return a mutable version. */
+ @SuppressWarnings({"unused", "rawtypes"})
+ protected MapField internalGetMutableMapField(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());
+ }
}
// =================================================================
@@ -481,21 +637,24 @@ public abstract class GeneratedMessage extends AbstractMessage
public interface ExtendableMessageOrBuilder<
MessageType extends ExtendableMessage> extends MessageOrBuilder {
+ // Re-define for return type covariance.
+ Message getDefaultInstanceForType();
/** Check if a singular extension is present. */
<Type> boolean hasExtension(
- GeneratedExtension<MessageType, Type> extension);
+ ExtensionLite<MessageType, Type> extension);
/** Get the number of elements in a repeated extension. */
<Type> int getExtensionCount(
- GeneratedExtension<MessageType, List<Type>> extension);
+ ExtensionLite<MessageType, List<Type>> extension);
/** Get the value of an extension. */
- <Type> Type getExtension(GeneratedExtension<MessageType, Type> extension);
+ <Type> Type getExtension(
+ ExtensionLite<MessageType, Type> extension);
/** Get one element of a repeated extension. */
<Type> Type getExtension(
- GeneratedExtension<MessageType, List<Type>> extension,
+ ExtensionLite<MessageType, List<Type>> extension,
int index);
}
@@ -552,7 +711,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
private void verifyExtensionContainingType(
- final GeneratedExtension<MessageType, ?> extension) {
+ final Extension<MessageType, ?> extension) {
if (extension.getDescriptor().getContainingType() !=
getDescriptorForType()) {
// This can only happen if someone uses unchecked operations.
@@ -567,7 +726,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 <Type> boolean hasExtension(
- final GeneratedExtension<MessageType, Type> extension) {
+ final ExtensionLite<MessageType, Type> extensionLite) {
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
return extensions.hasField(extension.getDescriptor());
}
@@ -575,7 +736,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 <Type> int getExtensionCount(
- final GeneratedExtension<MessageType, List<Type>> extension) {
+ final ExtensionLite<MessageType, List<Type>> extensionLite) {
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
final FieldDescriptor descriptor = extension.getDescriptor();
return extensions.getRepeatedFieldCount(descriptor);
@@ -585,7 +748,9 @@ public abstract class GeneratedMessage extends AbstractMessage
//@Override (Java 1.6 override semantics, but we must support 1.5)
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
- final GeneratedExtension<MessageType, Type> extension) {
+ final ExtensionLite<MessageType, Type> extensionLite) {
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
FieldDescriptor descriptor = extension.getDescriptor();
final Object value = extensions.getField(descriptor);
@@ -608,8 +773,10 @@ public abstract class GeneratedMessage extends AbstractMessage
//@Override (Java 1.6 override semantics, but we must support 1.5)
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
- final GeneratedExtension<MessageType, List<Type>> extension,
+ final ExtensionLite<MessageType, List<Type>> extensionLite,
final int index) {
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
FieldDescriptor descriptor = extension.getDescriptor();
return (Type) extension.singularFromReflectionType(
@@ -626,6 +793,26 @@ public abstract class GeneratedMessage extends AbstractMessage
return super.isInitialized() && extensionsAreInitialized();
}
+ @Override
+ protected boolean parseUnknownField(
+ CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistryLite extensionRegistry,
+ int tag) throws IOException {
+ return MessageReflection.mergeFieldFrom(
+ input, unknownFields, extensionRegistry, getDescriptorForType(),
+ new MessageReflection.ExtensionAdapter(extensions), tag);
+ }
+
+
+ /**
+ * Used by parsing constructors in generated classes.
+ */
+ @Override
+ protected void makeExtensionsImmutable() {
+ extensions.makeImmutable();
+ }
+
/**
* Used by subclasses to serialize extensions. Extension ranges may be
* interleaved with field numbers, but we must write them in canonical
@@ -655,9 +842,21 @@ public abstract class GeneratedMessage extends AbstractMessage
if (messageSetWireFormat && descriptor.getLiteJavaType() ==
WireFormat.JavaType.MESSAGE &&
!descriptor.isRepeated()) {
- output.writeMessageSetExtension(descriptor.getNumber(),
- (Message) next.getValue());
+ if (next instanceof LazyField.LazyEntry<?>) {
+ output.writeRawMessageSetExtension(descriptor.getNumber(),
+ ((LazyField.LazyEntry<?>) next).getField().toByteString());
+ } else {
+ output.writeMessageSetExtension(descriptor.getNumber(),
+ (Message) next.getValue());
+ }
} else {
+ // TODO(xiangl): Taken care of following code, it may cause
+ // problem when we use LazyField for normal fields/extensions.
+ // Due to the optional field can be duplicated at the end of
+ // serialized bytes, which will make the serialized size change
+ // after lazy field parsed. So when we use LazyField globally,
+ // we need to change the following write method to write cached
+ // bytes directly rather than write the parsed message.
FieldSet.writeField(descriptor, next.getValue(), output);
}
if (iter.hasNext()) {
@@ -693,7 +892,16 @@ public abstract class GeneratedMessage extends AbstractMessage
@Override
public Map<FieldDescriptor, Object> getAllFields() {
- final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
+ final Map<FieldDescriptor, Object> result =
+ super.getAllFieldsMutable(/* getBytesForString = */ false);
+ result.putAll(getExtensionFields());
+ return Collections.unmodifiableMap(result);
+ }
+
+ @Override
+ public Map<FieldDescriptor, Object> getAllFieldsRaw() {
+ final Map<FieldDescriptor, Object> result =
+ super.getAllFieldsMutable(/* getBytesForString = */ false);
result.putAll(getExtensionFields());
return Collections.unmodifiableMap(result);
}
@@ -811,6 +1019,11 @@ public abstract class GeneratedMessage extends AbstractMessage
super(parent);
}
+ // For immutable message conversion.
+ void internalSetExtensionSet(FieldSet<FieldDescriptor> extensions) {
+ this.extensions = extensions;
+ }
+
@Override
public BuilderType clear() {
extensions = FieldSet.emptySet();
@@ -819,11 +1032,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() {
@@ -833,7 +1045,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
private void verifyExtensionContainingType(
- final GeneratedExtension<MessageType, ?> extension) {
+ final Extension<MessageType, ?> extension) {
if (extension.getDescriptor().getContainingType() !=
getDescriptorForType()) {
// This can only happen if someone uses unchecked operations.
@@ -848,7 +1060,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 <Type> boolean hasExtension(
- final GeneratedExtension<MessageType, Type> extension) {
+ final ExtensionLite<MessageType, Type> extensionLite) {
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
return extensions.hasField(extension.getDescriptor());
}
@@ -856,7 +1070,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 <Type> int getExtensionCount(
- final GeneratedExtension<MessageType, List<Type>> extension) {
+ final ExtensionLite<MessageType, List<Type>> extensionLite) {
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
final FieldDescriptor descriptor = extension.getDescriptor();
return extensions.getRepeatedFieldCount(descriptor);
@@ -865,7 +1081,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> Type getExtension(
- final GeneratedExtension<MessageType, Type> extension) {
+ final ExtensionLite<MessageType, Type> extensionLite) {
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
FieldDescriptor descriptor = extension.getDescriptor();
final Object value = extensions.getField(descriptor);
@@ -887,8 +1105,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> Type getExtension(
- final GeneratedExtension<MessageType, List<Type>> extension,
+ final ExtensionLite<MessageType, List<Type>> extensionLite,
final int index) {
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
FieldDescriptor descriptor = extension.getDescriptor();
return (Type) extension.singularFromReflectionType(
@@ -897,8 +1117,10 @@ public abstract class GeneratedMessage extends AbstractMessage
/** Set the value of an extension. */
public final <Type> BuilderType setExtension(
- final GeneratedExtension<MessageType, Type> extension,
+ final ExtensionLite<MessageType, Type> extensionLite,
final Type value) {
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
ensureExtensionsIsMutable();
final FieldDescriptor descriptor = extension.getDescriptor();
@@ -909,8 +1131,10 @@ public abstract class GeneratedMessage extends AbstractMessage
/** Set the value of one element of a repeated extension. */
public final <Type> BuilderType setExtension(
- final GeneratedExtension<MessageType, List<Type>> extension,
+ final ExtensionLite<MessageType, List<Type>> extensionLite,
final int index, final Type value) {
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
ensureExtensionsIsMutable();
final FieldDescriptor descriptor = extension.getDescriptor();
@@ -923,8 +1147,10 @@ public abstract class GeneratedMessage extends AbstractMessage
/** Append a value to a repeated extension. */
public final <Type> BuilderType addExtension(
- final GeneratedExtension<MessageType, List<Type>> extension,
+ final ExtensionLite<MessageType, List<Type>> extensionLite,
final Type value) {
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
ensureExtensionsIsMutable();
final FieldDescriptor descriptor = extension.getDescriptor();
@@ -936,7 +1162,9 @@ public abstract class GeneratedMessage extends AbstractMessage
/** Clear an extension. */
public final <Type> BuilderType clearExtension(
- final GeneratedExtension<MessageType, ?> extension) {
+ final ExtensionLite<MessageType, ?> extensionLite) {
+ Extension<MessageType, ?> extension = checkNotLite(extensionLite);
+
verifyExtensionContainingType(extension);
ensureExtensionsIsMutable();
extensions.clearField(extension.getDescriptor());
@@ -973,8 +1201,9 @@ public abstract class GeneratedMessage extends AbstractMessage
final UnknownFieldSet.Builder unknownFields,
final ExtensionRegistryLite extensionRegistry,
final int tag) throws IOException {
- return AbstractMessage.Builder.mergeFieldFrom(
- input, unknownFields, extensionRegistry, this, tag);
+ return MessageReflection.mergeFieldFrom(
+ input, unknownFields, extensionRegistry, getDescriptorForType(),
+ new MessageReflection.BuilderAdapter(this), tag);
}
// ---------------------------------------------------------------
@@ -1114,7 +1343,7 @@ public abstract class GeneratedMessage extends AbstractMessage
* Gets the descriptor for an extension. The implementation depends on whether
* the extension is scoped in the top level of a file or scoped in a Message.
*/
- private static interface ExtensionDescriptorRetriever {
+ static interface ExtensionDescriptorRetriever {
FieldDescriptor getDescriptor();
}
@@ -1129,15 +1358,16 @@ public abstract class GeneratedMessage extends AbstractMessage
// the outer class's descriptor, from which the extension descriptor is
// obtained.
return new GeneratedExtension<ContainingType, Type>(
- new ExtensionDescriptorRetriever() {
+ new CachedDescriptorRetriever() {
//@Override (Java 1.6 override semantics, but we must support 1.5)
- public FieldDescriptor getDescriptor() {
+ public FieldDescriptor loadDescriptor() {
return scope.getDescriptorForType().getExtensions()
.get(descriptorIndex);
}
},
singularType,
- defaultInstance);
+ defaultInstance,
+ Extension.ExtensionType.IMMUTABLE);
}
/** For use by generated code only. */
@@ -1151,7 +1381,87 @@ public abstract class GeneratedMessage extends AbstractMessage
return new GeneratedExtension<ContainingType, Type>(
null, // ExtensionDescriptorRetriever is initialized in internalInit();
singularType,
- defaultInstance);
+ defaultInstance,
+ Extension.ExtensionType.IMMUTABLE);
+ }
+
+ private abstract static class CachedDescriptorRetriever
+ implements ExtensionDescriptorRetriever {
+ private volatile FieldDescriptor descriptor;
+ protected abstract FieldDescriptor loadDescriptor();
+
+ public FieldDescriptor getDescriptor() {
+ if (descriptor == null) {
+ synchronized (this) {
+ if (descriptor == null) {
+ descriptor = loadDescriptor();
+ }
+ }
+ }
+ return descriptor;
+ }
+ }
+
+ /**
+ * Used in proto1 generated code only.
+ *
+ * After enabling bridge, we can define proto2 extensions (the extended type
+ * is a proto2 mutable message) in a proto1 .proto file. For these extensions
+ * we should generate proto2 GeneratedExtensions.
+ */
+ public static <ContainingType extends Message, Type>
+ GeneratedExtension<ContainingType, Type>
+ newMessageScopedGeneratedExtension(
+ final Message scope, final String name,
+ final Class singularType, final Message defaultInstance) {
+ // For extensions scoped within a Message, we use the Message to resolve
+ // the outer class's descriptor, from which the extension descriptor is
+ // obtained.
+ return new GeneratedExtension<ContainingType, Type>(
+ new CachedDescriptorRetriever() {
+ protected FieldDescriptor loadDescriptor() {
+ return scope.getDescriptorForType().findFieldByName(name);
+ }
+ },
+ singularType,
+ defaultInstance,
+ Extension.ExtensionType.MUTABLE);
+ }
+
+ /**
+ * Used in proto1 generated code only.
+ *
+ * After enabling bridge, we can define proto2 extensions (the extended type
+ * is a proto2 mutable message) in a proto1 .proto file. For these extensions
+ * we should generate proto2 GeneratedExtensions.
+ */
+ public static <ContainingType extends Message, Type>
+ GeneratedExtension<ContainingType, Type>
+ newFileScopedGeneratedExtension(
+ final Class singularType, final Message defaultInstance,
+ final String descriptorOuterClass, final String extensionName) {
+ // For extensions scoped within a file, we load the descriptor outer
+ // class and rely on it to get the FileDescriptor which then can be
+ // used to obtain the extension's FieldDescriptor.
+ return new GeneratedExtension<ContainingType, Type>(
+ new CachedDescriptorRetriever() {
+ protected FieldDescriptor loadDescriptor() {
+ try {
+ Class clazz =
+ singularType.getClassLoader().loadClass(descriptorOuterClass);
+ FileDescriptor file =
+ (FileDescriptor) clazz.getField("descriptor").get(null);
+ return file.findExtensionByName(extensionName);
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Cannot load descriptors: " + descriptorOuterClass +
+ " is not a valid descriptor class name", e);
+ }
+ }
+ },
+ singularType,
+ defaultInstance,
+ Extension.ExtensionType.MUTABLE);
}
/**
@@ -1179,8 +1489,9 @@ public abstract class GeneratedMessage extends AbstractMessage
* these static singletons as parameters to the extension accessors defined
* in {@link ExtendableMessage} and {@link ExtendableBuilder}.
*/
- public static final class GeneratedExtension<
- ContainingType extends Message, Type> {
+ public static class GeneratedExtension<
+ ContainingType extends Message, Type> extends
+ Extension<ContainingType, Type> {
// TODO(kenton): Find ways to avoid using Java reflection within this
// class. Also try to avoid suppressing unchecked warnings.
@@ -1196,9 +1507,10 @@ public abstract class GeneratedMessage extends AbstractMessage
// In the case of non-nested extensions, we initialize the
// ExtensionDescriptorRetriever to null and rely on the outer class's static
// initializer to call internalInit() after the descriptor has been parsed.
- private GeneratedExtension(ExtensionDescriptorRetriever descriptorRetriever,
- Class singularType,
- Message messageDefaultInstance) {
+ GeneratedExtension(ExtensionDescriptorRetriever descriptorRetriever,
+ Class singularType,
+ Message messageDefaultInstance,
+ ExtensionType extensionType) {
if (Message.class.isAssignableFrom(singularType) &&
!singularType.isInstance(messageDefaultInstance)) {
throw new IllegalArgumentException(
@@ -1217,6 +1529,7 @@ public abstract class GeneratedMessage extends AbstractMessage
this.enumValueOf = null;
this.enumGetValueDescriptor = null;
}
+ this.extensionType = extensionType;
}
/** For use by generated code only. */
@@ -1237,6 +1550,7 @@ public abstract class GeneratedMessage extends AbstractMessage
private final Message messageDefaultInstance;
private final Method enumValueOf;
private final Method enumGetValueDescriptor;
+ private final ExtensionType extensionType;
public FieldDescriptor getDescriptor() {
if (descriptorRetriever == null) {
@@ -1254,14 +1568,19 @@ public abstract class GeneratedMessage extends AbstractMessage
return messageDefaultInstance;
}
+ protected ExtensionType getExtensionType() {
+ return extensionType;
+ }
+
/**
* Convert from the type used by the reflection accessors to the type used
* by native accessors. E.g., for enums, the reflection accessors use
* EnumValueDescriptors but the native accessors use the generated enum
* type.
*/
+ // @Override
@SuppressWarnings("unchecked")
- private Object fromReflectionType(final Object value) {
+ protected Object fromReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
if (descriptor.isRepeated()) {
if (descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE ||
@@ -1284,21 +1603,16 @@ public abstract class GeneratedMessage extends AbstractMessage
* Like {@link #fromReflectionType(Object)}, but if the type is a repeated
* type, this converts a single element.
*/
- private Object singularFromReflectionType(final Object value) {
+ // @Override
+ protected Object singularFromReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
switch (descriptor.getJavaType()) {
case MESSAGE:
if (singularType.isInstance(value)) {
return value;
} else {
- // It seems the copy of the embedded message stored inside the
- // extended message is not of the exact type the user was
- // expecting. This can happen if a user defines a
- // GeneratedExtension manually and gives it a different type.
- // This should not happen in normal use. But, to be nice, we'll
- // copy the message to whatever type the caller was expecting.
return messageDefaultInstance.newBuilderForType()
- .mergeFrom((Message) value).build();
+ .mergeFrom((Message) value).build();
}
case ENUM:
return invokeOrDie(enumValueOf, null, (EnumValueDescriptor) value);
@@ -1313,8 +1627,9 @@ public abstract class GeneratedMessage extends AbstractMessage
* EnumValueDescriptors but the native accessors use the generated enum
* type.
*/
+ // @Override
@SuppressWarnings("unchecked")
- private Object toReflectionType(final Object value) {
+ protected Object toReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
if (descriptor.isRepeated()) {
if (descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
@@ -1336,7 +1651,8 @@ public abstract class GeneratedMessage extends AbstractMessage
* Like {@link #toReflectionType(Object)}, but if the type is a repeated
* type, this converts a single element.
*/
- private Object singularToReflectionType(final Object value) {
+ // @Override
+ protected Object singularToReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
switch (descriptor.getJavaType()) {
case ENUM:
@@ -1345,6 +1661,34 @@ public abstract class GeneratedMessage extends AbstractMessage
return value;
}
}
+
+ // @Override
+ public int getNumber() {
+ return getDescriptor().getNumber();
+ }
+
+ // @Override
+ public WireFormat.FieldType getLiteType() {
+ return getDescriptor().getLiteType();
+ }
+
+ // @Override
+ public boolean isRepeated() {
+ return getDescriptor().isRepeated();
+ }
+
+ // @Override
+ @SuppressWarnings("unchecked")
+ public Type getDefaultValue() {
+ if (isRepeated()) {
+ return (Type) Collections.emptyList();
+ }
+ if (getDescriptor().getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ return (Type) messageDefaultInstance;
+ }
+ return (Type) singularFromReflectionType(
+ getDescriptor().getDefaultValue());
+ }
}
// =================================================================
@@ -1385,6 +1729,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
* with access to the fields of a message object using Java reflection.
*/
@@ -1405,39 +1768,104 @@ public abstract class GeneratedMessage extends AbstractMessage
final String[] camelCaseNames,
final Class<? extends GeneratedMessage> messageClass,
final Class<? extends Builder> builderClass) {
+ this(descriptor, camelCaseNames);
+ ensureFieldAccessorsInitialized(messageClass, builderClass);
+ }
+
+ /**
+ * Construct a FieldAccessorTable for a particular message class without
+ * initializing FieldAccessors.
+ */
+ public FieldAccessorTable(
+ final Descriptor descriptor,
+ final String[] camelCaseNames) {
this.descriptor = descriptor;
+ this.camelCaseNames = camelCaseNames;
fields = new FieldAccessor[descriptor.getFields().size()];
+ oneofs = new OneofAccessor[descriptor.getOneofs().size()];
+ initialized = false;
+ }
- for (int i = 0; i < fields.length; i++) {
- final FieldDescriptor field = descriptor.getFields().get(i);
- if (field.isRepeated()) {
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
- 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);
- } else {
- fields[i] = new RepeatedFieldAccessor(
- field, camelCaseNames[i], messageClass, builderClass);
+ private boolean isMapFieldEnabled(FieldDescriptor field) {
+ boolean result = true;
+ return result;
+ }
+
+ /**
+ * Ensures the field accessors are initialized. This method is thread-safe.
+ *
+ * @param messageClass The message type.
+ * @param builderClass The builder type.
+ * @return this
+ */
+ public FieldAccessorTable ensureFieldAccessorsInitialized(
+ Class<? extends GeneratedMessage> messageClass,
+ Class<? extends Builder> builderClass) {
+ if (initialized) { return this; }
+ synchronized (this) {
+ if (initialized) { return this; }
+ int fieldsSize = fields.length;
+ for (int i = 0; i < fieldsSize; i++) {
+ FieldDescriptor field = descriptor.getFields().get(i);
+ String containingOneofCamelCaseName = null;
+ if (field.getContainingOneof() != null) {
+ containingOneofCamelCaseName =
+ camelCaseNames[fieldsSize + field.getContainingOneof().getIndex()];
}
- } else {
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
- fields[i] = new SingularMessageFieldAccessor(
- field, camelCaseNames[i], messageClass, builderClass);
- } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
- fields[i] = new SingularEnumFieldAccessor(
- field, camelCaseNames[i], messageClass, builderClass);
+ if (field.isRepeated()) {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ 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);
+ } else {
+ fields[i] = new RepeatedFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ }
} else {
- fields[i] = new SingularFieldAccessor(
- field, camelCaseNames[i], messageClass, builderClass);
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ fields[i] = new SingularMessageFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass,
+ containingOneofCamelCaseName);
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+ fields[i] = new SingularEnumFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass,
+ containingOneofCamelCaseName);
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+ fields[i] = new SingularStringFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass,
+ containingOneofCamelCaseName);
+ } else {
+ fields[i] = new SingularFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass,
+ containingOneofCamelCaseName);
+ }
}
}
+
+ int oneofsSize = oneofs.length;
+ for (int i = 0; i < oneofsSize; i++) {
+ oneofs[i] = new OneofAccessor(
+ descriptor, camelCaseNames[i + fieldsSize],
+ messageClass, builderClass);
+ }
+ initialized = true;
+ camelCaseNames = null;
+ return this;
}
}
private final Descriptor descriptor;
private final FieldAccessor[] fields;
+ private String[] camelCaseNames;
+ private final OneofAccessor[] oneofs;
+ private volatile boolean initialized;
/** Get the FieldAccessor for a particular field. */
private FieldAccessor getField(final FieldDescriptor field) {
@@ -1453,6 +1881,15 @@ public abstract class GeneratedMessage extends AbstractMessage
return fields[field.getIndex()];
}
+ /** Get the OneofAccessor for a particular oneof. */
+ private OneofAccessor getOneof(final OneofDescriptor oneof) {
+ if (oneof.getContainingType() != descriptor) {
+ throw new IllegalArgumentException(
+ "OneofDescriptor does not match message type.");
+ }
+ return oneofs[oneof.getIndex()];
+ }
+
/**
* Abstract interface that provides access to a single field. This is
* implemented differently depending on the field type and cardinality.
@@ -1460,9 +1897,13 @@ public abstract class GeneratedMessage extends AbstractMessage
private interface FieldAccessor {
Object get(GeneratedMessage message);
Object get(GeneratedMessage.Builder builder);
+ Object getRaw(GeneratedMessage message);
+ Object getRaw(GeneratedMessage.Builder builder);
void set(Builder builder, Object value);
Object getRepeated(GeneratedMessage message, int index);
Object getRepeated(GeneratedMessage.Builder builder, int index);
+ Object getRepeatedRaw(GeneratedMessage message, int index);
+ Object getRepeatedRaw(GeneratedMessage.Builder builder, int index);
void setRepeated(Builder builder,
int index, Object value);
void addRepeated(Builder builder, Object value);
@@ -1472,6 +1913,67 @@ public abstract class GeneratedMessage extends AbstractMessage
int getRepeatedCount(GeneratedMessage.Builder builder);
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. */
+ private static class OneofAccessor {
+ OneofAccessor(
+ final Descriptor descriptor, final String camelCaseName,
+ final Class<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> builderClass) {
+ this.descriptor = descriptor;
+ caseMethod =
+ getMethodOrDie(messageClass, "get" + camelCaseName + "Case");
+ caseMethodBuilder =
+ getMethodOrDie(builderClass, "get" + camelCaseName + "Case");
+ clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+ }
+
+ private final Descriptor descriptor;
+ private final Method caseMethod;
+ private final Method caseMethodBuilder;
+ private final Method clearMethod;
+
+ public boolean has(final GeneratedMessage message) {
+ if (((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber() == 0) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean has(GeneratedMessage.Builder builder) {
+ if (((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber() == 0) {
+ return false;
+ }
+ return true;
+ }
+
+ public FieldDescriptor get(final GeneratedMessage message) {
+ int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+ if (fieldNumber > 0) {
+ return descriptor.findFieldByNumber(fieldNumber);
+ }
+ return null;
+ }
+
+ public FieldDescriptor get(GeneratedMessage.Builder builder) {
+ int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+ if (fieldNumber > 0) {
+ return descriptor.findFieldByNumber(fieldNumber);
+ }
+ return null;
+ }
+
+ public void clear(final Builder builder) {
+ invokeOrDie(clearMethod, builder);
+ }
+ }
+
+ private static boolean supportFieldPresence(FileDescriptor file) {
+ return file.getSyntax() == FileDescriptor.Syntax.PROTO2;
}
// ---------------------------------------------------------------
@@ -1480,16 +1982,25 @@ public abstract class GeneratedMessage extends AbstractMessage
SingularFieldAccessor(
final FieldDescriptor descriptor, final String camelCaseName,
final Class<? extends GeneratedMessage> messageClass,
- final Class<? extends Builder> builderClass) {
+ final Class<? extends Builder> builderClass,
+ final String containingOneofCamelCaseName) {
+ field = descriptor;
+ isOneofField = descriptor.getContainingOneof() != null;
+ hasHasMethod = supportFieldPresence(descriptor.getFile())
+ || (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName);
type = getMethod.getReturnType();
setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
hasMethod =
- getMethodOrDie(messageClass, "has" + camelCaseName);
+ hasHasMethod ? getMethodOrDie(messageClass, "has" + camelCaseName) : null;
hasMethodBuilder =
- getMethodOrDie(builderClass, "has" + camelCaseName);
+ hasHasMethod ? getMethodOrDie(builderClass, "has" + camelCaseName) : null;
clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+ caseMethod = isOneofField ? getMethodOrDie(
+ messageClass, "get" + containingOneofCamelCaseName + "Case") : null;
+ caseMethodBuilder = isOneofField ? getMethodOrDie(
+ builderClass, "get" + containingOneofCamelCaseName + "Case") : null;
}
// Note: We use Java reflection to call public methods rather than
@@ -1502,6 +2013,19 @@ public abstract class GeneratedMessage extends AbstractMessage
protected final Method hasMethod;
protected final Method hasMethodBuilder;
protected final Method clearMethod;
+ protected final Method caseMethod;
+ protected final Method caseMethodBuilder;
+ protected final FieldDescriptor field;
+ protected final boolean isOneofField;
+ protected final boolean hasHasMethod;
+
+ private int getOneofFieldNumber(final GeneratedMessage message) {
+ return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+ }
+
+ private int getOneofFieldNumber(final GeneratedMessage.Builder builder) {
+ return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+ }
public Object get(final GeneratedMessage message) {
return invokeOrDie(getMethod, message);
@@ -1509,6 +2033,12 @@ public abstract class GeneratedMessage extends AbstractMessage
public Object get(GeneratedMessage.Builder builder) {
return invokeOrDie(getMethodBuilder, builder);
}
+ public Object getRaw(final GeneratedMessage message) {
+ return get(message);
+ }
+ public Object getRaw(GeneratedMessage.Builder builder) {
+ return get(builder);
+ }
public void set(final Builder builder, final Object value) {
invokeOrDie(setMethod, builder, value);
}
@@ -1517,12 +2047,22 @@ public abstract class GeneratedMessage extends AbstractMessage
throw new UnsupportedOperationException(
"getRepeatedField() called on a singular field.");
}
+ public Object getRepeatedRaw(final GeneratedMessage message,
+ final int index) {
+ throw new UnsupportedOperationException(
+ "getRepeatedFieldRaw() called on a singular field.");
+ }
public Object getRepeated(GeneratedMessage.Builder builder, int index) {
throw new UnsupportedOperationException(
"getRepeatedField() called on a singular field.");
}
- public void setRepeated(final Builder builder,
- final int index, final Object value) {
+ public Object getRepeatedRaw(GeneratedMessage.Builder builder,
+ int index) {
+ throw new UnsupportedOperationException(
+ "getRepeatedFieldRaw() called on a singular field.");
+ }
+ public void setRepeated(final Builder builder, final int index,
+ final Object value) {
throw new UnsupportedOperationException(
"setRepeatedField() called on a singular field.");
}
@@ -1531,9 +2071,21 @@ public abstract class GeneratedMessage extends AbstractMessage
"addRepeatedField() called on a singular field.");
}
public boolean has(final GeneratedMessage message) {
+ if (!hasHasMethod) {
+ if (isOneofField) {
+ return getOneofFieldNumber(message) == field.getNumber();
+ }
+ return !get(message).equals(field.getDefaultValue());
+ }
return (Boolean) invokeOrDie(hasMethod, message);
}
public boolean has(GeneratedMessage.Builder builder) {
+ if (!hasHasMethod) {
+ if (isOneofField) {
+ return getOneofFieldNumber(builder) == field.getNumber();
+ }
+ return !get(builder).equals(field.getDefaultValue());
+ }
return (Boolean) invokeOrDie(hasMethodBuilder, builder);
}
public int getRepeatedCount(final GeneratedMessage message) {
@@ -1551,6 +2103,15 @@ public abstract class GeneratedMessage extends AbstractMessage
throw new UnsupportedOperationException(
"newBuilderForField() called on a non-Message type.");
}
+ public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
+ 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 {
@@ -1573,8 +2134,6 @@ public abstract class GeneratedMessage extends AbstractMessage
"get" + camelCaseName + "List");
getMethodBuilder = getMethodOrDie(builderClass,
"get" + camelCaseName + "List");
-
-
getRepeatedMethod =
getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
getRepeatedMethodBuilder =
@@ -1599,6 +2158,12 @@ public abstract class GeneratedMessage extends AbstractMessage
public Object get(GeneratedMessage.Builder builder) {
return invokeOrDie(getMethodBuilder, builder);
}
+ public Object getRaw(final GeneratedMessage message) {
+ return get(message);
+ }
+ public Object getRaw(GeneratedMessage.Builder builder) {
+ return get(builder);
+ }
public void set(final Builder builder, final Object value) {
// Add all the elements individually. This serves two purposes:
// 1) Verifies that each element has the correct type.
@@ -1616,6 +2181,13 @@ public abstract class GeneratedMessage extends AbstractMessage
public Object getRepeated(GeneratedMessage.Builder builder, int index) {
return invokeOrDie(getRepeatedMethodBuilder, builder, index);
}
+ public Object getRepeatedRaw(GeneratedMessage message, int index) {
+ return getRepeated(message, index);
+ }
+ public Object getRepeatedRaw(GeneratedMessage.Builder builder,
+ int index) {
+ return getRepeated(builder, index);
+ }
public void setRepeated(final Builder builder,
final int index, final Object value) {
invokeOrDie(setRepeatedMethod, builder, index, value);
@@ -1625,11 +2197,11 @@ public abstract class GeneratedMessage extends AbstractMessage
}
public boolean has(final GeneratedMessage message) {
throw new UnsupportedOperationException(
- "hasField() called on a singular field.");
+ "hasField() called on a repeated field.");
}
public boolean has(GeneratedMessage.Builder builder) {
throw new UnsupportedOperationException(
- "hasField() called on a singular field.");
+ "hasField() called on a repeated field.");
}
public int getRepeatedCount(final GeneratedMessage message) {
return (Integer) invokeOrDie(getCountMethod, message);
@@ -1644,6 +2216,139 @@ public abstract class GeneratedMessage extends AbstractMessage
throw new UnsupportedOperationException(
"newBuilderForField() called on a non-Message type.");
}
+ public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
+ 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<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> 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());
+ }
+
+ private MapField<?, ?> getMutableMapField(
+ GeneratedMessage.Builder builder) {
+ return (MapField<?, ?>) builder.internalGetMutableMapField(
+ 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 Object getRaw(GeneratedMessage message) {
+ return get(message);
+ }
+
+ public Object getRaw(GeneratedMessage.Builder builder) {
+ return get(builder);
+ }
+
+ 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 Object getRepeatedRaw(GeneratedMessage message, int index) {
+ return getRepeated(message, index);
+ }
+
+ public Object getRepeatedRaw(Builder builder, int index) {
+ return getRepeated(builder, index);
+ }
+
+ public void setRepeated(Builder builder, int index, Object value) {
+ getMutableMapField(builder).getMutableList().set(index, (Message) value);
+ }
+
+ public void addRepeated(Builder builder, Object value) {
+ getMutableMapField(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) {
+ getMutableMapField(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.");
+ }
}
// ---------------------------------------------------------------
@@ -1653,30 +2358,63 @@ public abstract class GeneratedMessage extends AbstractMessage
SingularEnumFieldAccessor(
final FieldDescriptor descriptor, final String camelCaseName,
final Class<? extends GeneratedMessage> messageClass,
- final Class<? extends Builder> builderClass) {
- super(descriptor, camelCaseName, messageClass, builderClass);
+ final Class<? extends Builder> 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));
}
}
@@ -1689,21 +2427,43 @@ public abstract class GeneratedMessage extends AbstractMessage
final Class<? extends Builder> 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);
}
@@ -1712,8 +2472,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);
}
@@ -1721,41 +2482,118 @@ 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));
}
}
// ---------------------------------------------------------------
+ /**
+ * Field accessor for string fields.
+ *
+ * <p>This class makes getFooBytes() and setFooBytes() available for
+ * reflection API so that reflection based serialize/parse functions can
+ * access the raw bytes of the field to preserve non-UTF8 bytes in the
+ * string.
+ *
+ * <p>This ensures the serialize/parse round-trip safety, which is important
+ * for servers which forward messages.
+ */
+ private static final class SingularStringFieldAccessor
+ extends SingularFieldAccessor {
+ SingularStringFieldAccessor(
+ final FieldDescriptor descriptor, final String camelCaseName,
+ final Class<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> builderClass,
+ final String containingOneofCamelCaseName) {
+ super(descriptor, camelCaseName, messageClass, builderClass,
+ containingOneofCamelCaseName);
+ getBytesMethod = getMethodOrDie(messageClass,
+ "get" + camelCaseName + "Bytes");
+ getBytesMethodBuilder = getMethodOrDie(builderClass,
+ "get" + camelCaseName + "Bytes");
+ setBytesMethodBuilder = getMethodOrDie(builderClass,
+ "set" + camelCaseName + "Bytes", ByteString.class);
+ }
+
+ private final Method getBytesMethod;
+ private final Method getBytesMethodBuilder;
+ private final Method setBytesMethodBuilder;
+
+ @Override
+ public Object getRaw(final GeneratedMessage message) {
+ return invokeOrDie(getBytesMethod, message);
+ }
+
+ @Override
+ public Object getRaw(GeneratedMessage.Builder builder) {
+ return invokeOrDie(getBytesMethodBuilder, builder);
+ }
+
+ @Override
+ public void set(GeneratedMessage.Builder builder, Object value) {
+ if (value instanceof ByteString) {
+ invokeOrDie(setBytesMethodBuilder, builder, value);
+ } else {
+ super.set(builder, value);
+ }
+ }
+ }
+
+ // ---------------------------------------------------------------
+
private static final class SingularMessageFieldAccessor
extends SingularFieldAccessor {
SingularMessageFieldAccessor(
final FieldDescriptor descriptor, final String camelCaseName,
final Class<? extends GeneratedMessage> messageClass,
- final Class<? extends Builder> builderClass) {
- super(descriptor, camelCaseName, messageClass, builderClass);
+ final Class<? extends Builder> builderClass,
+ final String containingOneofCamelCaseName) {
+ super(descriptor, camelCaseName, messageClass, builderClass,
+ containingOneofCamelCaseName);
newBuilderMethod = getMethodOrDie(type, "newBuilder");
+ getBuilderMethodBuilder =
+ getMethodOrDie(builderClass, "get" + camelCaseName + "Builder");
}
private final Method newBuilderMethod;
+ private final Method getBuilderMethodBuilder;
private Object coerceType(final Object value) {
if (type.isInstance(value)) {
@@ -1766,7 +2604,7 @@ public abstract class GeneratedMessage extends AbstractMessage
// DynamicMessage -- we should accept it. In this case we can make
// a copy of the message.
return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
- .mergeFrom((Message) value).build();
+ .mergeFrom((Message) value).buildPartial();
}
}
@@ -1778,6 +2616,10 @@ public abstract class GeneratedMessage extends AbstractMessage
public Message.Builder newBuilder() {
return (Message.Builder) invokeOrDie(newBuilderMethod, null);
}
+ @Override
+ public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
+ return (Message.Builder) invokeOrDie(getBuilderMethodBuilder, builder);
+ }
}
private static final class RepeatedMessageFieldAccessor
@@ -1789,9 +2631,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)) {
@@ -1819,16 +2664,36 @@ 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);
+ }
}
}
/**
* Replaces this object in the output stream with a serialized form.
* Part of Java's serialization magic. Generated sub-classes must override
- * this method by calling <code>return super.writeReplace();</code>
+ * this method by calling {@code return super.writeReplace();}
* @return a SerializedForm of this message
*/
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 <MessageType extends ExtendableMessage<MessageType>, T>
+ Extension<MessageType, T> checkNotLite(
+ ExtensionLite<MessageType, T> extension) {
+ if (extension.isLite()) {
+ throw new IllegalArgumentException("Expected non-lite extension.");
+ }
+
+ return (Extension<MessageType, T>) extension;
+ }
}
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index 1813e9b3..6839c9dd 100644
--- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,69 +30,192 @@
package com.google.protobuf;
+import com.google.protobuf.WireFormat.FieldType;
+
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Lite version of {@link GeneratedMessage}.
*
* @author kenton@google.com Kenton Varda
*/
-public abstract class GeneratedMessageLite extends AbstractMessageLite
- implements Serializable {
+public abstract class GeneratedMessageLite<
+ MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+ BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
+ extends AbstractMessageLite
+ implements Serializable {
+
+ /**
+ * Holds all the {@link PrototypeHolder}s for loaded classes.
+ */
+ // TODO(dweis): Consider different concurrency values.
+ // TODO(dweis): This will prevent garbage collection of the class loader.
+ // Ideally we'd use something like ClassValue but that's Java 7 only.
+ private static final Map<Class<?>, PrototypeHolder<?, ?>> PROTOTYPE_MAP =
+ new ConcurrentHashMap<Class<?>, PrototypeHolder<?, ?>>();
+
+ // For use by generated code only.
+ protected static <
+ MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+ BuilderType extends GeneratedMessageLite.Builder<
+ MessageType, BuilderType>> void onLoad(Class<MessageType> clazz,
+ PrototypeHolder<MessageType, BuilderType> protoTypeHolder) {
+ PROTOTYPE_MAP.put(clazz, protoTypeHolder);
+ }
+
private static final long serialVersionUID = 1L;
- protected GeneratedMessageLite() {
+ /** For use by generated code only. */
+ protected UnknownFieldSetLite unknownFields;
+
+ @SuppressWarnings("unchecked") // Guaranteed by runtime.
+ public final Parser<MessageType> getParserForType() {
+ return (Parser<MessageType>) PROTOTYPE_MAP
+ .get(getClass()).getParserForType();
+ }
+
+ @SuppressWarnings("unchecked") // Guaranteed by runtime.
+ public final MessageType getDefaultInstanceForType() {
+ return (MessageType) PROTOTYPE_MAP
+ .get(getClass()).getDefaultInstanceForType();
+ }
+
+ @SuppressWarnings("unchecked") // Guaranteed by runtime.
+ public final BuilderType newBuilderForType() {
+ return (BuilderType) PROTOTYPE_MAP
+ .get(getClass()).newBuilderForType();
+ }
+
+ /**
+ * 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 static boolean parseUnknownField(
+ CodedInputStream input,
+ UnknownFieldSetLite.Builder unknownFields,
+ ExtensionRegistryLite extensionRegistry,
+ int tag) throws IOException {
+ return unknownFields.mergeFieldFrom(tag, input);
}
- protected GeneratedMessageLite(Builder builder) {
+ // The default behavior. If a message has required fields in its subtree, the
+ // generated code will override.
+ public boolean isInitialized() {
+ return true;
}
@SuppressWarnings("unchecked")
- public abstract static class Builder<MessageType extends GeneratedMessageLite,
- BuilderType extends Builder>
- extends AbstractMessageLite.Builder<BuilderType> {
- protected Builder() {}
+ public abstract static class Builder<
+ MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+ BuilderType extends Builder<MessageType, BuilderType>>
+ extends AbstractMessageLite.Builder<BuilderType> {
+
+ private final MessageType defaultInstance;
+
+ /** For use by generated code only. */
+ protected UnknownFieldSetLite unknownFields =
+ UnknownFieldSetLite.getDefaultInstance();
+
+ protected Builder(MessageType defaultInstance) {
+ this.defaultInstance = defaultInstance;
+ }
+
+ // The default behavior. If a message has required fields in its subtree,
+ // the generated code will override.
+ public boolean isInitialized() {
+ return true;
+ }
//@Override (Java 1.6 override semantics, but we must support 1.5)
public BuilderType clear() {
+ 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 BuilderType mergeFrom(MessageType message);
+ public abstract MessageType buildPartial();
- // Defined here for return type covariance.
- public abstract MessageType getDefaultInstanceForType();
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public final MessageType build() {
+ MessageType result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ /** All subclasses implement this. */
+ public abstract BuilderType mergeFrom(MessageType message);
+
+ public MessageType getDefaultInstanceForType() {
+ return defaultInstance;
+ }
/**
* Called by subclasses to parse an unknown field.
* @return {@code true} unless the tag is an end-group tag.
*/
protected boolean parseUnknownField(
- final CodedInputStream input,
- final ExtensionRegistryLite extensionRegistry,
- final int tag) throws IOException {
- return input.skipField(tag);
+ CodedInputStream input,
+ UnknownFieldSetLite.Builder unknownFields,
+ ExtensionRegistryLite extensionRegistry,
+ int tag) throws IOException {
+ return unknownFields.mergeFieldFrom(tag, input);
+ }
+
+ /**
+ * Merge some unknown fields into the {@link UnknownFieldSetLite} for this
+ * message.
+ *
+ * <p>For use by generated code only.
+ */
+ protected final BuilderType mergeUnknownFields(
+ final UnknownFieldSetLite unknownFields) {
+ this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields);
+ return (BuilderType) this;
+ }
+
+ 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;
}
}
+
// =================================================================
// Extensions-related stuff
@@ -100,22 +223,24 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
* Lite equivalent of {@link com.google.protobuf.GeneratedMessage.ExtendableMessageOrBuilder}.
*/
public interface ExtendableMessageOrBuilder<
- MessageType extends ExtendableMessage> extends MessageLiteOrBuilder {
+ MessageType extends ExtendableMessage<MessageType, BuilderType>,
+ BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+ extends MessageLiteOrBuilder {
/** Check if a singular extension is present. */
<Type> boolean hasExtension(
- GeneratedExtension<MessageType, Type> extension);
+ ExtensionLite<MessageType, Type> extension);
/** Get the number of elements in a repeated extension. */
<Type> int getExtensionCount(
- GeneratedExtension<MessageType, List<Type>> extension);
+ ExtensionLite<MessageType, List<Type>> extension);
/** Get the value of an extension. */
- <Type> Type getExtension(GeneratedExtension<MessageType, Type> extension);
+ <Type> Type getExtension(ExtensionLite<MessageType, Type> extension);
/** Get one element of a repeated extension. */
<Type> Type getExtension(
- GeneratedExtension<MessageType, List<Type>> extension,
+ ExtensionLite<MessageType, List<Type>> extension,
int index);
}
@@ -123,18 +248,28 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
* Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
*/
public abstract static class ExtendableMessage<
- MessageType extends ExtendableMessage<MessageType>>
- extends GeneratedMessageLite
- implements ExtendableMessageOrBuilder<MessageType> {
+ MessageType extends ExtendableMessage<MessageType, BuilderType>,
+ BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+ extends GeneratedMessageLite<MessageType, BuilderType>
+ implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
+
+ /**
+ * Represents the set of extensions on this message. For use by generated
+ * code only.
+ */
+ protected FieldSet<ExtensionDescriptor> extensions = FieldSet.newFieldSet();
- private final FieldSet<ExtensionDescriptor> extensions;
+ // -1 => not memoized, 0 => false, 1 => true.
+ private byte memoizedIsInitialized = -1;
- protected ExtendableMessage() {
- this.extensions = FieldSet.newFieldSet();
- }
+ // The default behavior. If a message has required fields in its subtree,
+ // the generated code will override.
+ public boolean isInitialized() {
+ if (memoizedIsInitialized == -1) {
+ memoizedIsInitialized = (byte) (extensions.isInitialized() ? 1 : 0);
+ }
- protected ExtendableMessage(ExtendableBuilder<MessageType, ?> builder) {
- this.extensions = builder.buildExtensions();
+ return memoizedIsInitialized == 1;
}
private void verifyExtensionContainingType(
@@ -151,30 +286,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 <Type> boolean hasExtension(
- final GeneratedExtension<MessageType, Type> extension) {
- verifyExtensionContainingType(extension);
- return extensions.hasField(extension.descriptor);
+ final ExtensionLite<MessageType, Type> extension) {
+ GeneratedExtension<MessageType, Type> 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 <Type> int getExtensionCount(
- final GeneratedExtension<MessageType, List<Type>> extension) {
- verifyExtensionContainingType(extension);
- return extensions.getRepeatedFieldCount(extension.descriptor);
+ final ExtensionLite<MessageType, List<Type>> extension) {
+ GeneratedExtension<MessageType, List<Type>> 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> Type getExtension(
- final GeneratedExtension<MessageType, Type> extension) {
- verifyExtensionContainingType(extension);
- final Object value = extensions.getField(extension.descriptor);
+ final ExtensionLite<MessageType, Type> extension) {
+ GeneratedExtension<MessageType, Type> extensionLite =
+ checkIsLite(extension);
+
+ verifyExtensionContainingType(extensionLite);
+ final Object value = extensions.getField(extensionLite.descriptor);
if (value == null) {
- return extension.defaultValue;
+ return extensionLite.defaultValue;
} else {
- return (Type) value;
+ return (Type) extensionLite.fromFieldSetType(value);
}
}
@@ -182,10 +326,14 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
//@Override (Java 1.6 override semantics, but we must support 1.5)
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
- final GeneratedExtension<MessageType, List<Type>> extension,
+ final ExtensionLite<MessageType, List<Type>> extension,
final int index) {
- verifyExtensionContainingType(extension);
- return (Type) extensions.getRepeatedField(extension.descriptor, index);
+ GeneratedExtension<MessageType, List<Type>> extensionLite =
+ checkIsLite(extension);
+
+ verifyExtensionContainingType(extensionLite);
+ return (Type) extensionLite.singularFromFieldSetType(
+ extensions.getRepeatedField(extensionLite.descriptor, index));
}
/** Called by subclasses to check if all extensions are initialized. */
@@ -193,6 +341,15 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
return extensions.isInitialized();
}
+
+ /**
+ * Used by parsing constructors in generated classes.
+ */
+ protected static void makeExtensionsImmutable(
+ FieldSet<ExtensionDescriptor> extensions) {
+ extensions.makeImmutable();
+ }
+
/**
* Used by subclasses to serialize extensions. Extension ranges may be
* interleaved with field numbers, but we must write them in canonical
@@ -257,15 +414,28 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
*/
@SuppressWarnings("unchecked")
public abstract static class ExtendableBuilder<
- MessageType extends ExtendableMessage<MessageType>,
+ MessageType extends ExtendableMessage<MessageType, BuilderType>,
BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
extends Builder<MessageType, BuilderType>
- implements ExtendableMessageOrBuilder<MessageType> {
- protected ExtendableBuilder() {}
+ implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
+ protected ExtendableBuilder(MessageType defaultInstance) {
+ super(defaultInstance);
+ }
private FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
private boolean extensionsIsMutable;
+ // The default behavior. If a message has required fields in its subtree,
+ // the generated code will override.
+ public boolean isInitialized() {
+ return extensions.isInitialized();
+ }
+
+ // For immutable message conversion.
+ void internalSetExtensionSet(FieldSet<ExtensionDescriptor> extensions) {
+ this.extensions = extensions;
+ }
+
@Override
public BuilderType clear() {
extensions.clear();
@@ -283,8 +453,10 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
/**
* Called by the build code path to create a copy of the extensions for
* building the message.
+ * <p>
+ * For use by generated code only.
*/
- private FieldSet<ExtensionDescriptor> buildExtensions() {
+ protected final FieldSet<ExtensionDescriptor> buildExtensions() {
extensions.makeImmutable();
extensionsIsMutable = false;
return extensions;
@@ -304,30 +476,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 <Type> boolean hasExtension(
- final GeneratedExtension<MessageType, Type> extension) {
- verifyExtensionContainingType(extension);
- return extensions.hasField(extension.descriptor);
+ final ExtensionLite<MessageType, Type> extension) {
+ GeneratedExtension<MessageType, Type> 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 <Type> int getExtensionCount(
- final GeneratedExtension<MessageType, List<Type>> extension) {
- verifyExtensionContainingType(extension);
- return extensions.getRepeatedFieldCount(extension.descriptor);
+ final ExtensionLite<MessageType, List<Type>> extension) {
+ GeneratedExtension<MessageType, List<Type>> 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> Type getExtension(
- final GeneratedExtension<MessageType, Type> extension) {
- verifyExtensionContainingType(extension);
- final Object value = extensions.getField(extension.descriptor);
+ final ExtensionLite<MessageType, Type> extension) {
+ GeneratedExtension<MessageType, Type> extensionLite =
+ checkIsLite(extension);
+
+ verifyExtensionContainingType(extensionLite);
+ final Object value = extensions.getField(extensionLite.descriptor);
if (value == null) {
- return extension.defaultValue;
+ return extensionLite.defaultValue;
} else {
- return (Type) value;
+ return (Type) extensionLite.fromFieldSetType(value);
}
}
@@ -335,10 +516,14 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
@SuppressWarnings("unchecked")
//@Override (Java 1.6 override semantics, but we must support 1.5)
public final <Type> Type getExtension(
- final GeneratedExtension<MessageType, List<Type>> extension,
+ final ExtensionLite<MessageType, List<Type>> extension,
final int index) {
- verifyExtensionContainingType(extension);
- return (Type) extensions.getRepeatedField(extension.descriptor, index);
+ GeneratedExtension<MessageType, List<Type>> 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
@@ -346,46 +531,59 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
// of this dummy clone() implementation makes it go away.
@Override
public BuilderType clone() {
- throw new UnsupportedOperationException(
- "This is supposed to be overridden by subclasses.");
+ return super.clone();
}
-
+
/** Set the value of an extension. */
public final <Type> BuilderType setExtension(
- final GeneratedExtension<MessageType, Type> extension,
+ final ExtensionLite<MessageType, Type> extension,
final Type value) {
- verifyExtensionContainingType(extension);
+ GeneratedExtension<MessageType, Type> extensionLite =
+ checkIsLite(extension);
+
+ verifyExtensionContainingType(extensionLite);
ensureExtensionsIsMutable();
- extensions.setField(extension.descriptor, value);
+ extensions.setField(extensionLite.descriptor,
+ extensionLite.toFieldSetType(value));
return (BuilderType) this;
}
/** Set the value of one element of a repeated extension. */
public final <Type> BuilderType setExtension(
- final GeneratedExtension<MessageType, List<Type>> extension,
+ final ExtensionLite<MessageType, List<Type>> extension,
final int index, final Type value) {
- verifyExtensionContainingType(extension);
+ GeneratedExtension<MessageType, List<Type>> extensionLite =
+ checkIsLite(extension);
+
+ verifyExtensionContainingType(extensionLite);
ensureExtensionsIsMutable();
- extensions.setRepeatedField(extension.descriptor, index, value);
+ extensions.setRepeatedField(extensionLite.descriptor, index,
+ extensionLite.singularToFieldSetType(value));
return (BuilderType) this;
}
/** Append a value to a repeated extension. */
public final <Type> BuilderType addExtension(
- final GeneratedExtension<MessageType, List<Type>> extension,
+ final ExtensionLite<MessageType, List<Type>> extension,
final Type value) {
- verifyExtensionContainingType(extension);
+ GeneratedExtension<MessageType, List<Type>> extensionLite =
+ checkIsLite(extension);
+
+ verifyExtensionContainingType(extensionLite);
ensureExtensionsIsMutable();
- extensions.addRepeatedField(extension.descriptor, value);
+ extensions.addRepeatedField(extensionLite.descriptor,
+ extensionLite.singularToFieldSetType(value));
return (BuilderType) this;
}
/** Clear an extension. */
public final <Type> BuilderType clearExtension(
- final GeneratedExtension<MessageType, ?> extension) {
- verifyExtensionContainingType(extension);
+ final ExtensionLite<MessageType, ?> extension) {
+ GeneratedExtension<MessageType, ?> extensionLite = checkIsLite(extension);
+
+ verifyExtensionContainingType(extensionLite);
ensureExtensionsIsMutable();
- extensions.clearField(extension.descriptor);
+ extensions.clearField(extensionLite.descriptor);
return (BuilderType) this;
}
@@ -394,127 +592,135 @@ 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(
- final CodedInputStream input,
- final ExtensionRegistryLite extensionRegistry,
- final int tag) throws IOException {
- final int wireType = WireFormat.getTagWireType(tag);
- final int fieldNumber = WireFormat.getTagFieldNumber(tag);
-
- final GeneratedExtension<MessageType, ?> extension =
- extensionRegistry.findLiteExtensionByNumber(
- getDefaultInstanceForType(), fieldNumber);
-
- boolean unknown = false;
- boolean packed = false;
- if (extension == null) {
- unknown = true; // Unknown field.
- } else if (wireType == FieldSet.getWireFormatForFieldType(
- extension.descriptor.getLiteType(),
- false /* isPacked */)) {
- packed = false; // Normal, unpacked value.
- } else if (extension.descriptor.isRepeated &&
- extension.descriptor.type.isPackable() &&
- wireType == FieldSet.getWireFormatForFieldType(
- extension.descriptor.getLiteType(),
- true /* isPacked */)) {
- packed = true; // Packed value.
- } else {
- unknown = true; // Wrong wire type.
- }
+ protected final void mergeExtensionFields(final MessageType other) {
+ ensureExtensionsIsMutable();
+ extensions.mergeFrom(((ExtendableMessage) other).extensions);
+ }
+ }
- if (unknown) { // Unknown field or wrong wire type. Skip.
- return input.skipField(tag);
- }
+ //-----------------------------------------------------------------
- if (packed) {
- final int length = input.readRawVarint32();
- final int limit = input.pushLimit(length);
- if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
- while (input.getBytesUntilLimit() > 0) {
- final int rawValue = input.readEnum();
- final Object value =
- extension.descriptor.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;
- }
- ensureExtensionsIsMutable();
- extensions.addRepeatedField(extension.descriptor, value);
- }
- } else {
- while (input.getBytesUntilLimit() > 0) {
- final Object value =
- FieldSet.readPrimitiveField(input,
- extension.descriptor.getLiteType());
- ensureExtensionsIsMutable();
- extensions.addRepeatedField(extension.descriptor, value);
+ /**
+ * Parse an unknown field or an extension. For use by generated code only.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ protected static <MessageType extends MessageLite>
+ boolean parseUnknownField(
+ FieldSet<ExtensionDescriptor> extensions,
+ MessageType defaultInstance,
+ CodedInputStream input,
+ UnknownFieldSetLite.Builder unknownFields,
+ ExtensionRegistryLite extensionRegistry,
+ int tag) throws IOException {
+ int wireType = WireFormat.getTagWireType(tag);
+ int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+ GeneratedExtension<MessageType, ?> extension =
+ extensionRegistry.findLiteExtensionByNumber(
+ defaultInstance, fieldNumber);
+
+ boolean unknown = false;
+ boolean packed = false;
+ if (extension == null) {
+ unknown = true; // Unknown field.
+ } else if (wireType == FieldSet.getWireFormatForFieldType(
+ extension.descriptor.getLiteType(),
+ false /* isPacked */)) {
+ packed = false; // Normal, unpacked value.
+ } else if (extension.descriptor.isRepeated &&
+ extension.descriptor.type.isPackable() &&
+ wireType == FieldSet.getWireFormatForFieldType(
+ extension.descriptor.getLiteType(),
+ true /* isPacked */)) {
+ packed = true; // Packed value.
+ } else {
+ unknown = true; // Wrong wire type.
+ }
+
+ if (unknown) { // Unknown field or wrong wire type. Skip.
+ return unknownFields.mergeFieldFrom(tag, input);
+ }
+
+ if (packed) {
+ int length = input.readRawVarint32();
+ int limit = input.pushLimit(length);
+ if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
+ while (input.getBytesUntilLimit() > 0) {
+ int rawValue = input.readEnum();
+ Object value =
+ extension.descriptor.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;
}
+ extensions.addRepeatedField(extension.descriptor,
+ extension.singularToFieldSetType(value));
}
- input.popLimit(limit);
} else {
- final Object value;
- switch (extension.descriptor.getLiteJavaType()) {
- case MESSAGE: {
- MessageLite.Builder subBuilder = null;
- if (!extension.descriptor.isRepeated()) {
- MessageLite existingValue =
- (MessageLite) extensions.getField(extension.descriptor);
- if (existingValue != null) {
- subBuilder = existingValue.toBuilder();
- }
- }
- if (subBuilder == null) {
- subBuilder = extension.messageDefaultInstance.newBuilderForType();
- }
- if (extension.descriptor.getLiteType() ==
- WireFormat.FieldType.GROUP) {
- input.readGroup(extension.getNumber(),
- subBuilder, extensionRegistry);
- } else {
- input.readMessage(subBuilder, extensionRegistry);
+ while (input.getBytesUntilLimit() > 0) {
+ Object value =
+ FieldSet.readPrimitiveField(input,
+ extension.descriptor.getLiteType(),
+ /*checkUtf8=*/ false);
+ extensions.addRepeatedField(extension.descriptor, value);
+ }
+ }
+ input.popLimit(limit);
+ } else {
+ Object value;
+ switch (extension.descriptor.getLiteJavaType()) {
+ case MESSAGE: {
+ MessageLite.Builder subBuilder = null;
+ if (!extension.descriptor.isRepeated()) {
+ MessageLite existingValue =
+ (MessageLite) extensions.getField(extension.descriptor);
+ if (existingValue != null) {
+ subBuilder = existingValue.toBuilder();
}
- value = subBuilder.build();
- break;
}
- case ENUM:
- final int rawValue = input.readEnum();
- value = extension.descriptor.getEnumType()
- .findValueByNumber(rawValue);
- // If the number isn't recognized as a valid value for this enum,
- // drop it.
- if (value == null) {
- return true;
- }
- break;
- default:
- value = FieldSet.readPrimitiveField(input,
- extension.descriptor.getLiteType());
- break;
- }
-
- if (extension.descriptor.isRepeated()) {
- ensureExtensionsIsMutable();
- extensions.addRepeatedField(extension.descriptor, value);
- } else {
- ensureExtensionsIsMutable();
- extensions.setField(extension.descriptor, value);
+ if (subBuilder == null) {
+ subBuilder = extension.getMessageDefaultInstance()
+ .newBuilderForType();
+ }
+ if (extension.descriptor.getLiteType() ==
+ WireFormat.FieldType.GROUP) {
+ input.readGroup(extension.getNumber(),
+ subBuilder, extensionRegistry);
+ } else {
+ input.readMessage(subBuilder, extensionRegistry);
+ }
+ value = subBuilder.build();
+ break;
}
+ case ENUM:
+ int rawValue = input.readEnum();
+ value = extension.descriptor.getEnumType()
+ .findValueByNumber(rawValue);
+ // If the number isn't recognized as a valid value for this enum,
+ // write it to unknown fields object.
+ if (value == null) {
+ unknownFields.mergeVarintField(fieldNumber, rawValue);
+ return true;
+ }
+ break;
+ default:
+ value = FieldSet.readPrimitiveField(input,
+ extension.descriptor.getLiteType(),
+ /*checkUtf8=*/ false);
+ break;
}
- return true;
+ if (extension.descriptor.isRepeated()) {
+ extensions.addRepeatedField(extension.descriptor,
+ extension.singularToFieldSetType(value));
+ } else {
+ extensions.setField(extension.descriptor,
+ extension.singularToFieldSetType(value));
+ }
}
- protected final void mergeExtensionFields(final MessageType other) {
- ensureExtensionsIsMutable();
- extensions.mergeFrom(((ExtendableMessage) other).extensions);
- }
+ return true;
}
// -----------------------------------------------------------------
@@ -528,14 +734,16 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
final MessageLite messageDefaultInstance,
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
- final WireFormat.FieldType type) {
+ final WireFormat.FieldType type,
+ final Class singularType) {
return new GeneratedExtension<ContainingType, Type>(
containingTypeDefaultInstance,
defaultValue,
messageDefaultInstance,
new ExtensionDescriptor(enumTypeMap, number, type,
false /* isRepeated */,
- false /* isPacked */));
+ false /* isPacked */),
+ singularType);
}
/** For use by generated code only. */
@@ -547,7 +755,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type,
- final boolean isPacked) {
+ final boolean isPacked,
+ final Class singularType) {
@SuppressWarnings("unchecked") // Subclasses ensure Type is a List
Type emptyList = (Type) Collections.emptyList();
return new GeneratedExtension<ContainingType, Type>(
@@ -555,13 +764,14 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
emptyList,
messageDefaultInstance,
new ExtensionDescriptor(
- enumTypeMap, number, type, true /* isRepeated */, isPacked));
+ enumTypeMap, number, type, true /* isRepeated */, isPacked),
+ singularType);
}
- private static final class ExtensionDescriptor
+ static final class ExtensionDescriptor
implements FieldSet.FieldDescriptorLite<
ExtensionDescriptor> {
- private ExtensionDescriptor(
+ ExtensionDescriptor(
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type,
@@ -574,11 +784,11 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
this.isPacked = isPacked;
}
- private final Internal.EnumLiteMap<?> enumTypeMap;
- private final int number;
- private final WireFormat.FieldType type;
- private final boolean isRepeated;
- private final boolean isPacked;
+ final Internal.EnumLiteMap<?> enumTypeMap;
+ final int number;
+ final WireFormat.FieldType type;
+ final boolean isRepeated;
+ final boolean isPacked;
public int getNumber() {
return number;
@@ -610,25 +820,71 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
}
+
public int compareTo(ExtensionDescriptor other) {
return number - other.number;
}
}
+ // =================================================================
+
+ /** Calls Class.getMethod and throws a RuntimeException if it fails. */
+ @SuppressWarnings("unchecked")
+ static Method getMethodOrDie(Class clazz, String name, Class... params) {
+ try {
+ return clazz.getMethod(name, params);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(
+ "Generated message class \"" + clazz.getName() +
+ "\" missing method \"" + name + "\".", e);
+ }
+ }
+
+ /** Calls invoke and throws a RuntimeException if it fails. */
+ static Object invokeOrDie(Method method, Object object, Object... params) {
+ try {
+ return method.invoke(object, params);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "Couldn't use Java reflection to implement protocol message " +
+ "reflection.", e);
+ } catch (InvocationTargetException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ } else {
+ throw new RuntimeException(
+ "Unexpected exception thrown by generated accessor method.", cause);
+ }
+ }
+ }
+
/**
* Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
*
* Users should ignore the contents of this class and only use objects of
* this type as parameters to extension accessors and ExtensionRegistry.add().
*/
- public static final class GeneratedExtension<
- ContainingType extends MessageLite, Type> {
+ public static class GeneratedExtension<
+ ContainingType extends MessageLite, Type>
+ extends ExtensionLite<ContainingType, Type> {
- private GeneratedExtension(
+ /**
+ * Create a new isntance with the given parameters.
+ *
+ * The last parameter {@code singularType} is only needed for enum types.
+ * We store integer values for enum types in a {@link ExtendableMessage}
+ * and use Java reflection to convert an integer value back into a concrete
+ * enum object.
+ */
+ GeneratedExtension(
final ContainingType containingTypeDefaultInstance,
final Type defaultValue,
final MessageLite messageDefaultInstance,
- final ExtensionDescriptor descriptor) {
+ final ExtensionDescriptor descriptor,
+ Class singularType) {
// Defensive checks to verify the correct initialization order of
// GeneratedExtensions and their related GeneratedMessages.
if (containingTypeDefaultInstance == null) {
@@ -644,12 +900,24 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
this.defaultValue = defaultValue;
this.messageDefaultInstance = messageDefaultInstance;
this.descriptor = descriptor;
+
+ // Use Java reflection to invoke the static method {@code valueOf} of
+ // enum types in order to convert integers to concrete enum objects.
+ this.singularType = singularType;
+ if (Internal.EnumLite.class.isAssignableFrom(singularType)) {
+ this.enumValueOf = getMethodOrDie(
+ singularType, "valueOf", int.class);
+ } else {
+ this.enumValueOf = null;
+ }
}
- private final ContainingType containingTypeDefaultInstance;
- private final Type defaultValue;
- private final MessageLite messageDefaultInstance;
- private final ExtensionDescriptor descriptor;
+ final ContainingType containingTypeDefaultInstance;
+ final Type defaultValue;
+ final MessageLite messageDefaultInstance;
+ final ExtensionDescriptor descriptor;
+ final Class singularType;
+ final Method enumValueOf;
/**
* Default instance of the type being extended, used to identify that type.
@@ -663,13 +931,76 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
return descriptor.getNumber();
}
+
/**
- * If the extension is an embedded message, this is the default instance of
- * that type.
+ * If the extension is an embedded message or group, returns the default
+ * instance of the message.
*/
public MessageLite getMessageDefaultInstance() {
return messageDefaultInstance;
}
+
+ @SuppressWarnings("unchecked")
+ Object fromFieldSetType(final Object value) {
+ if (descriptor.isRepeated()) {
+ if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+ final List result = new ArrayList();
+ for (final Object element : (List) value) {
+ result.add(singularFromFieldSetType(element));
+ }
+ return result;
+ } else {
+ return value;
+ }
+ } else {
+ return singularFromFieldSetType(value);
+ }
+ }
+
+ Object singularFromFieldSetType(final Object value) {
+ if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+ return invokeOrDie(enumValueOf, null, (Integer) value);
+ } else {
+ return value;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ Object toFieldSetType(final Object value) {
+ if (descriptor.isRepeated()) {
+ if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+ final List result = new ArrayList();
+ for (final Object element : (List) value) {
+ result.add(singularToFieldSetType(element));
+ }
+ return result;
+ } else {
+ return value;
+ }
+ } else {
+ return singularToFieldSetType(value);
+ }
+ }
+
+ Object singularToFieldSetType(final Object value) {
+ if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+ return ((Internal.EnumLite) value).getNumber();
+ } else {
+ return value;
+ }
+ }
+
+ public FieldType getLiteType() {
+ return descriptor.getLiteType();
+ }
+
+ public boolean isRepeated() {
+ return descriptor.isRepeated;
+ }
+
+ public Type getDefaultValue() {
+ return defaultValue;
+ }
}
/**
@@ -679,8 +1010,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}.
@@ -700,19 +1031,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);
}
@@ -722,10 +1051,66 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
/**
* Replaces this object in the output stream with a serialized form.
* Part of Java's serialization magic. Generated sub-classes must override
- * this method by calling <code>return super.writeReplace();</code>
+ * this method by calling {@code return super.writeReplace();}
* @return a SerializedForm of this message
*/
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 <
+ MessageType extends ExtendableMessage<MessageType, BuilderType>,
+ BuilderType extends ExtendableBuilder<MessageType, BuilderType>,
+ T>
+ GeneratedExtension<MessageType, T> checkIsLite(
+ ExtensionLite<MessageType, T> extension) {
+ if (!extension.isLite()) {
+ throw new IllegalArgumentException("Expected a lite extension.");
+ }
+
+ return (GeneratedExtension<MessageType, T>) extension;
+ }
+
+ /**
+ * Represents the state needed to implement *ForType methods. Generated code
+ * must provide a static singleton instance by adding it with
+ * {@link GeneratedMessageLite#onLoad(Class, PrototypeHolder)} on class load.
+ * <ul>
+ * <li>{@link #getDefaultInstanceForType()}
+ * <li>{@link #getParserForType()}
+ * <li>{@link #newBuilderForType()}
+ * </ul>
+ * This allows us to trade three generated methods for a static Map.
+ */
+ protected static class PrototypeHolder<
+ MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+ BuilderType extends GeneratedMessageLite.Builder<
+ MessageType, BuilderType>> {
+
+ private final MessageType defaultInstance;
+ private final Parser<MessageType> parser;
+
+ public PrototypeHolder(
+ MessageType defaultInstance, Parser<MessageType> parser) {
+ this.defaultInstance = defaultInstance;
+ this.parser = parser;
+ }
+
+ public MessageType getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public Parser<MessageType> getParserForType() {
+ return parser;
+ }
+
+ @SuppressWarnings("unchecked") // Guaranteed by runtime.
+ public BuilderType newBuilderForType() {
+ return (BuilderType) defaultInstance.toBuilder();
+ }
+ }
}
diff --git a/java/src/main/java/com/google/protobuf/Internal.java b/java/src/main/java/com/google/protobuf/Internal.java
index 05eab57a..5a0de6d1 100644
--- a/java/src/main/java/com/google/protobuf/Internal.java
+++ b/java/src/main/java/com/google/protobuf/Internal.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,7 +30,17 @@
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
@@ -98,90 +108,111 @@ public class Internal {
"Java VM does not support a standard character set.", e);
}
}
+ /**
+ * Helper called by generated code to construct default values for bytes
+ * fields.
+ * <p>
+ * This is like {@link #bytesDefaultValue}, but returns a byte array.
+ */
+ public static byte[] byteArrayDefaultValue(String bytes) {
+ try {
+ return bytes.getBytes("ISO-8859-1");
+ } catch (UnsupportedEncodingException e) {
+ // This should never happen since all JVMs are required to implement
+ // ISO-8859-1.
+ throw new IllegalStateException(
+ "Java VM does not support a standard character set.", e);
+ }
+ }
+
+ /**
+ * Helper called by generated code to construct default values for bytes
+ * fields.
+ * <p>
+ * This is like {@link #bytesDefaultValue}, but returns a ByteBuffer.
+ */
+ public static ByteBuffer byteBufferDefaultValue(String bytes) {
+ return ByteBuffer.wrap(byteArrayDefaultValue(bytes));
+ }
+
+ /**
+ * Create a new ByteBuffer and copy all the content of {@code source}
+ * ByteBuffer to the new ByteBuffer. The new ByteBuffer's limit and
+ * capacity will be source.capacity(), and its position will be 0.
+ * Note that the state of {@code source} ByteBuffer won't be changed.
+ */
+ public static ByteBuffer copyByteBuffer(ByteBuffer source) {
+ // Make a duplicate of the source ByteBuffer and read data from the
+ // duplicate. This is to avoid affecting the source ByteBuffer's state.
+ ByteBuffer temp = source.duplicate();
+ // We want to copy all the data in the source ByteBuffer, not just the
+ // remaining bytes.
+ temp.clear();
+ ByteBuffer result = ByteBuffer.allocate(temp.capacity());
+ result.put(temp);
+ result.clear();
+ return result;
+ }
/**
* Helper called by generated code to determine if a byte array is a valid
* UTF-8 encoded string such that the original bytes can be converted to
* a String object and then back to a byte array round tripping the bytes
- * without loss.
- * <p>
- * This is inspired by UTF_8.java in sun.nio.cs.
+ * without loss. More precisely, returns {@code true} whenever:
+ * <pre> {@code
+ * Arrays.equals(byteString.toByteArray(),
+ * new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
+ * }</pre>
+ *
+ * <p>This method rejects "overlong" byte sequences, as well as
+ * 3-byte sequences that would map to a surrogate character, in
+ * accordance with the restricted definition of UTF-8 introduced in
+ * Unicode 3.1. Note that the UTF-8 decoder included in Oracle's
+ * JDK has been modified to also reject "overlong" byte sequences,
+ * but currently (2011) still accepts 3-byte surrogate character
+ * byte sequences.
+ *
+ * <p>See the Unicode Standard,</br>
+ * Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
+ * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
+ *
+ * <p>As of 2011-02, this method simply returns the result of {@link
+ * ByteString#isValidUtf8()}. Calling that method directly is preferred.
*
* @param byteString the string to check
* @return whether the byte array is round trippable
*/
public static boolean isValidUtf8(ByteString byteString) {
- int index = 0;
- int size = byteString.size();
- // To avoid the masking, we could change this to use bytes;
- // Then X > 0xC2 gets turned into X < -0xC2; X < 0x80
- // gets turned into X >= 0, etc.
-
- while (index < size) {
- int byte1 = byteString.byteAt(index++) & 0xFF;
- if (byte1 < 0x80) {
- // fast loop for single bytes
- continue;
-
- // we know from this point on that we have 2-4 byte forms
- } else if (byte1 < 0xC2 || byte1 > 0xF4) {
- // catch illegal first bytes: < C2 or > F4
- return false;
- }
- if (index >= size) {
- // fail if we run out of bytes
- return false;
- }
- int byte2 = byteString.byteAt(index++) & 0xFF;
- if (byte2 < 0x80 || byte2 > 0xBF) {
- // general trail-byte test
- return false;
- }
- if (byte1 <= 0xDF) {
- // two-byte form; general trail-byte test is sufficient
- continue;
- }
-
- // we know from this point on that we have 3 or 4 byte forms
- if (index >= size) {
- // fail if we run out of bytes
- return false;
- }
- int byte3 = byteString.byteAt(index++) & 0xFF;
- if (byte3 < 0x80 || byte3 > 0xBF) {
- // general trail-byte test
- return false;
- }
- if (byte1 <= 0xEF) {
- // three-byte form. Vastly more frequent than four-byte forms
- // The following has an extra test, but not worth restructuring
- if (byte1 == 0xE0 && byte2 < 0xA0 ||
- byte1 == 0xED && byte2 > 0x9F) {
- // check special cases of byte2
- return false;
- }
-
- } else {
- // four-byte form
+ return byteString.isValidUtf8();
+ }
+
+ /**
+ * Like {@link #isValidUtf8(ByteString)} but for byte arrays.
+ */
+ public static boolean isValidUtf8(byte[] byteArray) {
+ return Utf8.isValidUtf8(byteArray);
+ }
- if (index >= size) {
- // fail if we run out of bytes
- return false;
- }
- int byte4 = byteString.byteAt(index++) & 0xFF;
- if (byte4 < 0x80 || byte4 > 0xBF) {
- // general trail-byte test
- return false;
- }
- // The following has an extra test, but not worth restructuring
- if (byte1 == 0xF0 && byte2 < 0x90 ||
- byte1 == 0xF4 && byte2 > 0x8F) {
- // check special cases of byte2
- return false;
- }
- }
+ /**
+ * Helper method to get the UTF-8 bytes of a string.
+ */
+ public static byte[] toByteArray(String value) {
+ try {
+ return value.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported?", e);
+ }
+ }
+
+ /**
+ * Helper method to convert a byte array to a string using UTF-8 encoding.
+ */
+ public static String toStringUtf8(byte[] bytes) {
+ try {
+ return new String(bytes, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported?", e);
}
- return true;
}
/**
@@ -203,4 +234,328 @@ public class Internal {
public interface EnumLiteMap<T extends EnumLite> {
T findValueByNumber(int number);
}
+
+ /**
+ * Helper method for implementing {@link Message#hashCode()} for longs.
+ * @see Long#hashCode()
+ */
+ public static int hashLong(long n) {
+ return (int) (n ^ (n >>> 32));
+ }
+
+ /**
+ * Helper method for implementing {@link Message#hashCode()} for
+ * booleans.
+ * @see Boolean#hashCode()
+ */
+ public static int hashBoolean(boolean b) {
+ return b ? 1231 : 1237;
+ }
+
+ /**
+ * Helper method for implementing {@link Message#hashCode()} for enums.
+ * <p>
+ * This is needed because {@link java.lang.Enum#hashCode()} is final, but we
+ * need to use the field number as the hash code to ensure compatibility
+ * between statically and dynamically generated enum objects.
+ */
+ public static int hashEnum(EnumLite e) {
+ return e.getNumber();
+ }
+
+ /**
+ * Helper method for implementing {@link Message#hashCode()} for
+ * enum lists.
+ */
+ public static int hashEnumList(List<? extends EnumLite> list) {
+ int hash = 1;
+ for (EnumLite e : list) {
+ hash = 31 * hash + hashEnum(e);
+ }
+ return hash;
+ }
+
+ /**
+ * Helper method for implementing {@link Message#equals(Object)} for bytes field.
+ */
+ public static boolean equals(List<byte[]> a, List<byte[]> b) {
+ if (a.size() != b.size()) return false;
+ for (int i = 0; i < a.size(); ++i) {
+ if (!Arrays.equals(a.get(i), b.get(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Helper method for implementing {@link Message#hashCode()} for bytes field.
+ */
+ public static int hashCode(List<byte[]> list) {
+ int hash = 1;
+ for (byte[] bytes : list) {
+ hash = 31 * hash + hashCode(bytes);
+ }
+ return hash;
+ }
+
+ /**
+ * Helper method for implementing {@link Message#hashCode()} for bytes field.
+ */
+ public static int hashCode(byte[] bytes) {
+ // The hash code for a byte array should be the same as the hash code for a
+ // ByteString with the same content. This is to ensure that the generated
+ // hashCode() method will return the same value as the pure reflection
+ // based hashCode() method.
+ return LiteralByteString.hashCode(bytes);
+ }
+
+ /**
+ * Helper method for implementing {@link Message#equals(Object)} for bytes
+ * field.
+ */
+ public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) {
+ if (a.capacity() != b.capacity()) {
+ return false;
+ }
+ // ByteBuffer.equals() will only compare the remaining bytes, but we want to
+ // compare all the content.
+ return a.duplicate().clear().equals(b.duplicate().clear());
+ }
+
+ /**
+ * Helper method for implementing {@link Message#equals(Object)} for bytes
+ * field.
+ */
+ public static boolean equalsByteBuffer(
+ List<ByteBuffer> a, List<ByteBuffer> b) {
+ if (a.size() != b.size()) {
+ return false;
+ }
+ for (int i = 0; i < a.size(); ++i) {
+ if (!equalsByteBuffer(a.get(i), b.get(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Helper method for implementing {@link Message#hashCode()} for bytes
+ * field.
+ */
+ public static int hashCodeByteBuffer(List<ByteBuffer> list) {
+ int hash = 1;
+ for (ByteBuffer bytes : list) {
+ hash = 31 * hash + hashCodeByteBuffer(bytes);
+ }
+ return hash;
+ }
+
+ private static final int DEFAULT_BUFFER_SIZE = 4096;
+
+ /**
+ * Helper method for implementing {@link Message#hashCode()} for bytes
+ * field.
+ */
+ public static int hashCodeByteBuffer(ByteBuffer bytes) {
+ if (bytes.hasArray()) {
+ // Fast path.
+ int h = LiteralByteString.hashCode(bytes.capacity(), bytes.array(),
+ bytes.arrayOffset(), bytes.capacity());
+ return h == 0 ? 1 : h;
+ } else {
+ // Read the data into a temporary byte array before calculating the
+ // hash value.
+ final int bufferSize = bytes.capacity() > DEFAULT_BUFFER_SIZE
+ ? DEFAULT_BUFFER_SIZE : bytes.capacity();
+ final byte[] buffer = new byte[bufferSize];
+ final ByteBuffer duplicated = bytes.duplicate();
+ duplicated.clear();
+ int h = bytes.capacity();
+ while (duplicated.remaining() > 0) {
+ final int length = duplicated.remaining() <= bufferSize ?
+ duplicated.remaining() : bufferSize;
+ duplicated.get(buffer, 0, length);
+ h = LiteralByteString.hashCode(h, buffer, 0, length);
+ }
+ return h == 0 ? 1 : h;
+ }
+ }
+
+ /**
+ * An empty byte array constant used in generated code.
+ */
+ public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+ /**
+ * An empty byte array constant used in generated code.
+ */
+ public static final ByteBuffer EMPTY_BYTE_BUFFER =
+ ByteBuffer.wrap(EMPTY_BYTE_ARRAY);
+
+ /** An empty coded input stream constant used in generated code. */
+ public static final CodedInputStream EMPTY_CODED_INPUT_STREAM =
+ CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
+
+
+ /**
+ * Provides an immutable view of List<T> around a List<F>.
+ *
+ * Protobuf internal. Used in protobuf generated code only.
+ */
+ public static class ListAdapter<F, T> extends AbstractList<T> {
+ /**
+ * Convert individual elements of the List from F to T.
+ */
+ public interface Converter<F, T> {
+ T convert(F from);
+ }
+
+ private final List<F> fromList;
+ private final Converter<F, T> converter;
+
+ public ListAdapter(List<F> fromList, Converter<F, T> 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<K, RealValue> and provide a Map<K, V> interface.
+ */
+ public static class MapAdapter<K, V, RealValue> extends AbstractMap<K, V> {
+ /**
+ * An interface used to convert between two types.
+ */
+ public interface Converter<A, B> {
+ B doForward(A object);
+ A doBackward(B object);
+ }
+
+ public static <T extends EnumLite> Converter<Integer, T> newEnumConverter(
+ final EnumLiteMap<T> enumMap, final T unrecognizedValue) {
+ return new Converter<Integer, T>() {
+ 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<K, RealValue> realMap;
+ private final Converter<RealValue, V> valueConverter;
+
+ public MapAdapter(Map<K, RealValue> realMap,
+ Converter<RealValue, V> 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<java.util.Map.Entry<K, V>> entrySet() {
+ return new SetAdapter(realMap.entrySet());
+ }
+
+ private class SetAdapter extends AbstractSet<Map.Entry<K, V>> {
+ private final Set<Map.Entry<K, RealValue>> realSet;
+ public SetAdapter(Set<Map.Entry<K, RealValue>> realSet) {
+ this.realSet = realSet;
+ }
+
+ @Override
+ public Iterator<java.util.Map.Entry<K, V>> iterator() {
+ return new IteratorAdapter(realSet.iterator());
+ }
+
+ @Override
+ public int size() {
+ return realSet.size();
+ }
+ }
+
+ private class IteratorAdapter implements Iterator<Map.Entry<K, V>> {
+ private final Iterator<Map.Entry<K, RealValue>> realIterator;
+
+ public IteratorAdapter(
+ Iterator<Map.Entry<K, RealValue>> realIterator) {
+ this.realIterator = realIterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return realIterator.hasNext();
+ }
+
+ @Override
+ public java.util.Map.Entry<K, V> next() {
+ return new EntryAdapter(realIterator.next());
+ }
+
+ @Override
+ public void remove() {
+ realIterator.remove();
+ }
+ }
+
+ private class EntryAdapter implements Map.Entry<K, V> {
+ private final Map.Entry<K, RealValue> realEntry;
+
+ public EntryAdapter(Map.Entry<K, RealValue> 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/InvalidProtocolBufferException.java b/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
index 90f7ffbc..367fa23b 100644
--- a/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
+++ b/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -40,11 +40,32 @@ import java.io.IOException;
*/
public class InvalidProtocolBufferException extends IOException {
private static final long serialVersionUID = -1616151763072450476L;
+ private MessageLite unfinishedMessage = null;
public InvalidProtocolBufferException(final String description) {
super(description);
}
+ /**
+ * Attaches an unfinished message to the exception to support best-effort
+ * parsing in {@code Parser} interface.
+ *
+ * @return this
+ */
+ public InvalidProtocolBufferException setUnfinishedMessage(
+ MessageLite unfinishedMessage) {
+ this.unfinishedMessage = unfinishedMessage;
+ return this;
+ }
+
+ /**
+ * Returns the unfinished message attached to the exception, or null if
+ * no message is attached.
+ */
+ public MessageLite getUnfinishedMessage() {
+ return unfinishedMessage;
+ }
+
static InvalidProtocolBufferException truncatedMessage() {
return new InvalidProtocolBufferException(
"While parsing a protocol message, the input ended unexpectedly " +
@@ -90,4 +111,12 @@ public class InvalidProtocolBufferException extends IOException {
"Protocol message was too large. May be malicious. " +
"Use CodedInputStream.setSizeLimit() to increase the size limit.");
}
+
+ static InvalidProtocolBufferException parseFailure() {
+ return new InvalidProtocolBufferException("Failed to parse the message.");
+ }
+
+ static InvalidProtocolBufferException invalidUtf8() {
+ return new InvalidProtocolBufferException("Protocol message had invalid UTF-8.");
+ }
}
diff --git a/java/src/main/java/com/google/protobuf/LazyField.java b/java/src/main/java/com/google/protobuf/LazyField.java
new file mode 100644
index 00000000..3da8b900
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/LazyField.java
@@ -0,0 +1,154 @@
+// 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.Iterator;
+import java.util.Map.Entry;
+
+/**
+ * LazyField encapsulates the logic of lazily parsing message fields. It stores
+ * the message in a ByteString initially and then parse it on-demand.
+ *
+ * Most of key methods are implemented in {@link LazyFieldLite} but this class
+ * can contain default instance of the message to provide {@code hashCode()},
+ * {@code euqals()} and {@code toString()}.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyField extends LazyFieldLite {
+
+ /**
+ * Carry a message's default instance which is used by {@code hashCode()}, {@code euqals()} and
+ * {@code toString()}.
+ */
+ private final MessageLite defaultInstance;
+
+ public LazyField(MessageLite defaultInstance,
+ ExtensionRegistryLite extensionRegistry, ByteString bytes) {
+ super(extensionRegistry, bytes);
+
+ this.defaultInstance = defaultInstance;
+ }
+
+ @Override
+ public boolean containsDefaultInstance() {
+ return super.containsDefaultInstance() || value == defaultInstance;
+ }
+
+ public MessageLite getValue() {
+ return getValue(defaultInstance);
+ }
+
+ @Override
+ public int hashCode() {
+ return getValue().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return getValue().equals(obj);
+ }
+
+ @Override
+ public String toString() {
+ return getValue().toString();
+ }
+
+ // ====================================================
+
+ /**
+ * LazyEntry and LazyIterator are used to encapsulate the LazyField, when
+ * users iterate all fields from FieldSet.
+ */
+ static class LazyEntry<K> implements Entry<K, Object> {
+ private Entry<K, LazyField> entry;
+
+ private LazyEntry(Entry<K, LazyField> entry) {
+ this.entry = entry;
+ }
+
+ // @Override
+ public K getKey() {
+ return entry.getKey();
+ }
+
+ // @Override
+ public Object getValue() {
+ LazyField field = entry.getValue();
+ if (field == null) {
+ return null;
+ }
+ return field.getValue();
+ }
+
+ public LazyField getField() {
+ return entry.getValue();
+ }
+
+ // @Override
+ public Object setValue(Object value) {
+ if (!(value instanceof MessageLite)) {
+ throw new IllegalArgumentException(
+ "LazyField now only used for MessageSet, "
+ + "and the value of MessageSet must be an instance of MessageLite");
+ }
+ return entry.getValue().setValue((MessageLite) value);
+ }
+ }
+
+ static class LazyIterator<K> implements Iterator<Entry<K, Object>> {
+ private Iterator<Entry<K, Object>> iterator;
+
+ public LazyIterator(Iterator<Entry<K, Object>> iterator) {
+ this.iterator = iterator;
+ }
+
+ // @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @SuppressWarnings("unchecked")
+ // @Override
+ public Entry<K, Object> next() {
+ Entry<K, ?> entry = iterator.next();
+ if (entry.getValue() instanceof LazyField) {
+ return new LazyEntry<K>((Entry<K, LazyField>) entry);
+ }
+ return (Entry<K, Object>) entry;
+ }
+
+ // @Override
+ public void remove() {
+ iterator.remove();
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/src/main/java/com/google/protobuf/LazyFieldLite.java
new file mode 100644
index 00000000..eea1fe3c
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/LazyFieldLite.java
@@ -0,0 +1,339 @@
+// 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;
+
+/**
+ * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores
+ * the message in a ByteString initially and then parse it on-demand.
+ *
+ * LazyField is thread-compatible e.g. concurrent read are safe, however,
+ * synchronizations are needed under read/write situations.
+ *
+ * This class is internal implementation detail, so you don't need to use it directly.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyFieldLite {
+ private static final ExtensionRegistryLite EMPTY_REGISTRY =
+ ExtensionRegistryLite.getEmptyRegistry();
+
+ /**
+ * A delayed-parsed version of the bytes. When this is non-null then {@code extensionRegistry } is
+ * also non-null and {@code value} and {@code memoizedBytes} are null.
+ */
+ private ByteString delayedBytes;
+
+ /**
+ * An {@code ExtensionRegistryLite} for parsing bytes. It is non-null on a best-effort basis. It
+ * is only guaranteed to be non-null if this message was initialized using bytes and an
+ * {@code ExtensionRegistry}. If it directly had a value set then it will be null, unless it has
+ * been merged with another {@code LazyFieldLite} that had an {@code ExtensionRegistry}.
+ */
+ private ExtensionRegistryLite extensionRegistry;
+
+ /**
+ * The parsed value. When this is non-null then {@code delayedBytes} will be null.
+ */
+ protected volatile MessageLite value;
+
+ /**
+ * The memoized bytes for {@code value}. Will be null when {@code value} is null.
+ */
+ private volatile ByteString memoizedBytes;
+
+ /**
+ * Constructs a LazyFieldLite with bytes that will be parsed lazily.
+ */
+ public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
+ checkArguments(extensionRegistry, bytes);
+ this.extensionRegistry = extensionRegistry;
+ this.delayedBytes = bytes;
+ }
+
+ /**
+ * Constructs a LazyFieldLite with no contents, and no ability to parse extensions.
+ */
+ public LazyFieldLite() {
+ }
+
+ /**
+ * Constructs a LazyFieldLite instance with a value. The LazyFieldLite may not be able to parse
+ * the extensions in the value as it has no ExtensionRegistry.
+ */
+ public static LazyFieldLite fromValue(MessageLite value) {
+ LazyFieldLite lf = new LazyFieldLite();
+ lf.setValue(value);
+ return lf;
+ }
+
+ /**
+ * Determines whether this LazyFieldLite instance represents the default instance of this type.
+ */
+ public boolean containsDefaultInstance() {
+ return memoizedBytes == ByteString.EMPTY
+ || value == null && (delayedBytes == null || delayedBytes == ByteString.EMPTY);
+ }
+
+ /**
+ * Clears the value state of this instance.
+ *
+ * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+ * under read/write situations.
+ */
+ public void clear() {
+ // Don't clear the ExtensionRegistry. It might prove useful later on when merging in another
+ // value, but there is no guarantee that it will contain all extensions that were directly set
+ // on the values that need to be merged.
+ delayedBytes = null;
+ value = null;
+ memoizedBytes = null;
+ }
+
+ /**
+ * Overrides the contents of this LazyField.
+ *
+ * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+ * under read/write situations.
+ */
+ public void set(LazyFieldLite other) {
+ this.delayedBytes = other.delayedBytes;
+ this.value = other.value;
+ this.memoizedBytes = other.memoizedBytes;
+ // If the other LazyFieldLite was created by directly setting the value rather than first by
+ // parsing, then it will not have an extensionRegistry. In this case we hold on to the existing
+ // extensionRegistry, which has no guarantees that it has all the extensions that will be
+ // directly set on the value.
+ if (other.extensionRegistry != null) {
+ this.extensionRegistry = other.extensionRegistry;
+ }
+ }
+
+ /**
+ * Returns message instance. It may do some thread-safe delayed parsing of bytes.
+ *
+ * @param defaultInstance its message's default instance. It's also used to get parser for the
+ * message type.
+ */
+ public MessageLite getValue(MessageLite defaultInstance) {
+ ensureInitialized(defaultInstance);
+ return value;
+ }
+
+ /**
+ * Sets the value of the instance and returns the old value without delay parsing anything.
+ *
+ * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+ * under read/write situations.
+ */
+ public MessageLite setValue(MessageLite value) {
+ MessageLite originalValue = this.value;
+ this.delayedBytes = null;
+ this.memoizedBytes = null;
+ this.value = value;
+ return originalValue;
+ }
+
+ /**
+ * Merges another instance's contents. In some cases may drop some extensions if both fields
+ * contain data. If the other field has an {@code ExtensionRegistry} but this does not, then this
+ * field will copy over that {@code ExtensionRegistry}.
+ *
+ * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+ * under read/write situations.
+ */
+ public void merge(LazyFieldLite other) {
+ if (other.containsDefaultInstance()) {
+ return;
+ }
+
+ if (this.containsDefaultInstance()) {
+ set(other);
+ return;
+ }
+
+ // If the other field has an extension registry but this does not, copy over the other extension
+ // registry.
+ if (this.extensionRegistry == null) {
+ this.extensionRegistry = other.extensionRegistry;
+ }
+
+ // In the case that both of them are not parsed we simply concatenate the bytes to save time. In
+ // the (probably rare) case that they have different extension registries there is a chance that
+ // some of the extensions may be dropped, but the tradeoff of making this operation fast seems
+ // to outway the benefits of combining the extension registries, which is not normally done for
+ // lite protos anyways.
+ if (this.delayedBytes != null && other.delayedBytes != null) {
+ this.delayedBytes = this.delayedBytes.concat(other.delayedBytes);
+ return;
+ }
+
+ // At least one is parsed and both contain data. We won't drop any extensions here directly, but
+ // in the case that the extension registries are not the same then we might in the future if we
+ // need to serialze and parse a message again.
+ if (this.value == null && other.value != null) {
+ setValue(mergeValueAndBytes(other.value, this.delayedBytes, this.extensionRegistry));
+ return;
+ } else if (this.value != null && other.value == null) {
+ setValue(mergeValueAndBytes(this.value, other.delayedBytes, other.extensionRegistry));
+ return;
+ }
+
+ // At this point we have two fully parsed messages. We can't merge directly from one to the
+ // other because only generated builder code contains methods to mergeFrom another parsed
+ // message. We have to serialize one instance and then merge the bytes into the other. This may
+ // drop extensions from one of the messages if one of the values had an extension set on it
+ // directly.
+ //
+ // To mitigate this we prefer serializing a message that has an extension registry, and
+ // therefore a chance that all extensions set on it are in that registry.
+ //
+ // NOTE: The check for other.extensionRegistry not being null must come first because at this
+ // point in time if other.extensionRegistry is not null then this.extensionRegistry will not be
+ // null either.
+ if (other.extensionRegistry != null) {
+ setValue(mergeValueAndBytes(this.value, other.toByteString(), other.extensionRegistry));
+ return;
+ } else if (this.extensionRegistry != null) {
+ setValue(mergeValueAndBytes(other.value, this.toByteString(), this.extensionRegistry));
+ return;
+ } else {
+ // All extensions from the other message will be dropped because we have no registry.
+ setValue(mergeValueAndBytes(this.value, other.toByteString(), EMPTY_REGISTRY));
+ return;
+ }
+ }
+
+ private static MessageLite mergeValueAndBytes(
+ MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry) {
+ try {
+ return value.toBuilder().mergeFrom(otherBytes, extensionRegistry).build();
+ } catch (InvalidProtocolBufferException e) {
+ // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
+ // was invalid.
+ return value;
+ }
+ }
+
+ /**
+ * Sets this field with bytes to delay-parse.
+ */
+ public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) {
+ checkArguments(extensionRegistry, bytes);
+ this.delayedBytes = bytes;
+ this.extensionRegistry = extensionRegistry;
+ this.value = null;
+ this.memoizedBytes = null;
+ }
+
+ /**
+ * Due to the optional field can be duplicated at the end of serialized
+ * bytes, which will make the serialized size changed after LazyField
+ * parsed. Be careful when using this method.
+ */
+ public int getSerializedSize() {
+ if (delayedBytes != null) {
+ return delayedBytes.size();
+ } else if (memoizedBytes != null) {
+ return memoizedBytes.size();
+ } else if (value != null) {
+ return value.getSerializedSize();
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns a BytesString for this field in a thread-safe way.
+ */
+ public ByteString toByteString() {
+ if (delayedBytes != null) {
+ return delayedBytes;
+ }
+ if (memoizedBytes != null) {
+ return memoizedBytes;
+ }
+ synchronized (this) {
+ if (memoizedBytes != null) {
+ return memoizedBytes;
+ }
+ if (value == null) {
+ memoizedBytes = ByteString.EMPTY;
+ } else {
+ memoizedBytes = value.toByteString();
+ }
+ return memoizedBytes;
+ }
+ }
+
+ /**
+ * Might lazily parse the bytes that were previously passed in. Is thread-safe.
+ */
+ protected void ensureInitialized(MessageLite defaultInstance) {
+ if (value != null) {
+ return;
+ }
+ synchronized (this) {
+ if (value != null) {
+ return;
+ }
+ try {
+ if (delayedBytes != null) {
+ // The extensionRegistry shouldn't be null here since we have delayedBytes.
+ MessageLite parsedValue = defaultInstance.getParserForType()
+ .parseFrom(delayedBytes, extensionRegistry);
+ this.value = parsedValue;
+ this.memoizedBytes = delayedBytes;
+ this.delayedBytes = null;
+ } else {
+ this.value = defaultInstance;
+ this.memoizedBytes = ByteString.EMPTY;
+ this.delayedBytes = null;
+ }
+ } catch (InvalidProtocolBufferException e) {
+ // Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto
+ // was invalid.
+ this.value = defaultInstance;
+ this.memoizedBytes = ByteString.EMPTY;
+ this.delayedBytes = null;
+ }
+ }
+ }
+
+
+ private static void checkArguments(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
+ if (extensionRegistry == null) {
+ throw new NullPointerException("found null ExtensionRegistry");
+ }
+ if (bytes == null) {
+ throw new NullPointerException("found null ByteString");
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
index 1683a640..2d40a51f 100644
--- a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
+++ b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,17 +30,19 @@
package com.google.protobuf;
+import java.util.Arrays;
import java.util.List;
import java.util.AbstractList;
import java.util.ArrayList;
-import java.util.RandomAccess;
import java.util.Collection;
+import java.util.Collections;
+import java.util.RandomAccess;
/**
* An implementation of {@link LazyStringList} that wraps an ArrayList. Each
- * element is either a ByteString or a String. It caches the last one requested
- * which is most likely the one needed next. This minimizes memory usage while
- * satisfying the most common use cases.
+ * element is one of String, ByteString, or byte[]. It caches the last one
+ * requested which is most likely the one needed next. This minimizes memory
+ * usage while satisfying the most common use cases.
* <p>
* <strong>Note that this implementation is not synchronized.</strong>
* If multiple threads access an <tt>ArrayList</tt> instance concurrently,
@@ -63,8 +65,8 @@ import java.util.Collection;
public class LazyStringArrayList extends AbstractList<String>
implements LazyStringList, RandomAccess {
- public final static LazyStringList EMPTY = new UnmodifiableLazyStringList(
- new LazyStringArrayList());
+ public static final LazyStringList EMPTY =
+ new LazyStringArrayList().getUnmodifiableView();
private final List<Object> list;
@@ -72,6 +74,15 @@ public class LazyStringArrayList extends AbstractList<String>
list = new ArrayList<Object>();
}
+ public LazyStringArrayList(int intialCapacity) {
+ list = new ArrayList<Object>(intialCapacity);
+ }
+
+ public LazyStringArrayList(LazyStringList from) {
+ list = new ArrayList<Object>(from.size());
+ addAll(from);
+ }
+
public LazyStringArrayList(List<String> from) {
list = new ArrayList<Object>(from);
}
@@ -81,10 +92,17 @@ public class LazyStringArrayList extends AbstractList<String>
Object o = list.get(index);
if (o instanceof String) {
return (String) o;
- } else {
+ } else if (o instanceof ByteString) {
ByteString bs = (ByteString) o;
String s = bs.toStringUtf8();
- if (Internal.isValidUtf8(bs)) {
+ if (bs.isValidUtf8()) {
+ list.set(index, s);
+ }
+ return s;
+ } else {
+ byte[] ba = (byte[]) o;
+ String s = Internal.toStringUtf8(ba);
+ if (Internal.isValidUtf8(ba)) {
list.set(index, s);
}
return s;
@@ -109,8 +127,35 @@ public class LazyStringArrayList extends AbstractList<String>
}
@Override
+ public boolean addAll(Collection<? extends String> c) {
+ // The default implementation of AbstractCollection.addAll(Collection)
+ // delegates to add(Object). This implementation instead delegates to
+ // addAll(int, Collection), which makes a special case for Collections
+ // which are instances of LazyStringList.
+ return addAll(size(), c);
+ }
+
+ @Override
public boolean addAll(int index, Collection<? extends String> c) {
- boolean ret = list.addAll(index, c);
+ // When copying from another LazyStringList, directly copy the underlying
+ // elements rather than forcing each element to be decoded to a String.
+ Collection<?> collection = c instanceof LazyStringList
+ ? ((LazyStringList) c).getUnderlyingElements() : c;
+ boolean ret = list.addAll(index, collection);
+ modCount++;
+ return ret;
+ }
+
+ // @Override
+ public boolean addAllByteString(Collection<? extends ByteString> values) {
+ boolean ret = list.addAll(values);
+ modCount++;
+ return ret;
+ }
+
+ // @Override
+ public boolean addAllByteArray(Collection<byte[]> c) {
+ boolean ret = list.addAll(c);
modCount++;
return ret;
}
@@ -122,6 +167,7 @@ public class LazyStringArrayList extends AbstractList<String>
return asString(o);
}
+ @Override
public void clear() {
list.clear();
modCount++;
@@ -132,24 +178,194 @@ public class LazyStringArrayList extends AbstractList<String>
list.add(element);
modCount++;
}
+
+ // @Override
+ public void add(byte[] element) {
+ list.add(element);
+ modCount++;
+ }
// @Override
public ByteString getByteString(int index) {
Object o = list.get(index);
- if (o instanceof String) {
- ByteString b = ByteString.copyFromUtf8((String) o);
+ ByteString b = asByteString(o);
+ if (b != o) {
list.set(index, b);
- return b;
- } else {
- return (ByteString) o;
}
+ return b;
+ }
+
+ // @Override
+ public byte[] getByteArray(int index) {
+ Object o = list.get(index);
+ byte[] b = asByteArray(o);
+ if (b != o) {
+ list.set(index, b);
+ }
+ return b;
}
- private String asString(Object o) {
+ // @Override
+ public void set(int index, ByteString s) {
+ list.set(index, s);
+ }
+
+ // @Override
+ public void set(int index, byte[] s) {
+ list.set(index, s);
+ }
+
+
+ private static String asString(Object o) {
if (o instanceof String) {
return (String) o;
- } else {
+ } else if (o instanceof ByteString) {
return ((ByteString) o).toStringUtf8();
+ } else {
+ return Internal.toStringUtf8((byte[]) o);
+ }
+ }
+
+ private static ByteString asByteString(Object o) {
+ if (o instanceof ByteString) {
+ return (ByteString) o;
+ } else if (o instanceof String) {
+ return ByteString.copyFromUtf8((String) o);
+ } else {
+ return ByteString.copyFrom((byte[]) o);
}
}
+
+ private static byte[] asByteArray(Object o) {
+ if (o instanceof byte[]) {
+ return (byte[]) o;
+ } else if (o instanceof String) {
+ return Internal.toByteArray((String) o);
+ } else {
+ return ((ByteString) o).toByteArray();
+ }
+ }
+
+ // @Override
+ public List<?> getUnderlyingElements() {
+ return Collections.unmodifiableList(list);
+ }
+
+ // @Override
+ public void mergeFrom(LazyStringList other) {
+ for (Object o : other.getUnderlyingElements()) {
+ if (o instanceof byte[]) {
+ byte[] b = (byte[]) o;
+ // Byte array's content is mutable so they should be copied rather than
+ // shared when merging from one message to another.
+ list.add(Arrays.copyOf(b, b.length));
+ } else {
+ list.add(o);
+ }
+ }
+ }
+
+ private static class ByteArrayListView extends AbstractList<byte[]>
+ implements RandomAccess {
+ private final List<Object> list;
+
+ ByteArrayListView(List<Object> list) {
+ this.list = list;
+ }
+
+ @Override
+ public byte[] get(int index) {
+ Object o = list.get(index);
+ byte[] b = asByteArray(o);
+ if (b != o) {
+ list.set(index, b);
+ }
+ return b;
+ }
+
+ @Override
+ public int size() {
+ return list.size();
+ }
+
+ @Override
+ public byte[] set(int index, byte[] s) {
+ Object o = list.set(index, s);
+ modCount++;
+ return asByteArray(o);
+ }
+
+ @Override
+ public void add(int index, byte[] s) {
+ list.add(index, s);
+ modCount++;
+ }
+
+ @Override
+ public byte[] remove(int index) {
+ Object o = list.remove(index);
+ modCount++;
+ return asByteArray(o);
+ }
+ }
+
+ // @Override
+ public List<byte[]> asByteArrayList() {
+ return new ByteArrayListView(list);
+ }
+
+ private static class ByteStringListView extends AbstractList<ByteString>
+ implements RandomAccess {
+ private final List<Object> list;
+
+ ByteStringListView(List<Object> list) {
+ this.list = list;
+ }
+
+ @Override
+ public ByteString get(int index) {
+ Object o = list.get(index);
+ ByteString b = asByteString(o);
+ if (b != o) {
+ list.set(index, b);
+ }
+ return b;
+ }
+
+ @Override
+ public int size() {
+ return list.size();
+ }
+
+ @Override
+ public ByteString set(int index, ByteString s) {
+ Object o = list.set(index, s);
+ modCount++;
+ return asByteString(o);
+ }
+
+ @Override
+ public void add(int index, ByteString s) {
+ list.add(index, s);
+ modCount++;
+ }
+
+ @Override
+ public ByteString remove(int index) {
+ Object o = list.remove(index);
+ modCount++;
+ return asByteString(o);
+ }
+ }
+
+ // @Override
+ public List<ByteString> asByteStringList() {
+ return new ByteStringListView(list);
+ }
+
+ // @Override
+ public LazyStringList getUnmodifiableView() {
+ return new UnmodifiableLazyStringList(this);
+ }
+
}
diff --git a/java/src/main/java/com/google/protobuf/LazyStringList.java b/java/src/main/java/com/google/protobuf/LazyStringList.java
index 97139ca6..235126b6 100644
--- a/java/src/main/java/com/google/protobuf/LazyStringList.java
+++ b/java/src/main/java/com/google/protobuf/LazyStringList.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,25 +30,22 @@
package com.google.protobuf;
+import java.util.Collection;
import java.util.List;
/**
- * An interface extending List&lt;String&gt; that also provides access to the
- * items of the list as UTF8-encoded ByteString objects. This is used by the
- * protocol buffer implementation to support lazily converting bytes parsed
- * over the wire to String objects until needed and also increases the
+ * An interface extending {@code List<String>} that also provides access to the
+ * items of the list as UTF8-encoded ByteString or byte[] objects. This is
+ * used by the protocol buffer implementation to support lazily converting bytes
+ * parsed over the wire to String objects until needed and also increases the
* efficiency of serialization if the String was never requested as the
- * ByteString is already cached.
- * <p>
- * This only adds additional methods that are required for the use in the
- * protocol buffer code in order to be able successfuly round trip byte arrays
- * through parsing and serialization without conversion to strings. It's not
- * attempting to support the functionality of say List&ltByteString&gt, hence
- * why only these two very specific methods are added.
+ * ByteString or byte[] is already cached. The ByteString methods are used in
+ * immutable API only and byte[] methods used in mutable API only for they use
+ * different representations for string/bytes fields.
*
* @author jonp@google.com (Jon Perlow)
*/
-public interface LazyStringList extends List<String> {
+public interface LazyStringList extends ProtocolStringList {
/**
* Returns the element at the specified position in this list as a ByteString.
@@ -56,9 +53,19 @@ public interface LazyStringList extends List<String> {
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException if the index is out of range
- * (<tt>index &lt; 0 || index &gt;= size()</tt>)
+ * ({@code index < 0 || index >= size()})
*/
ByteString getByteString(int index);
+
+ /**
+ * Returns the element at the specified position in this list as byte[].
+ *
+ * @param index index of the element to return
+ * @return the element at the specified position in this list
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * ({@code index < 0 || index >= size()})
+ */
+ byte[] getByteArray(int index);
/**
* Appends the specified element to the end of this list (optional
@@ -69,4 +76,88 @@ public interface LazyStringList extends List<String> {
* is not supported by this list
*/
void add(ByteString element);
+
+ /**
+ * Appends the specified element to the end of this list (optional
+ * operation).
+ *
+ * @param element element to be appended to this list
+ * @throws UnsupportedOperationException if the <tt>add</tt> operation
+ * is not supported by this list
+ */
+ void add(byte[] element);
+
+ /**
+ * Replaces the element at the specified position in this list with the
+ * specified element (optional operation).
+ *
+ * @param index index of the element to replace
+ * @param element the element to be stored at the specified position
+ * @throws UnsupportedOperationException if the <tt>set</tt> operation
+ * is not supported by this list
+ * IndexOutOfBoundsException if the index is out of range
+ * ({@code index < 0 || index >= size()})
+ */
+ void set(int index, ByteString element);
+
+ /**
+ * Replaces the element at the specified position in this list with the
+ * specified element (optional operation).
+ *
+ * @param index index of the element to replace
+ * @param element the element to be stored at the specified position
+ * @throws UnsupportedOperationException if the <tt>set</tt> operation
+ * is not supported by this list
+ * IndexOutOfBoundsException if the index is out of range
+ * ({@code index < 0 || index >= size()})
+ */
+ void set(int index, byte[] element);
+
+ /**
+ * Appends all elements in the specified ByteString collection to the end of
+ * this list.
+ *
+ * @param c collection whose elements are to be added to this list
+ * @return true if this list changed as a result of the call
+ * @throws UnsupportedOperationException if the <tt>addAllByteString</tt>
+ * operation is not supported by this list
+ */
+ boolean addAllByteString(Collection<? extends ByteString> c);
+
+ /**
+ * Appends all elements in the specified byte[] collection to the end of
+ * this list.
+ *
+ * @param c collection whose elements are to be added to this list
+ * @return true if this list changed as a result of the call
+ * @throws UnsupportedOperationException if the <tt>addAllByteArray</tt>
+ * operation is not supported by this list
+ */
+ boolean addAllByteArray(Collection<byte[]> c);
+
+ /**
+ * Returns an unmodifiable List of the underlying elements, each of which is
+ * either a {@code String} or its equivalent UTF-8 encoded {@code ByteString}
+ * or byte[]. It is an error for the caller to modify the returned
+ * List, and attempting to do so will result in an
+ * {@link UnsupportedOperationException}.
+ */
+ List<?> getUnderlyingElements();
+
+ /**
+ * Merges all elements from another LazyStringList into this one. This method
+ * differs from {@link #addAll(Collection)} on that underlying byte arrays are
+ * copied instead of reference shared. Immutable API doesn't need to use this
+ * method as byte[] is not used there at all.
+ */
+ void mergeFrom(LazyStringList other);
+
+ /**
+ * Returns a mutable view of this list. Changes to the view will be made into
+ * the original list. This method is used in mutable API only.
+ */
+ List<byte[]> asByteArrayList();
+
+ /** Returns an unmodifiable view of the list. */
+ LazyStringList getUnmodifiableView();
}
diff --git a/java/src/main/java/com/google/protobuf/LiteralByteString.java b/java/src/main/java/com/google/protobuf/LiteralByteString.java
new file mode 100644
index 00000000..6893ddf1
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/LiteralByteString.java
@@ -0,0 +1,377 @@
+// 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.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * This class implements a {@link com.google.protobuf.ByteString} backed by a
+ * single array of bytes, contiguous in memory. It supports substring by
+ * pointing to only a sub-range of the underlying byte array, meaning that a
+ * substring will reference the full byte-array of the string it's made from,
+ * exactly as with {@link String}.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+class LiteralByteString extends ByteString {
+
+ private static final long serialVersionUID = 1L;
+
+ protected final byte[] bytes;
+
+ /**
+ * Creates a {@code LiteralByteString} backed by the given array, without
+ * copying.
+ *
+ * @param bytes array to wrap
+ */
+ LiteralByteString(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ @Override
+ public byte byteAt(int index) {
+ // Unlike most methods in this class, this one is a direct implementation
+ // ignoring the potential offset because we need to do range-checking in the
+ // substring case anyway.
+ return bytes[index];
+ }
+
+ @Override
+ public int size() {
+ return bytes.length;
+ }
+
+ // =================================================================
+ // ByteString -> substring
+
+ @Override
+ public ByteString substring(int beginIndex, int endIndex) {
+ if (beginIndex < 0) {
+ throw new IndexOutOfBoundsException(
+ "Beginning index: " + beginIndex + " < 0");
+ }
+ if (endIndex > size()) {
+ throw new IndexOutOfBoundsException("End index: " + endIndex + " > " +
+ size());
+ }
+ int substringLength = endIndex - beginIndex;
+ if (substringLength < 0) {
+ throw new IndexOutOfBoundsException(
+ "Beginning index larger than ending index: " + beginIndex + ", "
+ + endIndex);
+ }
+
+ ByteString result;
+ if (substringLength == 0) {
+ result = ByteString.EMPTY;
+ } else {
+ result = new BoundedByteString(bytes, getOffsetIntoBytes() + beginIndex,
+ substringLength);
+ }
+ return result;
+ }
+
+ // =================================================================
+ // ByteString -> byte[]
+
+ @Override
+ protected void copyToInternal(byte[] target, int sourceOffset,
+ int targetOffset, int numberToCopy) {
+ // Optimized form, not for subclasses, since we don't call
+ // getOffsetIntoBytes() or check the 'numberToCopy' parameter.
+ System.arraycopy(bytes, sourceOffset, target, targetOffset, numberToCopy);
+ }
+
+ @Override
+ public void copyTo(ByteBuffer target) {
+ target.put(bytes, getOffsetIntoBytes(), size()); // Copies bytes
+ }
+
+ @Override
+ public ByteBuffer asReadOnlyByteBuffer() {
+ ByteBuffer byteBuffer =
+ ByteBuffer.wrap(bytes, getOffsetIntoBytes(), size());
+ return byteBuffer.asReadOnlyBuffer();
+ }
+
+ @Override
+ public List<ByteBuffer> asReadOnlyByteBufferList() {
+ // Return the ByteBuffer generated by asReadOnlyByteBuffer() as a singleton
+ List<ByteBuffer> result = new ArrayList<ByteBuffer>(1);
+ result.add(asReadOnlyByteBuffer());
+ return result;
+ }
+
+ @Override
+ public void writeTo(OutputStream outputStream) throws IOException {
+ outputStream.write(toByteArray());
+ }
+
+ @Override
+ void writeToInternal(OutputStream outputStream, int sourceOffset,
+ int numberToWrite) throws IOException {
+ outputStream.write(bytes, getOffsetIntoBytes() + sourceOffset,
+ numberToWrite);
+ }
+
+ @Override
+ public String toString(String charsetName)
+ throws UnsupportedEncodingException {
+ // Optimize for empty strings, but ensure we don't silently ignore invalid
+ // encodings.
+ return size() == 0 && UTF_8.equals(charsetName)
+ ? ""
+ : new String(bytes, getOffsetIntoBytes(), size(), charsetName);
+ }
+
+ // =================================================================
+ // UTF-8 decoding
+
+ @Override
+ public boolean isValidUtf8() {
+ int offset = getOffsetIntoBytes();
+ return Utf8.isValidUtf8(bytes, offset, offset + size());
+ }
+
+ @Override
+ protected int partialIsValidUtf8(int state, int offset, int length) {
+ int index = getOffsetIntoBytes() + offset;
+ return Utf8.partialIsValidUtf8(state, bytes, index, index + length);
+ }
+
+ // =================================================================
+ // equals() and hashCode()
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof ByteString)) {
+ return false;
+ }
+
+ if (size() != ((ByteString) other).size()) {
+ return false;
+ }
+ if (size() == 0) {
+ return true;
+ }
+
+ 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);
+ } else {
+ throw new IllegalArgumentException(
+ "Has a new type of ByteString been created? Found "
+ + other.getClass());
+ }
+ }
+
+ /**
+ * Check equality of the substring of given length of this object starting at
+ * zero with another {@code LiteralByteString} substring starting at offset.
+ *
+ * @param other what to compare a substring in
+ * @param offset offset into other
+ * @param length number of bytes to compare
+ * @return true for equality of substrings, else false.
+ */
+ boolean equalsRange(LiteralByteString other, int offset, int length) {
+ if (length > other.size()) {
+ throw new IllegalArgumentException(
+ "Length too large: " + length + size());
+ }
+ if (offset + length > other.size()) {
+ throw new IllegalArgumentException(
+ "Ran off end of other: " + offset + ", " + length + ", " +
+ other.size());
+ }
+
+ byte[] thisBytes = bytes;
+ byte[] otherBytes = other.bytes;
+ int thisLimit = getOffsetIntoBytes() + length;
+ for (int thisIndex = getOffsetIntoBytes(), otherIndex =
+ other.getOffsetIntoBytes() + offset;
+ (thisIndex < thisLimit); ++thisIndex, ++otherIndex) {
+ if (thisBytes[thisIndex] != otherBytes[otherIndex]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Cached hash value. Intentionally accessed via a data race, which
+ * is safe because of the Java Memory Model's "no out-of-thin-air values"
+ * guarantees for ints.
+ */
+ private int hash = 0;
+
+ /**
+ * Compute the hashCode using the traditional algorithm from {@link
+ * ByteString}.
+ *
+ * @return hashCode value
+ */
+ @Override
+ public int hashCode() {
+ int h = hash;
+
+ if (h == 0) {
+ int size = size();
+ h = partialHash(size, 0, size);
+ if (h == 0) {
+ h = 1;
+ }
+ hash = h;
+ }
+ return h;
+ }
+
+ @Override
+ protected int peekCachedHashCode() {
+ return hash;
+ }
+
+ @Override
+ protected int partialHash(int h, int offset, int length) {
+ return hashCode(h, bytes, getOffsetIntoBytes() + offset, length);
+ }
+
+ static int hashCode(int h, byte[] bytes, int offset, int length) {
+ for (int i = offset; i < offset + length; i++) {
+ h = h * 31 + bytes[i];
+ }
+ return h;
+ }
+
+ static int hashCode(byte[] bytes) {
+ int h = hashCode(bytes.length, bytes, 0, bytes.length);
+ return h == 0 ? 1 : h;
+ }
+
+ // =================================================================
+ // Input stream
+
+ @Override
+ public InputStream newInput() {
+ return new ByteArrayInputStream(bytes, getOffsetIntoBytes(),
+ size()); // No copy
+ }
+
+ @Override
+ public CodedInputStream newCodedInput() {
+ // We trust CodedInputStream not to modify the bytes, or to give anyone
+ // else access to them.
+ return CodedInputStream.newInstance(this);
+ }
+
+ // =================================================================
+ // ByteIterator
+
+ @Override
+ public ByteIterator iterator() {
+ return new LiteralByteIterator();
+ }
+
+ private class LiteralByteIterator implements ByteIterator {
+ private int position;
+ private final int limit;
+
+ private LiteralByteIterator() {
+ position = 0;
+ limit = size();
+ }
+
+ public boolean hasNext() {
+ return (position < limit);
+ }
+
+ public Byte next() {
+ // Boxing calls Byte.valueOf(byte), which does not instantiate.
+ return nextByte();
+ }
+
+ public byte nextByte() {
+ try {
+ return bytes[position++];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new NoSuchElementException(e.getMessage());
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ // =================================================================
+ // Internal methods
+
+ @Override
+ protected int getTreeDepth() {
+ return 0;
+ }
+
+ @Override
+ protected boolean isBalanced() {
+ return true;
+ }
+
+ /**
+ * Offset into {@code bytes[]} to use, non-zero for substrings.
+ *
+ * @return always 0 for this class
+ */
+ protected int getOffsetIntoBytes() {
+ return 0;
+ }
+}
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..31414bb4
--- /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<K, V> extends AbstractMessage {
+ private static class Metadata<K, V> {
+ public final Descriptor descriptor;
+ public final MapEntry<K, V> defaultInstance;
+ public final AbstractParser<MapEntry<K, V>> parser;
+
+ public Metadata(
+ final Descriptor descriptor, final MapEntry<K, V> defaultInstance) {
+ this.descriptor = descriptor;
+ this.defaultInstance = defaultInstance;
+ final Metadata<K, V> thisMetadata = this;
+ this.parser = new AbstractParser<MapEntry<K, V>>() {
+ private final Parser<MapEntryLite<K, V>> dataParser =
+ defaultInstance.data.getParserForType();
+ @Override
+ public MapEntry<K, V> parsePartialFrom(
+ CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ MapEntryLite<K, V> data =
+ dataParser.parsePartialFrom(input, extensionRegistry);
+ return new MapEntry<K, V>(thisMetadata, data);
+ }
+
+ };
+ }
+ }
+
+ private final Metadata<K, V> metadata;
+ private final MapEntryLite<K, V> 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<K, V>(descriptor, this);
+ }
+
+ /** Create a new MapEntry message. */
+ private MapEntry(Metadata<K, V> metadata, MapEntryLite<K, V> 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 <K, V> MapEntry<K, V> newDefaultInstance(
+ Descriptor descriptor,
+ WireFormat.FieldType keyType, K defaultKey,
+ WireFormat.FieldType valueType, V defaultValue) {
+ return new MapEntry<K, V>(
+ 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<MapEntry<K, V>> getParserForType() {
+ return metadata.parser;
+ }
+
+ @Override
+ public Builder<K, V> newBuilderForType() {
+ return new Builder<K, V>(metadata);
+ }
+
+ @Override
+ public Builder<K, V> toBuilder() {
+ return new Builder<K, V>(metadata, data);
+ }
+
+ @Override
+ public MapEntry<K, V> getDefaultInstanceForType() {
+ return metadata.defaultInstance;
+ }
+
+ @Override
+ public Descriptor getDescriptorForType() {
+ return metadata.descriptor;
+ }
+
+ @Override
+ public Map<FieldDescriptor, Object> getAllFields() {
+ final TreeMap<FieldDescriptor, Object> result =
+ new TreeMap<FieldDescriptor, Object>();
+ 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<K, V>
+ extends AbstractMessage.Builder<Builder<K, V>> {
+ private final Metadata<K, V> metadata;
+ private MapEntryLite<K, V> data;
+ private MapEntryLite.Builder<K, V> dataBuilder;
+
+ private Builder(Metadata<K, V> metadata) {
+ this.metadata = metadata;
+ this.data = metadata.defaultInstance.data;
+ this.dataBuilder = null;
+ }
+
+ private Builder(Metadata<K, V> metadata, MapEntryLite<K, V> 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<K, V> setKey(K key) {
+ ensureMutable();
+ dataBuilder.setKey(key);
+ return this;
+ }
+
+ public Builder<K, V> clearKey() {
+ ensureMutable();
+ dataBuilder.clearKey();
+ return this;
+ }
+
+ public Builder<K, V> setValue(V value) {
+ ensureMutable();
+ dataBuilder.setValue(value);
+ return this;
+ }
+
+ public Builder<K, V> clearValue() {
+ ensureMutable();
+ dataBuilder.clearValue();
+ return this;
+ }
+
+ @Override
+ public MapEntry<K, V> build() {
+ MapEntry<K, V> result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ @Override
+ public MapEntry<K, V> buildPartial() {
+ if (dataBuilder != null) {
+ data = dataBuilder.buildPartial();
+ dataBuilder = null;
+ }
+ return new MapEntry<K, V>(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<K, V> 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<K, V> clearField(FieldDescriptor field) {
+ checkFieldDescriptor(field);
+ if (field.getNumber() == 1) {
+ clearKey();
+ } else {
+ clearValue();
+ }
+ return this;
+ }
+
+ @Override
+ public Builder<K, V> setRepeatedField(FieldDescriptor field, int index,
+ Object value) {
+ throw new RuntimeException(
+ "There is no repeated field in a map entry message.");
+ }
+
+ @Override
+ public Builder<K, V> addRepeatedField(FieldDescriptor field, Object value) {
+ throw new RuntimeException(
+ "There is no repeated field in a map entry message.");
+ }
+
+ @Override
+ public Builder<K, V> setUnknownFields(UnknownFieldSet unknownFields) {
+ // Unknown fields are discarded for MapEntry message.
+ return this;
+ }
+
+ @Override
+ public MapEntry<K, V> getDefaultInstanceForType() {
+ return metadata.defaultInstance;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ if (dataBuilder != null) {
+ return dataBuilder.isInitialized();
+ } else {
+ return data.isInitialized();
+ }
+ }
+
+ @Override
+ public Map<FieldDescriptor, Object> getAllFields() {
+ final TreeMap<FieldDescriptor, Object> result =
+ new TreeMap<FieldDescriptor, Object>();
+ 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<K, V> clone() {
+ if (dataBuilder == null) {
+ return new Builder<K, V>(metadata, data);
+ } else {
+ return new Builder<K, V>(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<K, V> extends AbstractMessageLite {
+ private static class Metadata<K, V> {
+ public final MapEntryLite<K, V> defaultInstance;
+ public final WireFormat.FieldType keyType;
+ public final WireFormat.FieldType valueType;
+ public final Parser<MapEntryLite<K, V>> parser;
+ public Metadata(
+ MapEntryLite<K, V> defaultInstance,
+ WireFormat.FieldType keyType,
+ WireFormat.FieldType valueType) {
+ this.defaultInstance = defaultInstance;
+ this.keyType = keyType;
+ this.valueType = valueType;
+ final Metadata<K, V> finalThis = this;
+ this.parser = new AbstractParser<MapEntryLite<K, V>>() {
+ @Override
+ public MapEntryLite<K, V> parsePartialFrom(
+ CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return new MapEntryLite<K, V>(finalThis, input, extensionRegistry);
+ }
+ };
+ }
+ }
+
+ private static final int KEY_FIELD_NUMBER = 1;
+ private static final int VALUE_FIELD_NUMBER = 2;
+
+ private final Metadata<K, V> 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<K, V>(this, keyType, valueType);
+ this.key = defaultKey;
+ this.value = defaultValue;
+ }
+
+ /** Creates a new MapEntryLite message. */
+ private MapEntryLite(Metadata<K, V> 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 <K, V> MapEntryLite<K, V> newDefaultInstance(
+ WireFormat.FieldType keyType, K defaultKey,
+ WireFormat.FieldType valueType, V defaultValue) {
+ return new MapEntryLite<K, V>(
+ 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<K, V> 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> 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<MapEntryLite<K, V>> getParserForType() {
+ return metadata.parser;
+ }
+
+ @Override
+ public Builder<K, V> newBuilderForType() {
+ return new Builder<K, V>(metadata);
+ }
+
+ @Override
+ public Builder<K, V> toBuilder() {
+ return new Builder<K, V>(metadata, key, value);
+ }
+
+ @Override
+ public MapEntryLite<K, V> 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<K, V>
+ extends AbstractMessageLite.Builder<Builder<K, V>> {
+ private final Metadata<K, V> metadata;
+ private K key;
+ private V value;
+
+ private Builder(Metadata<K, V> 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<K, V> setKey(K key) {
+ this.key = key;
+ return this;
+ }
+
+ public Builder<K, V> setValue(V value) {
+ this.value = value;
+ return this;
+ }
+
+ public Builder<K, V> clearKey() {
+ this.key = metadata.defaultInstance.key;
+ return this;
+ }
+
+ public Builder<K, V> clearValue() {
+ this.value = metadata.defaultInstance.value;
+ return this;
+ }
+
+ @Override
+ public Builder<K, V> clear() {
+ this.key = metadata.defaultInstance.key;
+ this.value = metadata.defaultInstance.value;
+ return this;
+ }
+
+ @Override
+ public MapEntryLite<K, V> build() {
+ MapEntryLite<K, V> result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ @Override
+ public MapEntryLite<K, V> buildPartial() {
+ return new MapEntryLite<K, V>(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<K, V> metadata, K key, V value) {
+ this.metadata = metadata;
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public Builder<K, V> clone() {
+ return new Builder<K, V>(metadata, key, value);
+ }
+
+ @Override
+ public Builder<K, V> mergeFrom(
+ CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ MapEntryLite<K, V> entry =
+ new MapEntryLite<K, V>(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..82906d37
--- /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<K, V> {
+ /**
+ * 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<K, V> mapData;
+ private List<Message> listData;
+
+ // Convert between a map entry Message and a key-value pair.
+ private static interface Converter<K, V> {
+ Message convertKeyAndValueToMessage(K key, V value);
+ void convertMessageToKeyAndValue(Message message, Map<K, V> map);
+
+ Message getMessageDefaultInstance();
+ }
+
+ private static class ImmutableMessageConverter<K, V> implements Converter<K, V> {
+ private final MapEntry<K, V> defaultEntry;
+ public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) {
+ this.defaultEntry = defaultEntry;
+ }
+
+ public Message convertKeyAndValueToMessage(K key, V value) {
+ return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial();
+ }
+
+ public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
+ MapEntry<K, V> entry = (MapEntry<K, V>) message;
+ map.put(entry.getKey(), entry.getValue());
+ }
+
+ public Message getMessageDefaultInstance() {
+ return defaultEntry;
+ }
+ }
+
+
+ private final Converter<K, V> converter;
+
+ private MapField(
+ Converter<K, V> converter,
+ StorageMode mode,
+ Map<K, V> mapData,
+ List<Message> listData) {
+ this.converter = converter;
+ this.mode = mode;
+ this.mapData = mapData;
+ this.listData = listData;
+ }
+
+ private MapField(
+ MapEntry<K, V> defaultEntry,
+ StorageMode mode,
+ Map<K, V> mapData,
+ List<Message> listData) {
+ this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData, listData);
+ }
+
+
+ /** Returns an immutable empty MapField. */
+ public static <K, V> MapField<K, V> emptyMapField(
+ MapEntry<K, V> defaultEntry) {
+ return new MapField<K, V>(
+ defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap(), null);
+ }
+
+
+ /** Creates a new mutable empty MapField. */
+ public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) {
+ return new MapField<K, V>(
+ defaultEntry, StorageMode.MAP, new HashMap<K, V>(), null);
+ }
+
+
+ private Message convertKeyAndValueToMessage(K key, V value) {
+ return converter.convertKeyAndValueToMessage(key, value);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
+ converter.convertMessageToKeyAndValue(message, map);
+ }
+
+ private List<Message> convertMapToList(Map<K, V> mapData) {
+ List<Message> listData = new ArrayList<Message>();
+ for (Map.Entry<K, V> entry : mapData.entrySet()) {
+ listData.add(
+ convertKeyAndValueToMessage(
+ entry.getKey(), entry.getValue()));
+ }
+ return listData;
+ }
+
+ private Map<K, V> convertListToMap(List<Message> listData) {
+ Map<K, V> mapData = new HashMap<K, V>();
+ for (Message item : listData) {
+ convertMessageToKeyAndValue(item, mapData);
+ }
+ return mapData;
+ }
+
+ /** Returns the content of this MapField as a read-only Map. */
+ public Map<K, V> 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<K, V> getMutableMap() {
+ if (mode != StorageMode.MAP) {
+ if (mode == StorageMode.LIST) {
+ mapData = convertListToMap(listData);
+ }
+ listData = null;
+ mode = StorageMode.MAP;
+ }
+ return mapData;
+ }
+
+ public void mergeFrom(MapField<K, V> other) {
+ getMutableMap().putAll(MapFieldLite.copy(other.getMap()));
+ }
+
+ public void clear() {
+ mapData = new HashMap<K, V>();
+ mode = StorageMode.MAP;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof MapField)) {
+ return false;
+ }
+ MapField<K, V> other = (MapField<K, V>) object;
+ return MapFieldLite.<K, V>equals(getMap(), other.getMap());
+ }
+
+ @Override
+ public int hashCode() {
+ return MapFieldLite.<K, V>calculateHashCodeForMap(getMap());
+ }
+
+ /** Returns a deep copy of this MapField. */
+ public MapField<K, V> copy() {
+ return new MapField<K, V>(
+ converter, StorageMode.MAP, MapFieldLite.copy(getMap()), null);
+ }
+
+ /** Gets the content of this MapField as a read-only List. */
+ List<Message> 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<Message> 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..7f94c690
--- /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<K, V> {
+ private Map<K, V> mapData;
+
+ private MapFieldLite(Map<K, V> 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 <K, V> MapFieldLite<K, V> emptyMapField() {
+ return (MapFieldLite<K, V>) EMPTY_MAP_FIELD;
+ }
+
+ /** Creates a new MapFieldLite instance. */
+ public static <K, V> MapFieldLite<K, V> newMapField() {
+ return new MapFieldLite<K, V>(new HashMap<K, V>());
+ }
+
+ /** Gets the content of this MapField as a read-only Map. */
+ public Map<K, V> getMap() {
+ return Collections.unmodifiableMap(mapData);
+ }
+
+ /** Gets a mutable Map view of this MapField. */
+ public Map<K, V> getMutableMap() {
+ return mapData;
+ }
+
+ public void mergeFrom(MapFieldLite<K, V> 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 <K, V> boolean equals(Map<K, V> a, Map<K, V> b) {
+ if (a == b) {
+ return true;
+ }
+ if (a.size() != b.size()) {
+ return false;
+ }
+ for (Map.Entry<K, V> 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<K, V> other = (MapFieldLite<K, V>) 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 <K, V> int calculateHashCodeForMap(Map<K, V> a) {
+ int result = 0;
+ for (Map.Entry<K, V> 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 <K, V> Map<K, V> copy(Map<K, V> map) {
+ Map<K, V> result = new HashMap<K, V>();
+ for (Map.Entry<K, V> entry : map.entrySet()) {
+ result.put(entry.getKey(), (V) copy(entry.getValue()));
+ }
+ return result;
+ }
+
+ /** Returns a deep copy of this map field. */
+ public MapFieldLite<K, V> copy() {
+ return new MapFieldLite<K, V>(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 67c4148e..fa0265e2 100644
--- a/java/src/main/java/com/google/protobuf/Message.java
+++ b/java/src/main/java/com/google/protobuf/Message.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -50,25 +50,29 @@ import java.util.Map;
*/
public interface Message extends MessageLite, MessageOrBuilder {
+ // (From MessageLite, re-declared here only for return type covariance.)
+ Parser<? extends Message> getParserForType();
+
+
// -----------------------------------------------------------------
// Comparison and hashing
/**
* Compares the specified object with this message for equality. Returns
- * <tt>true</tt> if the given object is a message of the same type (as
+ * {@code true} if the given object is a message of the same type (as
* defined by {@code getDescriptorForType()}) and has identical values for
* all of its fields. Subclasses must implement this; inheriting
* {@code Object.equals()} is incorrect.
*
* @param other object to be compared for equality with this message
- * @return <tt>true</tt> if the specified object is equal to this message
+ * @return {@code true} if the specified object is equal to this message
*/
@Override
boolean equals(Object other);
/**
* Returns the hash code value for this message. The hash code of a message
- * should mix the message's type (object identity of the decsriptor) with its
+ * should mix the message's type (object identity of the descriptor) with its
* contents (known and unknown field values). Subclasses must implement this;
* inheriting {@code Object.hashCode()} is incorrect.
*
@@ -83,7 +87,8 @@ public interface Message extends MessageLite, MessageOrBuilder {
/**
* Converts the message to a string in protocol buffer text format. This is
- * just a trivial wrapper around {@link TextFormat#printToString(Message)}.
+ * just a trivial wrapper around {@link
+ * TextFormat#printToString(MessageOrBuilder)}.
*/
@Override
String toString();
@@ -145,6 +150,43 @@ public interface Message extends MessageLite, MessageOrBuilder {
Builder newBuilderForField(Descriptors.FieldDescriptor field);
/**
+ * Get a nested builder instance for the given field.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * NOTE: implementations that do not support nested builders will throw
+ * <code>UnsupportedOperationException</code>.
+ */
+ Builder getFieldBuilder(Descriptors.FieldDescriptor field);
+
+ /**
+ * Get a nested builder instance for the given repeated field instance.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * NOTE: implementations that do not support nested builders will throw
+ * <code>UnsupportedOperationException</code>.
+ */
+ 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
* {@link Message#getField(Descriptors.FieldDescriptor)} would return.
@@ -158,6 +200,12 @@ public interface Message extends MessageLite, MessageOrBuilder {
Builder clearField(Descriptors.FieldDescriptor field);
/**
+ * Clears the oneof. This is exactly equivalent to calling the generated
+ * "clear" accessor method corresponding to the oneof.
+ */
+ Builder clearOneof(Descriptors.OneofDescriptor oneof);
+
+ /**
* Sets an element of a repeated field to the given value. The value must
* be of the correct type for this field, i.e. the same type that
* {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would
diff --git a/java/src/main/java/com/google/protobuf/MessageLite.java b/java/src/main/java/com/google/protobuf/MessageLite.java
index 31b8256e..798b7943 100644
--- a/java/src/main/java/com/google/protobuf/MessageLite.java
+++ b/java/src/main/java/com/google/protobuf/MessageLite.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -79,6 +79,12 @@ public interface MessageLite extends MessageLiteOrBuilder {
*/
int getSerializedSize();
+
+ /**
+ * Gets the parser for a message of the same type as this message.
+ */
+ Parser<? extends MessageLite> getParserForType();
+
// -----------------------------------------------------------------
// Convenience methods.
@@ -122,6 +128,7 @@ public interface MessageLite extends MessageLiteOrBuilder {
*/
void writeDelimitedTo(OutputStream output) throws IOException;
+
// =================================================================
// Builders
@@ -144,11 +151,8 @@ public interface MessageLite extends MessageLiteOrBuilder {
Builder clear();
/**
- * Construct the final message. Once this is called, the Builder is no
- * longer valid, and calling any other method will result in undefined
- * behavior and may throw a NullPointerException. If you need to continue
- * working with the builder after calling {@code build()}, {@code clone()}
- * it first.
+ * Constructs the message based on the state of the Builder. Subsequent
+ * changes to the Builder will not affect the returned message.
* @throws UninitializedMessageException The message is missing one or more
* required fields (i.e. {@link #isInitialized()} returns false).
* Use {@link #buildPartial()} to bypass this check.
@@ -158,11 +162,7 @@ public interface MessageLite extends MessageLiteOrBuilder {
/**
* Like {@link #build()}, but does not throw an exception if the message
* is missing required fields. Instead, a partial message is returned.
- * Once this is called, the Builder is no longer valid, and calling any
- * will result in undefined behavior and may throw a NullPointerException.
- *
- * If you need to continue working with the builder after calling
- * {@code buildPartial()}, {@code clone()} it first.
+ * Subsequent changes to the Builder will not affect the returned message.
*/
MessageLite buildPartial();
@@ -174,7 +174,7 @@ public interface MessageLite extends MessageLiteOrBuilder {
/**
* Parses a message of this type from the input and merges it with this
- * message, as if using {@link Builder#mergeFrom(MessageLite)}.
+ * message.
*
* <p>Warning: This does not verify that all required fields are present in
* the input message. If you call {@link #build()} without setting all
@@ -184,11 +184,6 @@ public interface MessageLite extends MessageLiteOrBuilder {
* <ul>
* <li>Call {@link #isInitialized()} to verify that all required fields
* are set before building.
- * <li>Parse the message separately using one of the static
- * {@code parseFrom} methods, then use {@link #mergeFrom(MessageLite)}
- * to merge it with this one. {@code parseFrom} will throw an
- * {@link InvalidProtocolBufferException} (an {@code IOException})
- * if some required fields are missing.
* <li>Use {@code buildPartial()} to build, which ignores missing
* required fields.
* </ul>
@@ -225,7 +220,7 @@ public interface MessageLite extends MessageLiteOrBuilder {
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
- * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
*
* @return this
*/
@@ -255,7 +250,7 @@ public interface MessageLite extends MessageLiteOrBuilder {
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
- * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
*
* @return this
*/
@@ -266,7 +261,7 @@ public interface MessageLite extends MessageLiteOrBuilder {
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
- * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
*
* @return this
*/
@@ -293,7 +288,7 @@ public interface MessageLite extends MessageLiteOrBuilder {
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
- * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
*
* @return this
*/
@@ -308,9 +303,9 @@ public interface MessageLite extends MessageLiteOrBuilder {
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
* this format.
*
- * @returns True if successful, or false if the stream is at EOF when the
- * method starts. Any other error (including reaching EOF during
- * parsing) will cause an exception to be thrown.
+ * @return True if successful, or false if the stream is at EOF when the
+ * method starts. Any other error (including reaching EOF during
+ * parsing) will cause an exception to be thrown.
*/
boolean mergeDelimitedFrom(InputStream input)
throws IOException;
diff --git a/java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java b/java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java
index 7cc72e9c..818386ce 100644
--- a/java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java
+++ b/java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -52,6 +52,8 @@ public interface MessageLiteOrBuilder {
/**
* Returns true if all required fields in the message and all embedded
* messages are set, false otherwise.
+ *
+ * <p>See also: {@link MessageOrBuilder#getInitializationErrorString()}
*/
boolean isInitialized();
diff --git a/java/src/main/java/com/google/protobuf/MessageOrBuilder.java b/java/src/main/java/com/google/protobuf/MessageOrBuilder.java
index 0132e7ca..f0fc4859 100644
--- a/java/src/main/java/com/google/protobuf/MessageOrBuilder.java
+++ b/java/src/main/java/com/google/protobuf/MessageOrBuilder.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,6 +30,7 @@
package com.google.protobuf;
+import java.util.List;
import java.util.Map;
/**
@@ -45,6 +46,24 @@ public interface MessageOrBuilder extends MessageLiteOrBuilder {
Message getDefaultInstanceForType();
/**
+ * Returns a list of field paths (e.g. "foo.bar.baz") of required fields
+ * which are not set in this message. You should call
+ * {@link MessageLiteOrBuilder#isInitialized()} first to check if there
+ * are any missing fields, as that method is likely to be much faster
+ * than this one even when the message is fully-initialized.
+ */
+ List<String> findInitializationErrors();
+
+ /**
+ * Returns a comma-delimited list of required fields which are not set
+ * in this message object. You should call
+ * {@link MessageLiteOrBuilder#isInitialized()} first to check if there
+ * are any missing fields, as that method is likely to be much faster
+ * than this one even when the message is fully-initialized.
+ */
+ String getInitializationErrorString();
+
+ /**
* Get the message's type's descriptor. This differs from the
* {@code getDescriptor()} method of generated message classes in that
* this method is an abstract method of the {@code Message} interface
@@ -57,7 +76,7 @@ public interface MessageOrBuilder extends MessageLiteOrBuilder {
* Returns a collection of all the fields in this message which are set
* and their corresponding values. A singular ("required" or "optional")
* field is set iff hasField() returns true for that field. A "repeated"
- * field is set iff getRepeatedFieldSize() is greater than zero. The
+ * field is set iff getRepeatedFieldCount() is greater than zero. The
* values are exactly what would be returned by calling
* {@link #getField(Descriptors.FieldDescriptor)} for each field. The map
* is guaranteed to be a sorted map, so iterating over it will return fields
@@ -70,6 +89,20 @@ public interface MessageOrBuilder extends MessageLiteOrBuilder {
Map<Descriptors.FieldDescriptor, Object> getAllFields();
/**
+ * Returns true if the given oneof is set.
+ * @throws IllegalArgumentException if
+ * {@code oneof.getContainingType() != getDescriptorForType()}.
+ */
+ boolean hasOneof(Descriptors.OneofDescriptor oneof);
+
+ /**
+ * Obtains the FieldDescriptor if the given oneof is set. Returns null
+ * if no field is set.
+ */
+ Descriptors.FieldDescriptor getOneofFieldDescriptor(
+ Descriptors.OneofDescriptor oneof);
+
+ /**
* Returns true if the given field is set. This is exactly equivalent to
* calling the generated "has" accessor method corresponding to the field.
* @throws IllegalArgumentException The field is a repeated field, or
@@ -80,7 +113,7 @@ public interface MessageOrBuilder extends MessageLiteOrBuilder {
/**
* Obtains the value of the given field, or the default value if it is
* not set. For primitive fields, the boxed primitive value is returned.
- * For enum fields, the EnumValueDescriptor for the value is returend. For
+ * For enum fields, the EnumValueDescriptor for the value is returned. For
* embedded message fields, the sub-message is returned. For repeated
* fields, a java.util.List is returned.
*/
@@ -98,7 +131,7 @@ public interface MessageOrBuilder extends MessageLiteOrBuilder {
/**
* Gets an element of a repeated field. For primitive fields, the boxed
* primitive value is returned. For enum fields, the EnumValueDescriptor
- * for the value is returend. For embedded message fields, the sub-message
+ * for the value is returned. For embedded message fields, the sub-message
* is returned.
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
diff --git a/java/src/main/java/com/google/protobuf/MessageReflection.java b/java/src/main/java/com/google/protobuf/MessageReflection.java
new file mode 100644
index 00000000..de4bfd3e
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/MessageReflection.java
@@ -0,0 +1,952 @@
+// 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 java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Reflection utility methods shared by both mutable and immutable messages.
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+class MessageReflection {
+
+ static void writeMessageTo(
+ Message message,
+ Map<FieldDescriptor, Object> fields,
+ CodedOutputStream output,
+ boolean alwaysWriteRequiredFields)
+ throws IOException {
+ final boolean isMessageSet =
+ message.getDescriptorForType().getOptions().getMessageSetWireFormat();
+ if (alwaysWriteRequiredFields) {
+ fields = new TreeMap<FieldDescriptor, Object>(fields);
+ for (final FieldDescriptor field :
+ message.getDescriptorForType().getFields()) {
+ if (field.isRequired() && !fields.containsKey(field)) {
+ fields.put(field, message.getField(field));
+ }
+ }
+ }
+ for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+ fields.entrySet()) {
+ final Descriptors.FieldDescriptor field = entry.getKey();
+ final Object value = entry.getValue();
+ if (isMessageSet && field.isExtension() &&
+ field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
+ !field.isRepeated()) {
+ output.writeMessageSetExtension(field.getNumber(), (Message) value);
+ } else {
+ FieldSet.writeField(field, value, output);
+ }
+ }
+
+ final UnknownFieldSet unknownFields = message.getUnknownFields();
+ if (isMessageSet) {
+ unknownFields.writeAsMessageSetTo(output);
+ } else {
+ unknownFields.writeTo(output);
+ }
+ }
+
+ static int getSerializedSize(
+ Message message,
+ Map<FieldDescriptor, Object> fields) {
+ int size = 0;
+ final boolean isMessageSet =
+ message.getDescriptorForType().getOptions().getMessageSetWireFormat();
+
+ for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+ fields.entrySet()) {
+ final Descriptors.FieldDescriptor field = entry.getKey();
+ final Object value = entry.getValue();
+ if (isMessageSet && field.isExtension() &&
+ field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
+ !field.isRepeated()) {
+ size += CodedOutputStream.computeMessageSetExtensionSize(
+ field.getNumber(), (Message) value);
+ } else {
+ size += FieldSet.computeFieldSize(field, value);
+ }
+ }
+
+ final UnknownFieldSet unknownFields = message.getUnknownFields();
+ if (isMessageSet) {
+ size += unknownFields.getSerializedSizeAsMessageSet();
+ } else {
+ size += unknownFields.getSerializedSize();
+ }
+ return size;
+ }
+
+ static String delimitWithCommas(List<String> parts) {
+ StringBuilder result = new StringBuilder();
+ for (String part : parts) {
+ if (result.length() > 0) {
+ result.append(", ");
+ }
+ result.append(part);
+ }
+ return result.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ static boolean isInitialized(MessageOrBuilder message) {
+ // Check that all required fields are present.
+ for (final Descriptors.FieldDescriptor field : message
+ .getDescriptorForType()
+ .getFields()) {
+ if (field.isRequired()) {
+ if (!message.hasField(field)) {
+ return false;
+ }
+ }
+ }
+
+ // Check that embedded messages are initialized.
+ for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+ message.getAllFields().entrySet()) {
+ final Descriptors.FieldDescriptor field = entry.getKey();
+ if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ for (final Message element
+ : (List<Message>) entry.getValue()) {
+ if (!element.isInitialized()) {
+ return false;
+ }
+ }
+ } else {
+ if (!((Message) entry.getValue()).isInitialized()) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static String subMessagePrefix(final String prefix,
+ final Descriptors.FieldDescriptor field,
+ final int index) {
+ final StringBuilder result = new StringBuilder(prefix);
+ if (field.isExtension()) {
+ result.append('(')
+ .append(field.getFullName())
+ .append(')');
+ } else {
+ result.append(field.getName());
+ }
+ if (index != -1) {
+ result.append('[')
+ .append(index)
+ .append(']');
+ }
+ result.append('.');
+ return result.toString();
+ }
+
+ private static void findMissingFields(final MessageOrBuilder message,
+ final String prefix,
+ final List<String> results) {
+ for (final Descriptors.FieldDescriptor field :
+ message.getDescriptorForType().getFields()) {
+ if (field.isRequired() && !message.hasField(field)) {
+ results.add(prefix + field.getName());
+ }
+ }
+
+ for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+ message.getAllFields().entrySet()) {
+ final Descriptors.FieldDescriptor field = entry.getKey();
+ final Object value = entry.getValue();
+
+ if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ int i = 0;
+ for (final Object element : (List) value) {
+ findMissingFields((MessageOrBuilder) element,
+ subMessagePrefix(prefix, field, i++),
+ results);
+ }
+ } else {
+ if (message.hasField(field)) {
+ findMissingFields((MessageOrBuilder) value,
+ subMessagePrefix(prefix, field, -1),
+ results);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Populates {@code this.missingFields} with the full "path" of each missing
+ * required field in the given message.
+ */
+ static List<String> findMissingFields(
+ final MessageOrBuilder message) {
+ final List<String> results = new ArrayList<String>();
+ findMissingFields(message, "", results);
+ return results;
+ }
+
+ static interface MergeTarget {
+ enum ContainerType {
+ MESSAGE, EXTENSION_SET
+ }
+
+ /**
+ * Returns the descriptor for the target.
+ */
+ public Descriptors.Descriptor getDescriptorForType();
+
+ public ContainerType getContainerType();
+
+ public ExtensionRegistry.ExtensionInfo findExtensionByName(
+ ExtensionRegistry registry, String name);
+
+ public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
+ ExtensionRegistry registry, Descriptors.Descriptor containingType,
+ int fieldNumber);
+
+ /**
+ * Obtains the value of the given field, or the default value if it is not
+ * set. For primitive fields, the boxed primitive value is returned. For
+ * enum fields, the EnumValueDescriptor for the value is returned. For
+ * embedded message fields, the sub-message is returned. For repeated
+ * fields, a java.util.List is returned.
+ */
+ public Object getField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Returns true if the given field is set. This is exactly equivalent to
+ * calling the generated "has" accessor method corresponding to the field.
+ *
+ * @throws IllegalArgumentException The field is a repeated field, or {@code
+ * field.getContainingType() != getDescriptorForType()}.
+ */
+ boolean hasField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Sets a field to the given value. The value must be of the correct type
+ * for this field, i.e. the same type that
+ * {@link Message#getField(Descriptors.FieldDescriptor)}
+ * would return.
+ */
+ MergeTarget setField(Descriptors.FieldDescriptor field, Object value);
+
+ /**
+ * Clears the field. This is exactly equivalent to calling the generated
+ * "clear" accessor method corresponding to the field.
+ */
+ MergeTarget clearField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Sets an element of a repeated field to the given value. The value must
+ * be of the correct type for this field, i.e. the same type that {@link
+ * Message#getRepeatedField(Descriptors.FieldDescriptor, int)} would return.
+ *
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() !=
+ * getDescriptorForType()}.
+ */
+ MergeTarget setRepeatedField(Descriptors.FieldDescriptor field,
+ int index, Object value);
+
+ /**
+ * Like {@code setRepeatedField}, but appends the value as a new element.
+ *
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() !=
+ * getDescriptorForType()}.
+ */
+ MergeTarget addRepeatedField(Descriptors.FieldDescriptor field,
+ Object value);
+
+ /**
+ * Returns true if the given oneof is set.
+ *
+ * @throws IllegalArgumentException if
+ * {@code oneof.getContainingType() != getDescriptorForType()}.
+ */
+ boolean hasOneof(Descriptors.OneofDescriptor oneof);
+
+ /**
+ * Clears the oneof. This is exactly equivalent to calling the generated
+ * "clear" accessor method corresponding to the oneof.
+ */
+ MergeTarget clearOneof(Descriptors.OneofDescriptor oneof);
+
+ /**
+ * Obtains the FieldDescriptor if the given oneof is set. Returns null
+ * if no field is set.
+ */
+ Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof);
+
+ /**
+ * Parse the input stream into a sub field group defined based on either
+ * FieldDescriptor or the default instance.
+ */
+ Object parseGroup(CodedInputStream input, ExtensionRegistryLite registry,
+ Descriptors.FieldDescriptor descriptor, Message defaultInstance)
+ throws IOException;
+
+ /**
+ * Parse the input stream into a sub field message defined based on either
+ * FieldDescriptor or the default instance.
+ */
+ Object parseMessage(CodedInputStream input, ExtensionRegistryLite registry,
+ Descriptors.FieldDescriptor descriptor, Message defaultInstance)
+ throws IOException;
+
+ /**
+ * Parse from a ByteString into a sub field message defined based on either
+ * FieldDescriptor or the default instance. There isn't a varint indicating
+ * the length of the message at the beginning of the input ByteString.
+ */
+ Object parseMessageFromBytes(
+ ByteString bytes, ExtensionRegistryLite registry,
+ Descriptors.FieldDescriptor descriptor, Message defaultInstance)
+ throws IOException;
+
+ /**
+ * Returns the UTF8 validation level for the field.
+ */
+ WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor
+ descriptor);
+
+ /**
+ * Returns a new merge target for a sub-field. When defaultInstance is
+ * provided, it indicates the descriptor is for an extension type, and
+ * implementations should create a new instance from the defaultInstance
+ * prototype directly.
+ */
+ MergeTarget newMergeTargetForField(
+ Descriptors.FieldDescriptor descriptor,
+ Message defaultInstance);
+
+ /**
+ * Finishes the merge and returns the underlying object.
+ */
+ Object finish();
+ }
+
+ static class BuilderAdapter implements MergeTarget {
+
+ private final Message.Builder builder;
+
+ public Descriptors.Descriptor getDescriptorForType() {
+ return builder.getDescriptorForType();
+ }
+
+ public BuilderAdapter(Message.Builder builder) {
+ this.builder = builder;
+ }
+
+ public Object getField(Descriptors.FieldDescriptor field) {
+ return builder.getField(field);
+ }
+
+ @Override
+ public boolean hasField(Descriptors.FieldDescriptor field) {
+ return builder.hasField(field);
+ }
+
+ public MergeTarget setField(Descriptors.FieldDescriptor field,
+ Object value) {
+ builder.setField(field, value);
+ return this;
+ }
+
+ public MergeTarget clearField(Descriptors.FieldDescriptor field) {
+ builder.clearField(field);
+ return this;
+ }
+
+ public MergeTarget setRepeatedField(
+ Descriptors.FieldDescriptor field, int index, Object value) {
+ builder.setRepeatedField(field, index, value);
+ return this;
+ }
+
+ public MergeTarget addRepeatedField(
+ Descriptors.FieldDescriptor field, Object value) {
+ builder.addRepeatedField(field, value);
+ return this;
+ }
+
+ @Override
+ public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
+ return builder.hasOneof(oneof);
+ }
+
+ @Override
+ public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
+ builder.clearOneof(oneof);
+ return this;
+ }
+
+ @Override
+ public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
+ return builder.getOneofFieldDescriptor(oneof);
+ }
+
+ public ContainerType getContainerType() {
+ return ContainerType.MESSAGE;
+ }
+
+ public ExtensionRegistry.ExtensionInfo findExtensionByName(
+ ExtensionRegistry registry, String name) {
+ return registry.findImmutableExtensionByName(name);
+ }
+
+ public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
+ ExtensionRegistry registry, Descriptors.Descriptor containingType,
+ int fieldNumber) {
+ return registry.findImmutableExtensionByNumber(containingType,
+ fieldNumber);
+ }
+
+ public Object parseGroup(CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry,
+ Descriptors.FieldDescriptor field, Message defaultInstance)
+ throws IOException {
+ Message.Builder subBuilder;
+ // When default instance is not null. The field is an extension field.
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ if (!field.isRepeated()) {
+ Message originalMessage = (Message) getField(field);
+ if (originalMessage != null) {
+ subBuilder.mergeFrom(originalMessage);
+ }
+ }
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
+ return subBuilder.buildPartial();
+ }
+
+ public Object parseMessage(CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry,
+ Descriptors.FieldDescriptor field, Message defaultInstance)
+ throws IOException {
+ Message.Builder subBuilder;
+ // When default instance is not null. The field is an extension field.
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ if (!field.isRepeated()) {
+ Message originalMessage = (Message) getField(field);
+ if (originalMessage != null) {
+ subBuilder.mergeFrom(originalMessage);
+ }
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ return subBuilder.buildPartial();
+ }
+
+ public Object parseMessageFromBytes(ByteString bytes,
+ ExtensionRegistryLite extensionRegistry,
+ Descriptors.FieldDescriptor field, Message defaultInstance)
+ throws IOException {
+ Message.Builder subBuilder;
+ // When default instance is not null. The field is an extension field.
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ if (!field.isRepeated()) {
+ Message originalMessage = (Message) getField(field);
+ if (originalMessage != null) {
+ subBuilder.mergeFrom(originalMessage);
+ }
+ }
+ subBuilder.mergeFrom(bytes, extensionRegistry);
+ return subBuilder.buildPartial();
+ }
+
+ public MergeTarget newMergeTargetForField(Descriptors.FieldDescriptor field,
+ Message defaultInstance) {
+ if (defaultInstance != null) {
+ return new BuilderAdapter(
+ defaultInstance.newBuilderForType());
+ } else {
+ return new BuilderAdapter(builder.newBuilderForField(field));
+ }
+ }
+
+ public WireFormat.Utf8Validation
+ getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+ if (descriptor.needsUtf8Check()) {
+ return WireFormat.Utf8Validation.STRICT;
+ }
+ // TODO(liujisi): support lazy strings for repeated fields.
+ if (!descriptor.isRepeated()
+ && builder instanceof GeneratedMessage.Builder) {
+ return WireFormat.Utf8Validation.LAZY;
+ }
+ return WireFormat.Utf8Validation.LOOSE;
+ }
+
+ public Object finish() {
+ return builder.buildPartial();
+ }
+ }
+
+
+ static class ExtensionAdapter implements MergeTarget {
+
+ private final FieldSet<Descriptors.FieldDescriptor> extensions;
+
+ ExtensionAdapter(FieldSet<Descriptors.FieldDescriptor> extensions) {
+ this.extensions = extensions;
+ }
+
+ public Descriptors.Descriptor getDescriptorForType() {
+ throw new UnsupportedOperationException(
+ "getDescriptorForType() called on FieldSet object");
+ }
+
+ public Object getField(Descriptors.FieldDescriptor field) {
+ return extensions.getField(field);
+ }
+
+ public boolean hasField(Descriptors.FieldDescriptor field) {
+ return extensions.hasField(field);
+ }
+
+ public MergeTarget setField(Descriptors.FieldDescriptor field,
+ Object value) {
+ extensions.setField(field, value);
+ return this;
+ }
+
+ public MergeTarget clearField(Descriptors.FieldDescriptor field) {
+ extensions.clearField(field);
+ return this;
+ }
+
+ public MergeTarget setRepeatedField(
+ Descriptors.FieldDescriptor field, int index, Object value) {
+ extensions.setRepeatedField(field, index, value);
+ return this;
+ }
+
+ public MergeTarget addRepeatedField(
+ Descriptors.FieldDescriptor field, Object value) {
+ extensions.addRepeatedField(field, value);
+ return this;
+ }
+
+ @Override
+ public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
+ return false;
+ }
+
+ @Override
+ public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
+ // Nothing to clear.
+ return this;
+ }
+
+ @Override
+ public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
+ return null;
+ }
+
+ public ContainerType getContainerType() {
+ return ContainerType.EXTENSION_SET;
+ }
+
+ public ExtensionRegistry.ExtensionInfo findExtensionByName(
+ ExtensionRegistry registry, String name) {
+ return registry.findImmutableExtensionByName(name);
+ }
+
+ public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
+ ExtensionRegistry registry, Descriptors.Descriptor containingType,
+ int fieldNumber) {
+ return registry.findImmutableExtensionByNumber(containingType,
+ fieldNumber);
+ }
+
+ public Object parseGroup(CodedInputStream input,
+ ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
+ Message defaultInstance) throws IOException {
+ Message.Builder subBuilder =
+ defaultInstance.newBuilderForType();
+ if (!field.isRepeated()) {
+ Message originalMessage = (Message) getField(field);
+ if (originalMessage != null) {
+ subBuilder.mergeFrom(originalMessage);
+ }
+ }
+ input.readGroup(field.getNumber(), subBuilder, registry);
+ return subBuilder.buildPartial();
+ }
+
+ public Object parseMessage(CodedInputStream input,
+ ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
+ Message defaultInstance) throws IOException {
+ Message.Builder subBuilder =
+ defaultInstance.newBuilderForType();
+ if (!field.isRepeated()) {
+ Message originalMessage = (Message) getField(field);
+ if (originalMessage != null) {
+ subBuilder.mergeFrom(originalMessage);
+ }
+ }
+ input.readMessage(subBuilder, registry);
+ return subBuilder.buildPartial();
+ }
+
+ public Object parseMessageFromBytes(ByteString bytes,
+ ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
+ Message defaultInstance) throws IOException {
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
+ if (!field.isRepeated()) {
+ Message originalMessage = (Message) getField(field);
+ if (originalMessage != null) {
+ subBuilder.mergeFrom(originalMessage);
+ }
+ }
+ subBuilder.mergeFrom(bytes, registry);
+ return subBuilder.buildPartial();
+ }
+
+ public MergeTarget newMergeTargetForField(
+ Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
+ throw new UnsupportedOperationException(
+ "newMergeTargetForField() called on FieldSet object");
+ }
+
+ public WireFormat.Utf8Validation
+ getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+ if (descriptor.needsUtf8Check()) {
+ return WireFormat.Utf8Validation.STRICT;
+ }
+ // TODO(liujisi): support lazy strings for ExtesnsionSet.
+ return WireFormat.Utf8Validation.LOOSE;
+ }
+
+ public Object finish() {
+ throw new UnsupportedOperationException(
+ "finish() called on FieldSet object");
+ }
+ }
+
+ /**
+ * Parses a single field into MergeTarget. The target can be Message.Builder,
+ * FieldSet or MutableMessage.
+ *
+ * Package-private because it is used by GeneratedMessage.ExtendableMessage.
+ *
+ * @param tag The tag, which should have already been read.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ static boolean mergeFieldFrom(
+ CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistryLite extensionRegistry,
+ Descriptors.Descriptor type,
+ MergeTarget target,
+ int tag) throws IOException {
+ if (type.getOptions().getMessageSetWireFormat() &&
+ tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
+ mergeMessageSetExtensionFromCodedStream(
+ input, unknownFields, extensionRegistry, type, target);
+ return true;
+ }
+
+ final int wireType = WireFormat.getTagWireType(tag);
+ final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+ final Descriptors.FieldDescriptor field;
+ Message defaultInstance = null;
+
+ if (type.isExtensionNumber(fieldNumber)) {
+ // extensionRegistry may be either ExtensionRegistry or
+ // ExtensionRegistryLite. Since the type we are parsing is a full
+ // message, only a full ExtensionRegistry could possibly contain
+ // extensions of it. Otherwise we will treat the registry as if it
+ // were empty.
+ if (extensionRegistry instanceof ExtensionRegistry) {
+ final ExtensionRegistry.ExtensionInfo extension =
+ target.findExtensionByNumber((ExtensionRegistry) extensionRegistry,
+ type, fieldNumber);
+ if (extension == null) {
+ field = null;
+ } else {
+ field = extension.descriptor;
+ defaultInstance = extension.defaultInstance;
+ if (defaultInstance == null &&
+ field.getJavaType()
+ == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+ throw new IllegalStateException(
+ "Message-typed extension lacked default instance: " +
+ field.getFullName());
+ }
+ }
+ } else {
+ field = null;
+ }
+ } else if (target.getContainerType() == MergeTarget.ContainerType.MESSAGE) {
+ field = type.findFieldByNumber(fieldNumber);
+ } else {
+ field = null;
+ }
+
+ boolean unknown = false;
+ boolean packed = false;
+ if (field == null) {
+ unknown = true; // Unknown field.
+ } else if (wireType == FieldSet.getWireFormatForFieldType(
+ field.getLiteType(),
+ false /* isPacked */)) {
+ packed = false;
+ } else if (field.isPackable() &&
+ wireType == FieldSet.getWireFormatForFieldType(
+ field.getLiteType(),
+ true /* isPacked */)) {
+ packed = true;
+ } else {
+ unknown = true; // Unknown wire type.
+ }
+
+ if (unknown) { // Unknown field or wrong wire type. Skip.
+ return unknownFields.mergeFieldFrom(tag, input);
+ }
+
+ if (packed) {
+ final int length = input.readRawVarint32();
+ final int limit = input.pushLimit(length);
+ if (field.getLiteType() == WireFormat.FieldType.ENUM) {
+ while (input.getBytesUntilLimit() > 0) {
+ final int rawValue = input.readEnum();
+ 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);
+ }
+ }
+ } else {
+ while (input.getBytesUntilLimit() > 0) {
+ final Object value = WireFormat.readPrimitiveField(
+ input, field.getLiteType(), target.getUtf8Validation(field));
+ target.addRepeatedField(field, value);
+ }
+ }
+ input.popLimit(limit);
+ } else {
+ final Object value;
+ switch (field.getType()) {
+ case GROUP: {
+ value = target
+ .parseGroup(input, extensionRegistry, field, defaultInstance);
+ break;
+ }
+ case MESSAGE: {
+ value = target
+ .parseMessage(input, extensionRegistry, field, defaultInstance);
+ break;
+ }
+ case ENUM:
+ final int rawValue = input.readEnum();
+ 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:
+ value = WireFormat.readPrimitiveField(
+ input, field.getLiteType(), target.getUtf8Validation(field));
+ break;
+ }
+
+ if (field.isRepeated()) {
+ target.addRepeatedField(field, value);
+ } else {
+ target.setField(field, value);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into
+ * MergeTarget.
+ */
+ private static void mergeMessageSetExtensionFromCodedStream(
+ CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistryLite extensionRegistry,
+ Descriptors.Descriptor type,
+ MergeTarget target) throws IOException {
+
+ // The wire format for MessageSet is:
+ // message MessageSet {
+ // repeated group Item = 1 {
+ // required int32 typeId = 2;
+ // required bytes message = 3;
+ // }
+ // }
+ // "typeId" is the extension's field number. The extension can only be
+ // a message type, where "message" contains the encoded bytes of that
+ // message.
+ //
+ // In practice, we will probably never see a MessageSet item in which
+ // the message appears before the type ID, or where either field does not
+ // appear exactly once. However, in theory such cases are valid, so we
+ // should be prepared to accept them.
+
+ int typeId = 0;
+ ByteString rawBytes = null; // If we encounter "message" before "typeId"
+ ExtensionRegistry.ExtensionInfo extension = null;
+
+ // Read bytes from input, if we get it's type first then parse it eagerly,
+ // otherwise we store the raw bytes in a local variable.
+ while (true) {
+ final int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+
+ if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
+ typeId = input.readUInt32();
+ if (typeId != 0) {
+ // extensionRegistry may be either ExtensionRegistry or
+ // ExtensionRegistryLite. Since the type we are parsing is a full
+ // message, only a full ExtensionRegistry could possibly contain
+ // extensions of it. Otherwise we will treat the registry as if it
+ // were empty.
+ if (extensionRegistry instanceof ExtensionRegistry) {
+ extension = target.findExtensionByNumber(
+ (ExtensionRegistry) extensionRegistry, type, typeId);
+ }
+ }
+
+ } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
+ if (typeId != 0) {
+ if (extension != null &&
+ ExtensionRegistryLite.isEagerlyParseMessageSets()) {
+ // We already know the type, so we can parse directly from the
+ // input with no copying. Hooray!
+ eagerlyMergeMessageSetExtension(
+ input, extension, extensionRegistry, target);
+ rawBytes = null;
+ continue;
+ }
+ }
+ // We haven't seen a type ID yet or we want parse message lazily.
+ rawBytes = input.readBytes();
+
+ } else { // Unknown tag. Skip it.
+ if (!input.skipField(tag)) {
+ break; // End of group
+ }
+ }
+ }
+ input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
+
+ // Process the raw bytes.
+ if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
+ if (extension != null) { // We known the type
+ mergeMessageSetExtensionFromBytes(
+ rawBytes, extension, extensionRegistry, target);
+ } else { // We don't know how to parse this. Ignore it.
+ if (rawBytes != null) {
+ unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
+ .addLengthDelimited(rawBytes).build());
+ }
+ }
+ }
+ }
+
+ private static void mergeMessageSetExtensionFromBytes(
+ ByteString rawBytes,
+ ExtensionRegistry.ExtensionInfo extension,
+ ExtensionRegistryLite extensionRegistry,
+ MergeTarget target) throws IOException {
+
+ Descriptors.FieldDescriptor field = extension.descriptor;
+ boolean hasOriginalValue = target.hasField(field);
+
+ if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) {
+ // If the field already exists, we just parse the field.
+ Object value = target.parseMessageFromBytes(
+ rawBytes, extensionRegistry,field, extension.defaultInstance);
+ target.setField(field, value);
+ } else {
+ // Use LazyField to load MessageSet lazily.
+ LazyField lazyField = new LazyField(
+ extension.defaultInstance, extensionRegistry, rawBytes);
+ target.setField(field, lazyField);
+ }
+ }
+
+ private static void eagerlyMergeMessageSetExtension(
+ CodedInputStream input,
+ ExtensionRegistry.ExtensionInfo extension,
+ ExtensionRegistryLite extensionRegistry,
+ MergeTarget target) throws IOException {
+ Descriptors.FieldDescriptor field = extension.descriptor;
+ Object value = target.parseMessage(input, extensionRegistry, field,
+ extension.defaultInstance);
+ target.setField(field, value);
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/Parser.java b/java/src/main/java/com/google/protobuf/Parser.java
new file mode 100644
index 00000000..227c02b7
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Parser.java
@@ -0,0 +1,261 @@
+// 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.InputStream;
+
+/**
+ * Abstract interface for parsing Protocol Messages.
+ *
+ * The implementation should be stateless and thread-safe.
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+public interface Parser<MessageType> {
+ /**
+ * Parses a message of {@code MessageType} from the input.
+ *
+ * <p>Note: The caller should call
+ * {@link CodedInputStream#checkLastTagWas(int)} after calling this to
+ * verify that the last tag seen was the appropriate end-group tag,
+ * or zero for EOF.
+ */
+ public MessageType parseFrom(CodedInputStream input)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(CodedInputStream)}, but also parses extensions.
+ * The extensions that you want to be able to parse must be registered in
+ * {@code extensionRegistry}. Extensions not in the registry will be treated
+ * as unknown fields.
+ */
+ public MessageType parseFrom(CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(CodedInputStream)}, but does not throw an
+ * exception if the message is missing required fields. Instead, a partial
+ * message is returned.
+ */
+ public MessageType parsePartialFrom(CodedInputStream input)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(CodedInputStream input, ExtensionRegistryLite)},
+ * but does not throw an exception if the message is missing required fields.
+ * Instead, a partial message is returned.
+ */
+ public MessageType parsePartialFrom(CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ // ---------------------------------------------------------------
+ // Convenience methods.
+
+ /**
+ * Parses {@code data} as a message of {@code MessageType}.
+ * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
+ */
+ public MessageType parseFrom(ByteString data)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parses {@code data} as a message of {@code MessageType}.
+ * This is just a small wrapper around
+ * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+ */
+ public MessageType parseFrom(ByteString data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(ByteString)}, but does not throw an
+ * exception if the message is missing required fields. Instead, a partial
+ * message is returned.
+ */
+ public MessageType parsePartialFrom(ByteString data)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
+ * but does not throw an exception if the message is missing required fields.
+ * Instead, a partial message is returned.
+ */
+ public MessageType parsePartialFrom(ByteString data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parses {@code data} as a message of {@code MessageType}.
+ * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
+ */
+ public MessageType parseFrom(byte[] data, int off, int len)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parses {@code data} as a message of {@code MessageType}.
+ * This is just a small wrapper around
+ * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+ */
+ public MessageType parseFrom(byte[] data, int off, int len,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parses {@code data} as a message of {@code MessageType}.
+ * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
+ */
+ public MessageType parseFrom(byte[] data)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parses {@code data} as a message of {@code MessageType}.
+ * This is just a small wrapper around
+ * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+ */
+ public MessageType parseFrom(byte[] data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(byte[], int, int)}, but does not throw an
+ * exception if the message is missing required fields. Instead, a partial
+ * message is returned.
+ */
+ public MessageType parsePartialFrom(byte[] data, int off, int len)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
+ * but does not throw an exception if the message is missing required fields.
+ * Instead, a partial message is returned.
+ */
+ public MessageType parsePartialFrom(byte[] data, int off, int len,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(byte[])}, but does not throw an
+ * exception if the message is missing required fields. Instead, a partial
+ * message is returned.
+ */
+ public MessageType parsePartialFrom(byte[] data)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(byte[], ExtensionRegistryLite)},
+ * but does not throw an exception if the message is missing required fields.
+ * Instead, a partial message is returned.
+ */
+ public MessageType parsePartialFrom(byte[] data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parse a message of {@code MessageType} from {@code input}.
+ * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
+ * Note that this method always reads the <i>entire</i> input (unless it
+ * throws an exception). If you want it to stop earlier, you will need to
+ * wrap your input in some wrapper stream that limits reading. Or, use
+ * {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write your
+ * message and {@link #parseDelimitedFrom(InputStream)} to read it.
+ * <p>
+ * Despite usually reading the entire input, this does not close the stream.
+ */
+ public MessageType parseFrom(InputStream input)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parses a message of {@code MessageType} from {@code input}.
+ * This is just a small wrapper around
+ * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+ */
+ public MessageType parseFrom(InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(InputStream)}, but does not throw an
+ * exception if the message is missing required fields. Instead, a partial
+ * message is returned.
+ */
+ public MessageType parsePartialFrom(InputStream input)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(InputStream, ExtensionRegistryLite)},
+ * but does not throw an exception if the message is missing required fields.
+ * Instead, a partial message is returned.
+ */
+ public MessageType parsePartialFrom(InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseFrom(InputStream)}, but does not read util EOF.
+ * Instead, the size of message (encoded as a varint) is read first,
+ * then the message data. Use
+ * {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write
+ * messages in this format.
+ *
+ * @return Parsed message if successful, or null if the stream is at EOF when
+ * the method starts. Any other error (including reaching EOF during
+ * parsing) will cause an exception to be thrown.
+ */
+ public MessageType parseDelimitedFrom(InputStream input)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseDelimitedFrom(InputStream)} but supporting extensions.
+ */
+ public MessageType parseDelimitedFrom(InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseDelimitedFrom(InputStream)}, but does not throw an
+ * exception if the message is missing required fields. Instead, a partial
+ * message is returned.
+ */
+ public MessageType parsePartialDelimitedFrom(InputStream input)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Like {@link #parseDelimitedFrom(InputStream, ExtensionRegistryLite)},
+ * but does not throw an exception if the message is missing required fields.
+ * Instead, a partial message is returned.
+ */
+ public MessageType parsePartialDelimitedFrom(
+ InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+}
diff --git a/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java b/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
index 112400f4..0c8df989 100644
--- a/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
+++ b/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/main/java/com/google/protobuf/ProtocolStringList.java b/java/src/main/java/com/google/protobuf/ProtocolStringList.java
new file mode 100644
index 00000000..d553b41e
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/ProtocolStringList.java
@@ -0,0 +1,48 @@
+// 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.List;
+
+/**
+ * An interface extending {@code List<String>} used for repeated string fields
+ * to provide optional access to the data as a list of ByteStrings. The
+ * underlying implementation stores values as either ByteStrings or Strings
+ * (see {@link LazyStringArrayList}) depending on how the value was initialized
+ * or last read, and it is often more efficient to deal with lists of
+ * ByteStrings when handling protos that have been deserialized from bytes.
+ */
+public interface ProtocolStringList extends List<String> {
+
+ /** Returns a view of the data as a list of ByteStrings. */
+ List<ByteString> asByteStringList();
+
+}
diff --git a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
index 0024f791..be737b1a 100644
--- a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
+++ b/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -37,24 +37,24 @@ import java.util.Collections;
import java.util.List;
/**
- * <code>RepeatedFieldBuilder</code> implements a structure that a protocol
+ * {@code RepeatedFieldBuilder} implements a structure that a protocol
* message uses to hold a repeated field of other protocol messages. It supports
* the classical use case of adding immutable {@link Message}'s to the
* repeated field and is highly optimized around this (no extra memory
* allocations and sharing of immutable arrays).
* <br>
* It also supports the additional use case of adding a {@link Message.Builder}
- * to the repeated field and deferring conversion of that <code>Builder</code>
- * to an immutable <code>Message</code>. In this way, it's possible to maintain
- * a tree of <code>Builder</code>'s that acts as a fully read/write data
+ * to the repeated field and deferring conversion of that {@code Builder}
+ * to an immutable {@code Message}. In this way, it's possible to maintain
+ * a tree of {@code Builder}'s that acts as a fully read/write data
* structure.
* <br>
* Logically, one can think of a tree of builders as converting the entire tree
* to messages when build is called on the root or when any method is called
* that desires a Message instead of a Builder. In terms of the implementation,
- * the <code>SingleFieldBuilder</code> and <code>RepeatedFieldBuilder</code>
+ * the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
* classes cache messages that were created so that messages only need to be
- * created when some change occured in its builder or a builder for one of its
+ * created when some change occurred in its builder or a builder for one of its
* descendants.
*
* @param <MType> the type of message for the field
@@ -192,7 +192,7 @@ public class RepeatedFieldBuilder
/**
* Get the message at the specified index. If the message is currently stored
- * as a <code>Builder</code>, it is converted to a <code>Message</code> by
+ * as a {@code Builder}, it is converted to a {@code Message} by
* calling {@link Message.Builder#buildPartial} on it.
*
* @param index the index of the message to get
@@ -204,7 +204,7 @@ public class RepeatedFieldBuilder
/**
* Get the message at the specified index. If the message is currently stored
- * as a <code>Builder</code>, it is converted to a <code>Message</code> by
+ * as a {@code Builder}, it is converted to a {@code Message} by
* calling {@link Message.Builder#buildPartial} on it.
*
* @param index the index of the message to get
@@ -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<MType> collection = (Collection<MType>) 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<MType>) 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/RopeByteString.java b/java/src/main/java/com/google/protobuf/RopeByteString.java
new file mode 100644
index 00000000..168bcce2
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/RopeByteString.java
@@ -0,0 +1,977 @@
+// 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;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.ByteArrayInputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Stack;
+
+/**
+ * Class to represent {@code ByteStrings} formed by concatenation of other
+ * ByteStrings, without copying the data in the pieces. The concatenation is
+ * represented as a tree whose leaf nodes are each a {@link LiteralByteString}.
+ *
+ * <p>Most of the operation here is inspired by the now-famous paper <a
+ * href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
+ * BAP95 </a> Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and
+ * michael plass
+ *
+ * <p>The algorithms described in the paper have been implemented for character
+ * strings in {@link com.google.common.string.Rope} and in the c++ class {@code
+ * cord.cc}.
+ *
+ * <p>Fundamentally the Rope algorithm represents the collection of pieces as a
+ * binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum
+ * sequence length, sequences that are too short relative to their depth cause a
+ * tree rebalance. More precisely, a tree of depth d is "balanced" in the
+ * terminology of BAP95 if its length is at least F(d+2), where F(n) is the
+ * n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have minimum
+ * lengths 1, 2, 3, 5, 8, 13,...
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+class RopeByteString extends ByteString {
+
+ /**
+ * BAP95. Let Fn be the nth Fibonacci number. A {@link RopeByteString} of
+ * depth n is "balanced", i.e flat enough, if its length is at least Fn+2,
+ * e.g. a "balanced" {@link RopeByteString} of depth 1 must have length at
+ * least 2, of depth 4 must have length >= 8, etc.
+ *
+ * <p>There's nothing special about using the Fibonacci numbers for this, but
+ * they are a reasonable sequence for encapsulating the idea that we are OK
+ * with longer strings being encoded in deeper binary trees.
+ *
+ * <p>For 32-bit integers, this array has length 46.
+ */
+ private static final int[] minLengthByDepth;
+
+ static {
+ // Dynamically generate the list of Fibonacci numbers the first time this
+ // class is accessed.
+ List<Integer> numbers = new ArrayList<Integer>();
+
+ // we skip the first Fibonacci number (1). So instead of: 1 1 2 3 5 8 ...
+ // we have: 1 2 3 5 8 ...
+ int f1 = 1;
+ int f2 = 1;
+
+ // get all the values until we roll over.
+ while (f2 > 0) {
+ numbers.add(f2);
+ int temp = f1 + f2;
+ f1 = f2;
+ f2 = temp;
+ }
+
+ // we include this here so that we can index this array to [x + 1] in the
+ // loops below.
+ numbers.add(Integer.MAX_VALUE);
+ minLengthByDepth = new int[numbers.size()];
+ for (int i = 0; i < minLengthByDepth.length; i++) {
+ // unbox all the values
+ minLengthByDepth[i] = numbers.get(i);
+ }
+ }
+
+ private final int totalLength;
+ private final ByteString left;
+ private final ByteString right;
+ private final int leftLength;
+ private final int treeDepth;
+
+ /**
+ * Create a new RopeByteString, which can be thought of as a new tree node, by
+ * recording references to the two given strings.
+ *
+ * @param left string on the left of this node, should have {@code size() >
+ * 0}
+ * @param right string on the right of this node, should have {@code size() >
+ * 0}
+ */
+ private RopeByteString(ByteString left, ByteString right) {
+ this.left = left;
+ this.right = right;
+ leftLength = left.size();
+ totalLength = leftLength + right.size();
+ treeDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
+ }
+
+ /**
+ * Concatenate the given strings while performing various optimizations to
+ * slow the growth rate of tree depth and tree node count. The result is
+ * either a {@link LiteralByteString} or a {@link RopeByteString}
+ * depending on which optimizations, if any, were applied.
+ *
+ * <p>Small pieces of length less than {@link
+ * ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in
+ * BAP95. Large pieces are referenced without copy.
+ *
+ * @param left string on the left
+ * @param right string on the right
+ * @return concatenation representing the same sequence as the given strings
+ */
+ static ByteString concatenate(ByteString left, ByteString right) {
+ ByteString result;
+ RopeByteString leftRope =
+ (left instanceof RopeByteString) ? (RopeByteString) left : null;
+ if (right.size() == 0) {
+ result = left;
+ } else if (left.size() == 0) {
+ result = right;
+ } else {
+ int newLength = left.size() + right.size();
+ if (newLength < ByteString.CONCATENATE_BY_COPY_SIZE) {
+ // Optimization from BAP95: For short (leaves in paper, but just short
+ // here) total length, do a copy of data to a new leaf.
+ result = concatenateBytes(left, right);
+ } else if (leftRope != null
+ && leftRope.right.size() + right.size() < CONCATENATE_BY_COPY_SIZE) {
+ // Optimization from BAP95: As an optimization of the case where the
+ // ByteString is constructed by repeated concatenate, recognize the case
+ // where a short string is concatenated to a left-hand node whose
+ // right-hand branch is short. In the paper this applies to leaves, but
+ // we just look at the length here. This has the advantage of shedding
+ // references to unneeded data when substrings have been taken.
+ //
+ // When we recognize this case, we do a copy of the data and create a
+ // new parent node so that the depth of the result is the same as the
+ // given left tree.
+ ByteString newRight = concatenateBytes(leftRope.right, right);
+ result = new RopeByteString(leftRope.left, newRight);
+ } else if (leftRope != null
+ && leftRope.left.getTreeDepth() > leftRope.right.getTreeDepth()
+ && leftRope.getTreeDepth() > right.getTreeDepth()) {
+ // Typically for concatenate-built strings the left-side is deeper than
+ // the right. This is our final attempt to concatenate without
+ // increasing the tree depth. We'll redo the the node on the RHS. This
+ // is yet another optimization for building the string by repeatedly
+ // concatenating on the right.
+ ByteString newRight = new RopeByteString(leftRope.right, right);
+ result = new RopeByteString(leftRope.left, newRight);
+ } else {
+ // Fine, we'll add a node and increase the tree depth--unless we
+ // rebalance ;^)
+ int newDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
+ if (newLength >= minLengthByDepth[newDepth]) {
+ // The tree is shallow enough, so don't rebalance
+ result = new RopeByteString(left, right);
+ } else {
+ result = new Balancer().balance(left, right);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Concatenates two strings by copying data values. This is called in a few
+ * cases in order to reduce the growth of the number of tree nodes.
+ *
+ * @param left string on the left
+ * @param right string on the right
+ * @return string formed by copying data bytes
+ */
+ private static LiteralByteString concatenateBytes(ByteString left,
+ ByteString right) {
+ int leftSize = left.size();
+ int rightSize = right.size();
+ byte[] bytes = new byte[leftSize + rightSize];
+ left.copyTo(bytes, 0, 0, leftSize);
+ right.copyTo(bytes, 0, leftSize, rightSize);
+ return new LiteralByteString(bytes); // Constructor wraps bytes
+ }
+
+ /**
+ * Create a new RopeByteString for testing only while bypassing all the
+ * defenses of {@link #concatenate(ByteString, ByteString)}. This allows
+ * testing trees of specific structure. We are also able to insert empty
+ * leaves, though these are dis-allowed, so that we can make sure the
+ * implementation can withstand their presence.
+ *
+ * @param left string on the left of this node
+ * @param right string on the right of this node
+ * @return an unsafe instance for testing only
+ */
+ static RopeByteString newInstanceForTest(ByteString left, ByteString right) {
+ return new RopeByteString(left, right);
+ }
+
+ /**
+ * Gets the byte at the given index.
+ * Throws {@link ArrayIndexOutOfBoundsException} for backwards-compatibility
+ * reasons although it would more properly be {@link
+ * IndexOutOfBoundsException}.
+ *
+ * @param index index of byte
+ * @return the value
+ * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
+ */
+ @Override
+ public byte byteAt(int index) {
+ if (index < 0) {
+ throw new ArrayIndexOutOfBoundsException("Index < 0: " + index);
+ }
+ if (index > totalLength) {
+ throw new ArrayIndexOutOfBoundsException(
+ "Index > length: " + index + ", " + totalLength);
+ }
+
+ byte result;
+ // Find the relevant piece by recursive descent
+ if (index < leftLength) {
+ result = left.byteAt(index);
+ } else {
+ result = right.byteAt(index - leftLength);
+ }
+ return result;
+ }
+
+ @Override
+ public int size() {
+ return totalLength;
+ }
+
+ // =================================================================
+ // Pieces
+
+ @Override
+ protected int getTreeDepth() {
+ return treeDepth;
+ }
+
+ /**
+ * Determines if the tree is balanced according to BAP95, which means the tree
+ * is flat-enough with respect to the bounds. Note that this definition of
+ * balanced is one where sub-trees of balanced trees are not necessarily
+ * balanced.
+ *
+ * @return true if the tree is balanced
+ */
+ @Override
+ protected boolean isBalanced() {
+ return totalLength >= minLengthByDepth[treeDepth];
+ }
+
+ /**
+ * Takes a substring of this one. This involves recursive descent along the
+ * left and right edges of the substring, and referencing any wholly contained
+ * segments in between. Any leaf nodes entirely uninvolved in the substring
+ * will not be referenced by the substring.
+ *
+ * <p>Substrings of {@code length < 2} should result in at most a single
+ * recursive call chain, terminating at a leaf node. Thus the result will be a
+ * {@link LiteralByteString}. {@link #RopeByteString(ByteString,
+ * ByteString)}.
+ *
+ * @param beginIndex start at this index
+ * @param endIndex the last character is the one before this index
+ * @return substring leaf node or tree
+ */
+ @Override
+ public ByteString substring(int beginIndex, int endIndex) {
+ if (beginIndex < 0) {
+ throw new IndexOutOfBoundsException(
+ "Beginning index: " + beginIndex + " < 0");
+ }
+ if (endIndex > totalLength) {
+ throw new IndexOutOfBoundsException(
+ "End index: " + endIndex + " > " + totalLength);
+ }
+ int substringLength = endIndex - beginIndex;
+ if (substringLength < 0) {
+ throw new IndexOutOfBoundsException(
+ "Beginning index larger than ending index: " + beginIndex + ", "
+ + endIndex);
+ }
+
+ ByteString result;
+ if (substringLength == 0) {
+ // Empty substring
+ result = ByteString.EMPTY;
+ } else if (substringLength == totalLength) {
+ // The whole string
+ result = this;
+ } else {
+ // Proper substring
+ if (endIndex <= leftLength) {
+ // Substring on the left
+ result = left.substring(beginIndex, endIndex);
+ } else if (beginIndex >= leftLength) {
+ // Substring on the right
+ result = right
+ .substring(beginIndex - leftLength, endIndex - leftLength);
+ } else {
+ // Split substring
+ ByteString leftSub = left.substring(beginIndex);
+ ByteString rightSub = right.substring(0, endIndex - leftLength);
+ // Intentionally not rebalancing, since in many cases these two
+ // substrings will already be less deep than the top-level
+ // RopeByteString we're taking a substring of.
+ result = new RopeByteString(leftSub, rightSub);
+ }
+ }
+ return result;
+ }
+
+ // =================================================================
+ // ByteString -> byte[]
+
+ @Override
+ protected void copyToInternal(byte[] target, int sourceOffset,
+ int targetOffset, int numberToCopy) {
+ if (sourceOffset + numberToCopy <= leftLength) {
+ left.copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
+ } else if (sourceOffset >= leftLength) {
+ right.copyToInternal(target, sourceOffset - leftLength, targetOffset,
+ numberToCopy);
+ } else {
+ int leftLength = this.leftLength - sourceOffset;
+ left.copyToInternal(target, sourceOffset, targetOffset, leftLength);
+ right.copyToInternal(target, 0, targetOffset + leftLength,
+ numberToCopy - leftLength);
+ }
+ }
+
+ @Override
+ public void copyTo(ByteBuffer target) {
+ left.copyTo(target);
+ right.copyTo(target);
+ }
+
+ @Override
+ public ByteBuffer asReadOnlyByteBuffer() {
+ ByteBuffer byteBuffer = ByteBuffer.wrap(toByteArray());
+ return byteBuffer.asReadOnlyBuffer();
+ }
+
+ @Override
+ public List<ByteBuffer> asReadOnlyByteBufferList() {
+ // Walk through the list of LiteralByteString's that make up this
+ // rope, and add each one as a read-only ByteBuffer.
+ List<ByteBuffer> result = new ArrayList<ByteBuffer>();
+ PieceIterator pieces = new PieceIterator(this);
+ while (pieces.hasNext()) {
+ LiteralByteString byteString = pieces.next();
+ result.add(byteString.asReadOnlyByteBuffer());
+ }
+ return result;
+ }
+
+ @Override
+ public void writeTo(OutputStream outputStream) throws IOException {
+ left.writeTo(outputStream);
+ right.writeTo(outputStream);
+ }
+
+ @Override
+ void writeToInternal(OutputStream out, int sourceOffset,
+ int numberToWrite) throws IOException {
+ if (sourceOffset + numberToWrite <= leftLength) {
+ left.writeToInternal(out, sourceOffset, numberToWrite);
+ } else if (sourceOffset >= leftLength) {
+ right.writeToInternal(out, sourceOffset - leftLength, numberToWrite);
+ } else {
+ int numberToWriteInLeft = leftLength - sourceOffset;
+ left.writeToInternal(out, sourceOffset, numberToWriteInLeft);
+ right.writeToInternal(out, 0, numberToWrite - numberToWriteInLeft);
+ }
+ }
+
+ @Override
+ public String toString(String charsetName)
+ throws UnsupportedEncodingException {
+ // Optimize for empty strings, but ensure we don't silently ignore invalid
+ // encodings.
+ return size() == 0 && UTF_8.equals(charsetName)
+ ? ""
+ : new String(toByteArray(), charsetName);
+ }
+
+ // =================================================================
+ // UTF-8 decoding
+
+ @Override
+ public boolean isValidUtf8() {
+ int leftPartial = left.partialIsValidUtf8(Utf8.COMPLETE, 0, leftLength);
+ int state = right.partialIsValidUtf8(leftPartial, 0, right.size());
+ return state == Utf8.COMPLETE;
+ }
+
+ @Override
+ protected int partialIsValidUtf8(int state, int offset, int length) {
+ int toIndex = offset + length;
+ if (toIndex <= leftLength) {
+ return left.partialIsValidUtf8(state, offset, length);
+ } else if (offset >= leftLength) {
+ return right.partialIsValidUtf8(state, offset - leftLength, length);
+ } else {
+ int leftLength = this.leftLength - offset;
+ int leftPartial = left.partialIsValidUtf8(state, offset, leftLength);
+ return right.partialIsValidUtf8(leftPartial, 0, length - leftLength);
+ }
+ }
+
+ // =================================================================
+ // equals() and hashCode()
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof ByteString)) {
+ return false;
+ }
+
+ ByteString otherByteString = (ByteString) other;
+ if (totalLength != otherByteString.size()) {
+ return false;
+ }
+ if (totalLength == 0) {
+ return true;
+ }
+
+ // You don't really want to be calling equals on long strings, but since
+ // we cache the hashCode, we effectively cache inequality. We use the cached
+ // hashCode if it's already computed. It's arguable we should compute the
+ // hashCode here, and if we're going to be testing a bunch of byteStrings,
+ // it might even make sense.
+ if (hash != 0) {
+ int cachedOtherHash = otherByteString.peekCachedHashCode();
+ if (cachedOtherHash != 0 && hash != cachedOtherHash) {
+ return false;
+ }
+ }
+
+ return equalsFragments(otherByteString);
+ }
+
+ /**
+ * Determines if this string is equal to another of the same length by
+ * iterating over the leaf nodes. On each step of the iteration, the
+ * overlapping segments of the leaves are compared.
+ *
+ * @param other string of the same length as this one
+ * @return true if the values of this string equals the value of the given
+ * one
+ */
+ private boolean equalsFragments(ByteString other) {
+ int thisOffset = 0;
+ Iterator<LiteralByteString> thisIter = new PieceIterator(this);
+ LiteralByteString thisString = thisIter.next();
+
+ int thatOffset = 0;
+ Iterator<LiteralByteString> thatIter = new PieceIterator(other);
+ LiteralByteString thatString = thatIter.next();
+
+ int pos = 0;
+ while (true) {
+ int thisRemaining = thisString.size() - thisOffset;
+ int thatRemaining = thatString.size() - thatOffset;
+ int bytesToCompare = Math.min(thisRemaining, thatRemaining);
+
+ // At least one of the offsets will be zero
+ boolean stillEqual = (thisOffset == 0)
+ ? thisString.equalsRange(thatString, thatOffset, bytesToCompare)
+ : thatString.equalsRange(thisString, thisOffset, bytesToCompare);
+ if (!stillEqual) {
+ return false;
+ }
+
+ pos += bytesToCompare;
+ if (pos >= totalLength) {
+ if (pos == totalLength) {
+ return true;
+ }
+ throw new IllegalStateException();
+ }
+ // We always get to the end of at least one of the pieces
+ if (bytesToCompare == thisRemaining) { // If reached end of this
+ thisOffset = 0;
+ thisString = thisIter.next();
+ } else {
+ thisOffset += bytesToCompare;
+ }
+ if (bytesToCompare == thatRemaining) { // If reached end of that
+ thatOffset = 0;
+ thatString = thatIter.next();
+ } else {
+ thatOffset += bytesToCompare;
+ }
+ }
+ }
+
+ /**
+ * Cached hash value. Intentionally accessed via a data race, which is safe
+ * because of the Java Memory Model's "no out-of-thin-air values" guarantees
+ * for ints.
+ */
+ private int hash = 0;
+
+ @Override
+ public int hashCode() {
+ int h = hash;
+
+ if (h == 0) {
+ h = totalLength;
+ h = partialHash(h, 0, totalLength);
+ if (h == 0) {
+ h = 1;
+ }
+ hash = h;
+ }
+ return h;
+ }
+
+ @Override
+ protected int peekCachedHashCode() {
+ return hash;
+ }
+
+ @Override
+ protected int partialHash(int h, int offset, int length) {
+ int toIndex = offset + length;
+ if (toIndex <= leftLength) {
+ return left.partialHash(h, offset, length);
+ } else if (offset >= leftLength) {
+ return right.partialHash(h, offset - leftLength, length);
+ } else {
+ int leftLength = this.leftLength - offset;
+ int leftPartial = left.partialHash(h, offset, leftLength);
+ return right.partialHash(leftPartial, 0, length - leftLength);
+ }
+ }
+
+ // =================================================================
+ // Input stream
+
+ @Override
+ public CodedInputStream newCodedInput() {
+ return CodedInputStream.newInstance(new RopeInputStream());
+ }
+
+ @Override
+ public InputStream newInput() {
+ return new RopeInputStream();
+ }
+
+ /**
+ * This class implements the balancing algorithm of BAP95. In the paper the
+ * authors use an array to keep track of pieces, while here we use a stack.
+ * The tree is balanced by traversing subtrees in left to right order, and the
+ * stack always contains the part of the string we've traversed so far.
+ *
+ * <p>One surprising aspect of the algorithm is the result of balancing is not
+ * necessarily balanced, though it is nearly balanced. For details, see
+ * BAP95.
+ */
+ private static class Balancer {
+ // Stack containing the part of the string, starting from the left, that
+ // we've already traversed. The final string should be the equivalent of
+ // concatenating the strings on the stack from bottom to top.
+ private final Stack<ByteString> prefixesStack = new Stack<ByteString>();
+
+ private ByteString balance(ByteString left, ByteString right) {
+ doBalance(left);
+ doBalance(right);
+
+ // Sweep stack to gather the result
+ ByteString partialString = prefixesStack.pop();
+ while (!prefixesStack.isEmpty()) {
+ ByteString newLeft = prefixesStack.pop();
+ partialString = new RopeByteString(newLeft, partialString);
+ }
+ // We should end up with a RopeByteString since at a minimum we will
+ // create one from concatenating left and right
+ return partialString;
+ }
+
+ private void doBalance(ByteString root) {
+ // BAP95: Insert balanced subtrees whole. This means the result might not
+ // be balanced, leading to repeated rebalancings on concatenate. However,
+ // these rebalancings are shallow due to ignoring balanced subtrees, and
+ // relatively few calls to insert() result.
+ if (root.isBalanced()) {
+ insert(root);
+ } else if (root instanceof RopeByteString) {
+ RopeByteString rbs = (RopeByteString) root;
+ doBalance(rbs.left);
+ doBalance(rbs.right);
+ } else {
+ throw new IllegalArgumentException(
+ "Has a new type of ByteString been created? Found " +
+ root.getClass());
+ }
+ }
+
+ /**
+ * Push a string on the balance stack (BAP95). BAP95 uses an array and
+ * calls the elements in the array 'bins'. We instead use a stack, so the
+ * 'bins' of lengths are represented by differences between the elements of
+ * minLengthByDepth.
+ *
+ * <p>If the length bin for our string, and all shorter length bins, are
+ * empty, we just push it on the stack. Otherwise, we need to start
+ * concatenating, putting the given string in the "middle" and continuing
+ * until we land in an empty length bin that matches the length of our
+ * concatenation.
+ *
+ * @param byteString string to place on the balance stack
+ */
+ private void insert(ByteString byteString) {
+ int depthBin = getDepthBinForLength(byteString.size());
+ int binEnd = minLengthByDepth[depthBin + 1];
+
+ // BAP95: Concatenate all trees occupying bins representing the length of
+ // our new piece or of shorter pieces, to the extent that is possible.
+ // The goal is to clear the bin which our piece belongs in, but that may
+ // not be entirely possible if there aren't enough longer bins occupied.
+ if (prefixesStack.isEmpty() || prefixesStack.peek().size() >= binEnd) {
+ prefixesStack.push(byteString);
+ } else {
+ int binStart = minLengthByDepth[depthBin];
+
+ // Concatenate the subtrees of shorter length
+ ByteString newTree = prefixesStack.pop();
+ while (!prefixesStack.isEmpty()
+ && prefixesStack.peek().size() < binStart) {
+ ByteString left = prefixesStack.pop();
+ newTree = new RopeByteString(left, newTree);
+ }
+
+ // Concatenate the given string
+ newTree = new RopeByteString(newTree, byteString);
+
+ // Continue concatenating until we land in an empty bin
+ while (!prefixesStack.isEmpty()) {
+ depthBin = getDepthBinForLength(newTree.size());
+ binEnd = minLengthByDepth[depthBin + 1];
+ if (prefixesStack.peek().size() < binEnd) {
+ ByteString left = prefixesStack.pop();
+ newTree = new RopeByteString(left, newTree);
+ } else {
+ break;
+ }
+ }
+ prefixesStack.push(newTree);
+ }
+ }
+
+ private int getDepthBinForLength(int length) {
+ int depth = Arrays.binarySearch(minLengthByDepth, length);
+ if (depth < 0) {
+ // It wasn't an exact match, so convert to the index of the containing
+ // fragment, which is one less even than the insertion point.
+ int insertionPoint = -(depth + 1);
+ depth = insertionPoint - 1;
+ }
+
+ return depth;
+ }
+ }
+
+ /**
+ * This class is a continuable tree traversal, which keeps the state
+ * information which would exist on the stack in a recursive traversal instead
+ * on a stack of "Bread Crumbs". The maximum depth of the stack in this
+ * iterator is the same as the depth of the tree being traversed.
+ *
+ * <p>This iterator is used to implement
+ * {@link RopeByteString#equalsFragments(ByteString)}.
+ */
+ private static class PieceIterator implements Iterator<LiteralByteString> {
+
+ private final Stack<RopeByteString> breadCrumbs =
+ new Stack<RopeByteString>();
+ private LiteralByteString next;
+
+ private PieceIterator(ByteString root) {
+ next = getLeafByLeft(root);
+ }
+
+ private LiteralByteString getLeafByLeft(ByteString root) {
+ ByteString pos = root;
+ while (pos instanceof RopeByteString) {
+ RopeByteString rbs = (RopeByteString) pos;
+ breadCrumbs.push(rbs);
+ pos = rbs.left;
+ }
+ return (LiteralByteString) pos;
+ }
+
+ private LiteralByteString getNextNonEmptyLeaf() {
+ while (true) {
+ // Almost always, we go through this loop exactly once. However, if
+ // we discover an empty string in the rope, we toss it and try again.
+ if (breadCrumbs.isEmpty()) {
+ return null;
+ } else {
+ LiteralByteString result = getLeafByLeft(breadCrumbs.pop().right);
+ if (!result.isEmpty()) {
+ return result;
+ }
+ }
+ }
+ }
+
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ /**
+ * Returns the next item and advances one {@code LiteralByteString}.
+ *
+ * @return next non-empty LiteralByteString or {@code null}
+ */
+ public LiteralByteString next() {
+ if (next == null) {
+ throw new NoSuchElementException();
+ }
+ LiteralByteString result = next;
+ next = getNextNonEmptyLeaf();
+ return result;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ // =================================================================
+ // Serializable
+
+ private static final long serialVersionUID = 1L;
+
+ Object writeReplace() {
+ return new LiteralByteString(toByteArray());
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException {
+ throw new InvalidObjectException(
+ "RopeByteStream instances are not to be serialized directly");
+ }
+
+ // =================================================================
+ // ByteIterator
+
+ @Override
+ public ByteIterator iterator() {
+ return new RopeByteIterator();
+ }
+
+ private class RopeByteIterator implements ByteString.ByteIterator {
+
+ private final PieceIterator pieces;
+ private ByteIterator bytes;
+ int bytesRemaining;
+
+ private RopeByteIterator() {
+ pieces = new PieceIterator(RopeByteString.this);
+ bytes = pieces.next().iterator();
+ bytesRemaining = size();
+ }
+
+ public boolean hasNext() {
+ return (bytesRemaining > 0);
+ }
+
+ public Byte next() {
+ return nextByte(); // Does not instantiate a Byte
+ }
+
+ public byte nextByte() {
+ if (!bytes.hasNext()) {
+ bytes = pieces.next().iterator();
+ }
+ --bytesRemaining;
+ return bytes.nextByte();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * This class is the {@link RopeByteString} equivalent for
+ * {@link ByteArrayInputStream}.
+ */
+ private class RopeInputStream extends InputStream {
+ // Iterates through the pieces of the rope
+ private PieceIterator pieceIterator;
+ // The current piece
+ private LiteralByteString currentPiece;
+ // The size of the current piece
+ private int currentPieceSize;
+ // The index of the next byte to read in the current piece
+ private int currentPieceIndex;
+ // The offset of the start of the current piece in the rope byte string
+ private int currentPieceOffsetInRope;
+ // Offset in the buffer at which user called mark();
+ private int mark;
+
+ public RopeInputStream() {
+ initialize();
+ }
+
+ @Override
+ public int read(byte b[], int offset, int length) {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (offset < 0 || length < 0 || length > b.length - offset) {
+ throw new IndexOutOfBoundsException();
+ }
+ return readSkipInternal(b, offset, length);
+ }
+
+ @Override
+ public long skip(long length) {
+ if (length < 0) {
+ throw new IndexOutOfBoundsException();
+ } else if (length > Integer.MAX_VALUE) {
+ length = Integer.MAX_VALUE;
+ }
+ return readSkipInternal(null, 0, (int) length);
+ }
+
+ /**
+ * Internal implementation of read and skip. If b != null, then read the
+ * next {@code length} bytes into the buffer {@code b} at
+ * offset {@code offset}. If b == null, then skip the next {@code length)
+ * bytes.
+ * <p>
+ * This method assumes that all error checking has already happened.
+ * <p>
+ * Returns the actual number of bytes read or skipped.
+ */
+ private int readSkipInternal(byte b[], int offset, int length) {
+ int bytesRemaining = length;
+ while (bytesRemaining > 0) {
+ advanceIfCurrentPieceFullyRead();
+ if (currentPiece == null) {
+ if (bytesRemaining == length) {
+ // We didn't manage to read anything
+ return -1;
+ }
+ break;
+ } else {
+ // Copy the bytes from this piece.
+ int currentPieceRemaining = currentPieceSize - currentPieceIndex;
+ int count = Math.min(currentPieceRemaining, bytesRemaining);
+ if (b != null) {
+ currentPiece.copyTo(b, currentPieceIndex, offset, count);
+ offset += count;
+ }
+ currentPieceIndex += count;
+ bytesRemaining -= count;
+ }
+ }
+ // Return the number of bytes read.
+ return length - bytesRemaining;
+ }
+
+ @Override
+ public int read() throws IOException {
+ advanceIfCurrentPieceFullyRead();
+ if (currentPiece == null) {
+ return -1;
+ } else {
+ return currentPiece.byteAt(currentPieceIndex++) & 0xFF;
+ }
+ }
+
+ @Override
+ public int available() throws IOException {
+ int bytesRead = currentPieceOffsetInRope + currentPieceIndex;
+ return RopeByteString.this.size() - bytesRead;
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public void mark(int readAheadLimit) {
+ // Set the mark to our position in the byte string
+ mark = currentPieceOffsetInRope + currentPieceIndex;
+ }
+
+ @Override
+ public synchronized void reset() {
+ // Just reinitialize and skip the specified number of bytes.
+ initialize();
+ readSkipInternal(null, 0, mark);
+ }
+
+ /** Common initialization code used by both the constructor and reset() */
+ private void initialize() {
+ pieceIterator = new PieceIterator(RopeByteString.this);
+ currentPiece = pieceIterator.next();
+ currentPieceSize = currentPiece.size();
+ currentPieceIndex = 0;
+ currentPieceOffsetInRope = 0;
+ }
+
+ /**
+ * Skips to the next piece if we have read all the data in the current
+ * piece. Sets currentPiece to null if we have reached the end of the
+ * input.
+ */
+ private void advanceIfCurrentPieceFullyRead() {
+ if (currentPiece != null && currentPieceIndex == currentPieceSize) {
+ // Generally, we can only go through this loop at most once, since
+ // empty strings can't end up in a rope. But better to test.
+ currentPieceOffsetInRope += currentPieceSize;
+ currentPieceIndex = 0;
+ if (pieceIterator.hasNext()) {
+ currentPiece = pieceIterator.next();
+ currentPieceSize = currentPiece.size();
+ } else {
+ currentPiece = null;
+ currentPieceSize = 0;
+ }
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcCallback.java b/java/src/main/java/com/google/protobuf/RpcCallback.java
index 1fd35ed3..10752968 100644
--- a/java/src/main/java/com/google/protobuf/RpcCallback.java
+++ b/java/src/main/java/com/google/protobuf/RpcCallback.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/main/java/com/google/protobuf/RpcChannel.java b/java/src/main/java/com/google/protobuf/RpcChannel.java
index c6ec54fc..f272f4ad 100644
--- a/java/src/main/java/com/google/protobuf/RpcChannel.java
+++ b/java/src/main/java/com/google/protobuf/RpcChannel.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/main/java/com/google/protobuf/RpcController.java b/java/src/main/java/com/google/protobuf/RpcController.java
index aaa5446d..a92dd7be 100644
--- a/java/src/main/java/com/google/protobuf/RpcController.java
+++ b/java/src/main/java/com/google/protobuf/RpcController.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/main/java/com/google/protobuf/RpcUtil.java b/java/src/main/java/com/google/protobuf/RpcUtil.java
index b1b959a8..694b8d13 100644
--- a/java/src/main/java/com/google/protobuf/RpcUtil.java
+++ b/java/src/main/java/com/google/protobuf/RpcUtil.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -91,9 +91,8 @@ public final class RpcUtil {
@SuppressWarnings("unchecked")
private static <Type extends Message> Type copyAsType(
final Type typeDefaultInstance, final Message source) {
- return (Type)typeDefaultInstance.newBuilderForType()
- .mergeFrom(source)
- .build();
+ return (Type) typeDefaultInstance
+ .newBuilderForType().mergeFrom(source).build();
}
/**
diff --git a/java/src/main/java/com/google/protobuf/Service.java b/java/src/main/java/com/google/protobuf/Service.java
index 541585f4..ba7b033e 100644
--- a/java/src/main/java/com/google/protobuf/Service.java
+++ b/java/src/main/java/com/google/protobuf/Service.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/main/java/com/google/protobuf/ServiceException.java b/java/src/main/java/com/google/protobuf/ServiceException.java
index cde669d6..00d57075 100644
--- a/java/src/main/java/com/google/protobuf/ServiceException.java
+++ b/java/src/main/java/com/google/protobuf/ServiceException.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/main/java/com/google/protobuf/SingleFieldBuilder.java b/java/src/main/java/com/google/protobuf/SingleFieldBuilder.java
index d4475f66..aba65e32 100644
--- a/java/src/main/java/com/google/protobuf/SingleFieldBuilder.java
+++ b/java/src/main/java/com/google/protobuf/SingleFieldBuilder.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -31,23 +31,23 @@
package com.google.protobuf;
/**
- * <code>SingleFieldBuilder</code> implements a structure that a protocol
+ * {@code SingleFieldBuilder} implements a structure that a protocol
* message uses to hold a single field of another protocol message. It supports
* the classical use case of setting an immutable {@link Message} as the value
* of the field and is highly optimized around this.
* <br>
* It also supports the additional use case of setting a {@link Message.Builder}
- * as the field and deferring conversion of that <code>Builder</code>
- * to an immutable <code>Message</code>. In this way, it's possible to maintain
- * a tree of <code>Builder</code>'s that acts as a fully read/write data
+ * as the field and deferring conversion of that {@code Builder}
+ * to an immutable {@code Message}. In this way, it's possible to maintain
+ * a tree of {@code Builder}'s that acts as a fully read/write data
* structure.
* <br>
* Logically, one can think of a tree of builders as converting the entire tree
* to messages when build is called on the root or when any method is called
* that desires a Message instead of a Builder. In terms of the implementation,
- * the <code>SingleFieldBuilder</code> and <code>RepeatedFieldBuilder</code>
+ * the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
* classes cache messages that were created so that messages only need to be
- * created when some change occured in its builder or a builder for one of its
+ * created when some change occurred in its builder or a builder for one of its
* descendants.
*
* @param <MType> the type of message for the field
@@ -99,7 +99,7 @@ public class SingleFieldBuilder
/**
* Get the message for the field. If the message is currently stored
- * as a <code>Builder</code>, it is converted to a <code>Message</code> by
+ * as a {@code Builder}, it is converted to a {@code Message} by
* calling {@link Message.Builder#buildPartial} on it. If no message has
* been set, returns the default instance of the message.
*
diff --git a/java/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/src/main/java/com/google/protobuf/SmallSortedMap.java
index 1cf270f3..0674d2e2 100644
--- a/java/src/main/java/com/google/protobuf/SmallSortedMap.java
+++ b/java/src/main/java/com/google/protobuf/SmallSortedMap.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -51,14 +51,14 @@ import java.util.SortedMap;
* remaining entries are stored in an overflow map. Iteration over the entries
* in the map should be done as follows:
*
- * <pre>
- * for (int i = 0; i &lt; fieldMap.getNumArrayEntries(); i++) {
+ * <pre> {@code
+ * for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) {
* process(fieldMap.getArrayEntryAt(i));
* }
- * for (Map.Entry&lt;K, V&gt; entry : fieldMap.getOverflowEntries()) {
+ * for (Map.Entry<K, V> entry : fieldMap.getOverflowEntries()) {
* process(entry);
* }
- * </pre>
+ * }</pre>
*
* The resulting iteration is in order of ascending field tag number. The
* object returned by {@link #entrySet()} adheres to the same contract but is
@@ -394,7 +394,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
/**
* Entry implementation that implements Comparable in order to support
- * binary search witin the entry array. Also checks mutability in
+ * binary search within the entry array. Also checks mutability in
* {@link #setValue()}.
*/
private class Entry implements Map.Entry<K, V>, Comparable<Entry> {
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
index d5fbdabf..dd2b4600 100644
--- a/java/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/src/main/java/com/google/protobuf/TextFormat.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -31,17 +31,18 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
-import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
import java.io.IOException;
-import java.nio.CharBuffer;
import java.math.BigInteger;
+import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -55,16 +56,23 @@ import java.util.regex.Pattern;
public final class TextFormat {
private TextFormat() {}
- private static final Printer DEFAULT_PRINTER = new Printer(false);
- private static final Printer SINGLE_LINE_PRINTER = new Printer(true);
+ private static final Logger logger =
+ Logger.getLogger(TextFormat.class.getName());
+
+ private static final Printer DEFAULT_PRINTER = new Printer();
+ private static final Printer SINGLE_LINE_PRINTER =
+ (new Printer()).setSingleLineMode(true);
+ private static final Printer UNICODE_PRINTER =
+ (new Printer()).setEscapeNonAscii(false);
/**
* Outputs a textual representation of the Protocol Message supplied into
* the parameter output. (This representation is the new version of the
* classic "ProtocolPrinter" output from the original Protocol Buffer system)
*/
- public static void print(final Message message, final Appendable output)
- throws IOException {
+ public static void print(
+ final MessageOrBuilder message, final Appendable output)
+ throws IOException {
DEFAULT_PRINTER.print(message, new TextGenerator(output));
}
@@ -76,10 +84,30 @@ public final class TextFormat {
}
/**
+ * Same as {@code print()}, except that non-ASCII characters are not
+ * escaped.
+ */
+ public static void printUnicode(
+ final MessageOrBuilder message, final Appendable output)
+ throws IOException {
+ UNICODE_PRINTER.print(message, new TextGenerator(output));
+ }
+
+ /**
+ * Same as {@code print()}, except that non-ASCII characters are not
+ * escaped.
+ */
+ public static void printUnicode(final UnknownFieldSet fields,
+ final Appendable output)
+ throws IOException {
+ UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(output));
+ }
+
+ /**
* Generates a human readable form of this message, useful for debugging and
* other purposes, with no newline characters.
*/
- public static String shortDebugString(final Message message) {
+ public static String shortDebugString(final MessageOrBuilder message) {
try {
final StringBuilder sb = new StringBuilder();
SINGLE_LINE_PRINTER.print(message, new TextGenerator(sb));
@@ -109,7 +137,7 @@ public final class TextFormat {
* Like {@code print()}, but writes directly to a {@code String} and
* returns it.
*/
- public static String printToString(final Message message) {
+ public static String printToString(final MessageOrBuilder message) {
try {
final StringBuilder text = new StringBuilder();
print(message, text);
@@ -133,6 +161,34 @@ public final class TextFormat {
}
}
+ /**
+ * Same as {@code printToString()}, except that non-ASCII characters
+ * in string type fields are not escaped in backslash+octals.
+ */
+ public static String printToUnicodeString(final MessageOrBuilder message) {
+ try {
+ final StringBuilder text = new StringBuilder();
+ UNICODE_PRINTER.print(message, new TextGenerator(text));
+ return text.toString();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Same as {@code printToString()}, except that non-ASCII characters
+ * in string type fields are not escaped in backslash+octals.
+ */
+ public static String printToUnicodeString(final UnknownFieldSet fields) {
+ try {
+ final StringBuilder text = new StringBuilder();
+ UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(text));
+ return text.toString();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
public static void printField(final FieldDescriptor field,
final Object value,
final Appendable output)
@@ -216,13 +272,27 @@ public final class TextFormat {
/** Helper class for converting protobufs to text. */
private static final class Printer {
/** Whether to omit newlines from the output. */
- final boolean singleLineMode;
+ boolean singleLineMode = false;
- private Printer(final boolean singleLineMode) {
+ /** Whether to escape non ASCII characters with backslash and octal. */
+ boolean escapeNonAscii = true;
+
+ private Printer() {}
+
+ /** Setter of singleLineMode */
+ private Printer setSingleLineMode(boolean singleLineMode) {
this.singleLineMode = singleLineMode;
+ return this;
}
- private void print(final Message message, final TextGenerator generator)
+ /** Setter of escapeNonAscii */
+ private Printer setEscapeNonAscii(boolean escapeNonAscii) {
+ this.escapeNonAscii = escapeNonAscii;
+ return this;
+ }
+
+ private void print(
+ final MessageOrBuilder message, final TextGenerator generator)
throws IOException {
for (Map.Entry<FieldDescriptor, Object> field
: message.getAllFields().entrySet()) {
@@ -339,13 +409,20 @@ public final class TextFormat {
case STRING:
generator.print("\"");
- generator.print(escapeText((String) value));
+ generator.print(escapeNonAscii
+ ? escapeText((String) value)
+ : escapeDoubleQuotesAndBackslashes((String) value)
+ .replace("\n", "\\n"));
generator.print("\"");
break;
case BYTES:
generator.print("\"");
- generator.print(escapeBytes((ByteString) value));
+ if (value instanceof ByteString) {
+ generator.print(escapeBytes((ByteString) value));
+ } else {
+ generator.print(escapeBytes((byte[]) value));
+ }
generator.print("\"");
break;
@@ -409,16 +486,16 @@ public final class TextFormat {
}
/** Convert an unsigned 32-bit integer to a string. */
- private static String unsignedToString(final int value) {
+ public static String unsignedToString(final int value) {
if (value >= 0) {
return Integer.toString(value);
} else {
- return Long.toString(((long) value) & 0x00000000FFFFFFFFL);
+ return Long.toString(value & 0x00000000FFFFFFFFL);
}
}
/** Convert an unsigned 64-bit integer to a string. */
- private static String unsignedToString(final long value) {
+ public static String unsignedToString(final long value) {
if (value >= 0) {
return Long.toString(value);
} else {
@@ -472,17 +549,16 @@ public final class TextFormat {
for (int i = 0; i < size; i++) {
if (text.charAt(i) == '\n') {
- write(text.subSequence(pos, size), i - pos + 1);
+ write(text.subSequence(pos, i + 1));
pos = i + 1;
atStartOfLine = true;
}
}
- write(text.subSequence(pos, size), size - pos);
+ write(text.subSequence(pos, size));
}
- private void write(final CharSequence data, final int size)
- throws IOException {
- if (size == 0) {
+ private void write(final CharSequence data) throws IOException {
+ if (data.length() == 0) {
return;
}
if (atStartOfLine) {
@@ -541,7 +617,7 @@ public final class TextFormat {
private int previousLine = 0;
private int previousColumn = 0;
- // We use possesive quantifiers (*+ and ++) because otherwise the Java
+ // We use possessive quantifiers (*+ and ++) because otherwise the Java
// regex matcher has stack overflows on large inputs.
private static final Pattern WHITESPACE =
Pattern.compile("(\\s|(#.*$))++", Pattern.MULTILINE);
@@ -654,8 +730,16 @@ public final class TextFormat {
}
final char c = currentToken.charAt(0);
- return ('0' <= c && c <= '9') ||
- c == '-' || c == '+';
+ return ('0' <= c && c <= '9')
+ || c == '-' || c == '+';
+ }
+
+ /**
+ * Returns {@code true} if the current token's text is equal to that
+ * specified.
+ */
+ public boolean lookingAt(String text) {
+ return currentToken.equals(text);
}
/**
@@ -665,13 +749,14 @@ public final class TextFormat {
public String consumeIdentifier() throws ParseException {
for (int i = 0; i < currentToken.length(); i++) {
final char c = currentToken.charAt(i);
- if (('a' <= c && c <= 'z') ||
- ('A' <= c && c <= 'Z') ||
- ('0' <= c && c <= '9') ||
- (c == '_') || (c == '.')) {
+ if (('a' <= c && c <= 'z')
+ || ('A' <= c && c <= 'Z')
+ || ('0' <= c && c <= '9')
+ || (c == '_') || (c == '.')) {
// OK
} else {
- throw parseException("Expected identifier.");
+ throw parseException(
+ "Expected identifier. Found '" + currentToken + "'");
}
}
@@ -681,6 +766,19 @@ public final class TextFormat {
}
/**
+ * If the next token is an identifier, consume it and return {@code true}.
+ * Otherwise, return {@code false} without doing anything.
+ */
+ public boolean tryConsumeIdentifier() {
+ try {
+ consumeIdentifier();
+ return true;
+ } catch (ParseException e) {
+ return false;
+ }
+ }
+
+ /**
* If the next token is a 32-bit signed integer, consume it and return its
* value. Otherwise, throw a {@link ParseException}.
*/
@@ -723,6 +821,19 @@ public final class TextFormat {
}
/**
+ * If the next token is a 64-bit signed integer, consume it and return
+ * {@code true}. Otherwise, return {@code false} without doing anything.
+ */
+ public boolean tryConsumeInt64() {
+ try {
+ consumeInt64();
+ return true;
+ } catch (ParseException e) {
+ return false;
+ }
+ }
+
+ /**
* If the next token is a 64-bit unsigned integer, consume it and return its
* value. Otherwise, throw a {@link ParseException}.
*/
@@ -737,6 +848,19 @@ public final class TextFormat {
}
/**
+ * If the next token is a 64-bit unsigned integer, consume it and return
+ * {@code true}. Otherwise, return {@code false} without doing anything.
+ */
+ public boolean tryConsumeUInt64() {
+ try {
+ consumeUInt64();
+ return true;
+ } catch (ParseException e) {
+ return false;
+ }
+ }
+
+ /**
* If the next token is a double, consume it and return its value.
* Otherwise, throw a {@link ParseException}.
*/
@@ -762,6 +886,19 @@ public final class TextFormat {
}
/**
+ * If the next token is a double, consume it and return {@code true}.
+ * Otherwise, return {@code false} without doing anything.
+ */
+ public boolean tryConsumeDouble() {
+ try {
+ consumeDouble();
+ return true;
+ } catch (ParseException e) {
+ return false;
+ }
+ }
+
+ /**
* If the next token is a float, consume it and return its value.
* Otherwise, throw a {@link ParseException}.
*/
@@ -787,18 +924,31 @@ public final class TextFormat {
}
/**
+ * If the next token is a float, consume it and return {@code true}.
+ * Otherwise, return {@code false} without doing anything.
+ */
+ public boolean tryConsumeFloat() {
+ try {
+ consumeFloat();
+ return true;
+ } catch (ParseException e) {
+ return false;
+ }
+ }
+
+ /**
* If the next token is a boolean, consume it and return its value.
* Otherwise, throw a {@link ParseException}.
*/
public boolean consumeBoolean() throws ParseException {
- if (currentToken.equals("true") ||
- currentToken.equals("t") ||
- currentToken.equals("1")) {
+ if (currentToken.equals("true")
+ || currentToken.equals("t")
+ || currentToken.equals("1")) {
nextToken();
return true;
- } else if (currentToken.equals("false") ||
- currentToken.equals("f") ||
- currentToken.equals("0")) {
+ } else if (currentToken.equals("false")
+ || currentToken.equals("f")
+ || currentToken.equals("0")) {
nextToken();
return false;
} else {
@@ -815,6 +965,19 @@ public final class TextFormat {
}
/**
+ * If the next token is a string, consume it and return true. Otherwise,
+ * return false.
+ */
+ public boolean tryConsumeString() {
+ try {
+ consumeString();
+ return true;
+ } catch (ParseException e) {
+ return false;
+ }
+ }
+
+ /**
* If the next token is a string, consume it, unescape it as a
* {@link ByteString}, and return it. Otherwise, throw a
* {@link ParseException}.
@@ -834,15 +997,17 @@ public final class TextFormat {
* multiple adjacent tokens which are automatically concatenated, like in
* C or Python.
*/
- private void consumeByteString(List<ByteString> list) throws ParseException {
- final char quote = currentToken.length() > 0 ? currentToken.charAt(0)
- : '\0';
+ private void consumeByteString(List<ByteString> list)
+ throws ParseException {
+ final char quote = currentToken.length() > 0
+ ? currentToken.charAt(0)
+ : '\0';
if (quote != '\"' && quote != '\'') {
throw parseException("Expected string.");
}
- if (currentToken.length() < 2 ||
- currentToken.charAt(currentToken.length() - 1) != quote) {
+ if (currentToken.length() < 2
+ || currentToken.charAt(currentToken.length() - 1) != quote) {
throw parseException("String missing ending quote.");
}
@@ -864,7 +1029,7 @@ public final class TextFormat {
public ParseException parseException(final String description) {
// Note: People generally prefer one-based line and column numbers.
return new ParseException(
- (line + 1) + ":" + (column + 1) + ": " + description);
+ line + 1, column + 1, description);
}
/**
@@ -875,7 +1040,7 @@ public final class TextFormat {
final String description) {
// Note: People generally prefer one-based line and column numbers.
return new ParseException(
- (previousLine + 1) + ":" + (previousColumn + 1) + ": " + description);
+ previousLine + 1, previousColumn + 1, description);
}
/**
@@ -900,11 +1065,58 @@ public final class TextFormat {
public static class ParseException extends IOException {
private static final long serialVersionUID = 3196188060225107702L;
+ private final int line;
+ private final int column;
+
+ /** Create a new instance, with -1 as the line and column numbers. */
public ParseException(final String message) {
- super(message);
+ this(-1, -1, message);
+ }
+
+ /**
+ * Create a new instance
+ *
+ * @param line the line number where the parse error occurred,
+ * using 1-offset.
+ * @param column the column number where the parser error occurred,
+ * using 1-offset.
+ */
+ public ParseException(final int line, final int column,
+ final String message) {
+ super(Integer.toString(line) + ":" + column + ": " + message);
+ this.line = line;
+ this.column = column;
+ }
+
+ /**
+ * Return the line where the parse exception occurred, or -1 when
+ * none is provided. The value is specified as 1-offset, so the first
+ * line is line 1.
+ */
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * Return the column where the parse exception occurred, or -1 when
+ * none is provided. The value is specified as 1-offset, so the first
+ * line is line 1.
+ */
+ public int getColumn() {
+ return column;
}
}
+ private static final Parser PARSER = Parser.newBuilder().build();
+
+ /**
+ * Return a {@link Parser} instance which can parse text-format
+ * messages. The returned instance is thread-safe.
+ */
+ public static Parser getParser() {
+ return PARSER;
+ }
+
/**
* Parse a text-format message from {@code input} and merge the contents
* into {@code builder}.
@@ -912,7 +1124,7 @@ public final class TextFormat {
public static void merge(final Readable input,
final Message.Builder builder)
throws IOException {
- merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+ PARSER.merge(input, builder);
}
/**
@@ -922,7 +1134,7 @@ public final class TextFormat {
public static void merge(final CharSequence input,
final Message.Builder builder)
throws ParseException {
- merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+ PARSER.merge(input, builder);
}
/**
@@ -934,35 +1146,9 @@ public final class TextFormat {
final ExtensionRegistry extensionRegistry,
final Message.Builder builder)
throws IOException {
- // Read the entire input to a String then parse that.
-
- // If StreamTokenizer were not quite so crippled, or if there were a kind
- // of Reader that could read in chunks that match some particular regex,
- // or if we wanted to write a custom Reader to tokenize our stream, then
- // we would not have to read to one big String. Alas, none of these is
- // the case. Oh well.
-
- merge(toStringBuilder(input), extensionRegistry, builder);
+ PARSER.merge(input, extensionRegistry, builder);
}
- private static final int BUFFER_SIZE = 4096;
-
- // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
- // overhead is worthwhile
- private static StringBuilder toStringBuilder(final Readable input)
- throws IOException {
- final StringBuilder text = new StringBuilder();
- final CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
- while (true) {
- final int n = input.read(buffer);
- if (n == -1) {
- break;
- }
- buffer.flip();
- text.append(buffer, 0, n);
- }
- return text;
- }
/**
* Parse a text-format message from {@code input} and merge the contents
@@ -973,187 +1159,475 @@ public final class TextFormat {
final ExtensionRegistry extensionRegistry,
final Message.Builder builder)
throws ParseException {
- final Tokenizer tokenizer = new Tokenizer(input);
-
- while (!tokenizer.atEnd()) {
- mergeField(tokenizer, extensionRegistry, builder);
- }
+ PARSER.merge(input, extensionRegistry, builder);
}
+
/**
- * Parse a single field from {@code tokenizer} and merge it into
- * {@code builder}.
+ * Parser for text-format proto2 instances. This class is thread-safe.
+ * The implementation largely follows google/protobuf/text_format.cc.
+ *
+ * <p>Use {@link TextFormat#getParser()} to obtain the default parser, or
+ * {@link Builder} to control the parser behavior.
*/
- private static void mergeField(final Tokenizer tokenizer,
- final ExtensionRegistry extensionRegistry,
- final Message.Builder builder)
- throws ParseException {
- FieldDescriptor field;
- final Descriptor type = builder.getDescriptorForType();
- ExtensionRegistry.ExtensionInfo extension = null;
+ public static class Parser {
+ /**
+ * Determines if repeated values for non-repeated fields and
+ * oneofs are permitted. For example, given required/optional field "foo"
+ * and a oneof containing "baz" and "qux":
+ * <li>
+ * <ul>"foo: 1 foo: 2"
+ * <ul>"baz: 1 qux: 2"
+ * <ul>merging "foo: 2" into a proto in which foo is already set, or
+ * <ul>merging "qux: 2" into a proto in which baz is already set.
+ * </li>
+ */
+ public enum SingularOverwritePolicy {
+ /** The last value is retained. */
+ ALLOW_SINGULAR_OVERWRITES,
+ /** An error is issued. */
+ FORBID_SINGULAR_OVERWRITES
+ }
- if (tokenizer.tryConsume("[")) {
- // An extension.
- final StringBuilder name =
- new StringBuilder(tokenizer.consumeIdentifier());
- while (tokenizer.tryConsume(".")) {
- name.append('.');
- name.append(tokenizer.consumeIdentifier());
- }
+ private final boolean allowUnknownFields;
+ private final SingularOverwritePolicy singularOverwritePolicy;
- extension = extensionRegistry.findExtensionByName(name.toString());
+ private Parser(boolean allowUnknownFields,
+ SingularOverwritePolicy singularOverwritePolicy) {
+ this.allowUnknownFields = allowUnknownFields;
+ this.singularOverwritePolicy = singularOverwritePolicy;
+ }
+
+ /**
+ * Returns a new instance of {@link Builder}.
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
- if (extension == null) {
- throw tokenizer.parseExceptionPreviousToken(
- "Extension \"" + name + "\" not found in the ExtensionRegistry.");
- } else if (extension.descriptor.getContainingType() != type) {
- throw tokenizer.parseExceptionPreviousToken(
- "Extension \"" + name + "\" does not extend message type \"" +
- type.getFullName() + "\".");
+ /**
+ * Builder that can be used to obtain new instances of {@link Parser}.
+ */
+ public static class Builder {
+ private boolean allowUnknownFields = false;
+ private SingularOverwritePolicy singularOverwritePolicy =
+ SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
+
+
+ /**
+ * Sets parser behavior when a non-repeated field appears more than once.
+ */
+ public Builder setSingularOverwritePolicy(SingularOverwritePolicy p) {
+ this.singularOverwritePolicy = p;
+ return this;
}
- tokenizer.consume("]");
+ public Parser build() {
+ return new Parser(allowUnknownFields, singularOverwritePolicy);
+ }
+ }
- field = extension.descriptor;
- } else {
- final String name = tokenizer.consumeIdentifier();
- field = type.findFieldByName(name);
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}.
+ */
+ public void merge(final Readable input,
+ final Message.Builder builder)
+ throws IOException {
+ merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+ }
- // Group names are expected to be capitalized as they appear in the
- // .proto file, which actually matches their type names, not their field
- // names.
- if (field == null) {
- // Explicitly specify US locale so that this code does not break when
- // executing in Turkey.
- final String lowerName = name.toLowerCase(Locale.US);
- field = type.findFieldByName(lowerName);
- // If the case-insensitive match worked but the field is NOT a group,
- if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
- field = null;
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}.
+ */
+ public void merge(final CharSequence input,
+ final Message.Builder builder)
+ throws ParseException {
+ merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+ }
+
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}. Extensions will be recognized if they are
+ * registered in {@code extensionRegistry}.
+ */
+ public void merge(final Readable input,
+ final ExtensionRegistry extensionRegistry,
+ final Message.Builder builder)
+ throws IOException {
+ // Read the entire input to a String then parse that.
+
+ // If StreamTokenizer were not quite so crippled, or if there were a kind
+ // of Reader that could read in chunks that match some particular regex,
+ // or if we wanted to write a custom Reader to tokenize our stream, then
+ // we would not have to read to one big String. Alas, none of these is
+ // the case. Oh well.
+
+ merge(toStringBuilder(input), extensionRegistry, builder);
+ }
+
+
+ private static final int BUFFER_SIZE = 4096;
+
+ // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
+ // overhead is worthwhile
+ private static StringBuilder toStringBuilder(final Readable input)
+ throws IOException {
+ final StringBuilder text = new StringBuilder();
+ final CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
+ while (true) {
+ final int n = input.read(buffer);
+ if (n == -1) {
+ break;
}
+ buffer.flip();
+ text.append(buffer, 0, n);
}
- // Again, special-case group names as described above.
- if (field != null && field.getType() == FieldDescriptor.Type.GROUP &&
- !field.getMessageType().getName().equals(name)) {
- field = null;
- }
+ return text;
+ }
- if (field == null) {
- throw tokenizer.parseExceptionPreviousToken(
- "Message type \"" + type.getFullName() +
- "\" has no field named \"" + name + "\".");
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}. Extensions will be recognized if they are
+ * registered in {@code extensionRegistry}.
+ */
+ public void merge(final CharSequence input,
+ final ExtensionRegistry extensionRegistry,
+ final Message.Builder builder)
+ throws ParseException {
+ final Tokenizer tokenizer = new Tokenizer(input);
+ MessageReflection.BuilderAdapter target =
+ new MessageReflection.BuilderAdapter(builder);
+
+ while (!tokenizer.atEnd()) {
+ mergeField(tokenizer, extensionRegistry, target);
}
}
- Object value = null;
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
- tokenizer.tryConsume(":"); // optional
+ /**
+ * Parse a single field from {@code tokenizer} and merge it into
+ * {@code builder}.
+ */
+ private void mergeField(final Tokenizer tokenizer,
+ final ExtensionRegistry extensionRegistry,
+ final MessageReflection.MergeTarget target)
+ throws ParseException {
+ FieldDescriptor field = null;
+ final Descriptor type = target.getDescriptorForType();
+ ExtensionRegistry.ExtensionInfo extension = null;
+
+ if (tokenizer.tryConsume("[")) {
+ // An extension.
+ final StringBuilder name =
+ new StringBuilder(tokenizer.consumeIdentifier());
+ while (tokenizer.tryConsume(".")) {
+ name.append('.');
+ name.append(tokenizer.consumeIdentifier());
+ }
- final String endToken;
- if (tokenizer.tryConsume("<")) {
- endToken = ">";
- } else {
- tokenizer.consume("{");
- endToken = "}";
- }
+ extension = target.findExtensionByName(
+ extensionRegistry, name.toString());
+
+ if (extension == null) {
+ if (!allowUnknownFields) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Extension \"" + name + "\" not found in the ExtensionRegistry.");
+ } else {
+ logger.warning(
+ "Extension \"" + name + "\" not found in the ExtensionRegistry.");
+ }
+ } else {
+ if (extension.descriptor.getContainingType() != type) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Extension \"" + name + "\" does not extend message type \""
+ + type.getFullName() + "\".");
+ }
+ field = extension.descriptor;
+ }
- final Message.Builder subBuilder;
- if (extension == null) {
- subBuilder = builder.newBuilderForField(field);
+ tokenizer.consume("]");
} else {
- subBuilder = extension.defaultInstance.newBuilderForType();
+ final String name = tokenizer.consumeIdentifier();
+ field = type.findFieldByName(name);
+
+ // Group names are expected to be capitalized as they appear in the
+ // .proto file, which actually matches their type names, not their field
+ // names.
+ if (field == null) {
+ // Explicitly specify US locale so that this code does not break when
+ // executing in Turkey.
+ final String lowerName = name.toLowerCase(Locale.US);
+ field = type.findFieldByName(lowerName);
+ // If the case-insensitive match worked but the field is NOT a group,
+ if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
+ field = null;
+ }
+ }
+ // Again, special-case group names as described above.
+ if (field != null && field.getType() == FieldDescriptor.Type.GROUP
+ && !field.getMessageType().getName().equals(name)) {
+ field = null;
+ }
+
+ if (field == null) {
+ if (!allowUnknownFields) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Message type \"" + type.getFullName()
+ + "\" has no field named \"" + name + "\".");
+ } else {
+ logger.warning(
+ "Message type \"" + type.getFullName()
+ + "\" has no field named \"" + name + "\".");
+ }
+ }
}
- while (!tokenizer.tryConsume(endToken)) {
- if (tokenizer.atEnd()) {
- throw tokenizer.parseException(
- "Expected \"" + endToken + "\".");
+ // Skips unknown fields.
+ if (field == null) {
+ // Try to guess the type of this field.
+ // If this field is not a message, there should be a ":" between the
+ // field name and the field value and also the field value should not
+ // start with "{" or "<" which indicates the beginning of a message body.
+ // If there is no ":" or there is a "{" or "<" after ":", this field has
+ // to be a message or the input is ill-formed.
+ if (tokenizer.tryConsume(":")
+ && !tokenizer.lookingAt("{")
+ && !tokenizer.lookingAt("<")) {
+ skipFieldValue(tokenizer);
+ } else {
+ skipFieldMessage(tokenizer);
}
- mergeField(tokenizer, extensionRegistry, subBuilder);
+ return;
}
- value = subBuilder.build();
+ // Handle potential ':'.
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ tokenizer.tryConsume(":"); // optional
+ } else {
+ tokenizer.consume(":"); // required
+ }
+ // Support specifying repeated field values as a comma-separated list.
+ // Ex."foo: [1, 2, 3]"
+ if (field.isRepeated() && tokenizer.tryConsume("[")) {
+ while (true) {
+ consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
+ if (tokenizer.tryConsume("]")) {
+ // End of list.
+ break;
+ }
+ tokenizer.consume(",");
+ }
+ } else {
+ consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
+ }
- } else {
- tokenizer.consume(":");
+ // For historical reasons, fields may optionally be separated by commas or
+ // semicolons.
+ if (!tokenizer.tryConsume(";")) {
+ tokenizer.tryConsume(",");
+ }
+ }
- switch (field.getType()) {
- case INT32:
- case SINT32:
- case SFIXED32:
- value = tokenizer.consumeInt32();
- break;
+ /**
+ * Parse a single field value from {@code tokenizer} and merge it into
+ * {@code builder}.
+ */
+ private void consumeFieldValue(
+ final Tokenizer tokenizer,
+ final ExtensionRegistry extensionRegistry,
+ final MessageReflection.MergeTarget target,
+ final FieldDescriptor field,
+ final ExtensionRegistry.ExtensionInfo extension)
+ throws ParseException {
+ Object value = null;
- case INT64:
- case SINT64:
- case SFIXED64:
- value = tokenizer.consumeInt64();
- break;
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ final String endToken;
+ if (tokenizer.tryConsume("<")) {
+ endToken = ">";
+ } else {
+ tokenizer.consume("{");
+ endToken = "}";
+ }
- case UINT32:
- case FIXED32:
- value = tokenizer.consumeUInt32();
- break;
+ final MessageReflection.MergeTarget subField;
+ subField = target.newMergeTargetForField(field,
+ (extension == null) ? null : extension.defaultInstance);
- case UINT64:
- case FIXED64:
- value = tokenizer.consumeUInt64();
- break;
+ while (!tokenizer.tryConsume(endToken)) {
+ if (tokenizer.atEnd()) {
+ throw tokenizer.parseException(
+ "Expected \"" + endToken + "\".");
+ }
+ mergeField(tokenizer, extensionRegistry, subField);
+ }
- case FLOAT:
- value = tokenizer.consumeFloat();
- break;
+ value = subField.finish();
- case DOUBLE:
- value = tokenizer.consumeDouble();
- break;
+ } else {
+ switch (field.getType()) {
+ case INT32:
+ case SINT32:
+ case SFIXED32:
+ value = tokenizer.consumeInt32();
+ break;
+
+ case INT64:
+ case SINT64:
+ case SFIXED64:
+ value = tokenizer.consumeInt64();
+ break;
+
+ case UINT32:
+ case FIXED32:
+ value = tokenizer.consumeUInt32();
+ break;
+
+ case UINT64:
+ case FIXED64:
+ value = tokenizer.consumeUInt64();
+ break;
+
+ case FLOAT:
+ value = tokenizer.consumeFloat();
+ break;
+
+ case DOUBLE:
+ value = tokenizer.consumeDouble();
+ break;
+
+ case BOOL:
+ value = tokenizer.consumeBoolean();
+ break;
+
+ case STRING:
+ value = tokenizer.consumeString();
+ break;
+
+ case BYTES:
+ value = tokenizer.consumeByteString();
+ break;
+
+ case ENUM:
+ final EnumDescriptor enumType = field.getEnumType();
+
+ if (tokenizer.lookingAtInteger()) {
+ final int number = tokenizer.consumeInt32();
+ value = enumType.findValueByNumber(number);
+ if (value == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Enum type \"" + enumType.getFullName()
+ + "\" has no value with number " + number + '.');
+ }
+ } else {
+ final String id = tokenizer.consumeIdentifier();
+ value = enumType.findValueByName(id);
+ if (value == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Enum type \"" + enumType.getFullName()
+ + "\" has no value named \"" + id + "\".");
+ }
+ }
- case BOOL:
- value = tokenizer.consumeBoolean();
- break;
+ break;
- case STRING:
- value = tokenizer.consumeString();
- break;
+ case MESSAGE:
+ case GROUP:
+ throw new RuntimeException("Can't get here.");
+ }
+ }
- case BYTES:
- value = tokenizer.consumeByteString();
- break;
+ if (field.isRepeated()) {
+ target.addRepeatedField(field, value);
+ } else if ((singularOverwritePolicy
+ == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
+ && target.hasField(field)) {
+ throw tokenizer.parseExceptionPreviousToken("Non-repeated field \""
+ + field.getFullName() + "\" cannot be overwritten.");
+ } else if ((singularOverwritePolicy
+ == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
+ && field.getContainingOneof() != null
+ && target.hasOneof(field.getContainingOneof())) {
+ Descriptors.OneofDescriptor oneof = field.getContainingOneof();
+ throw tokenizer.parseExceptionPreviousToken("Field \""
+ + field.getFullName() + "\" is specified along with field \""
+ + target.getOneofFieldDescriptor(oneof).getFullName()
+ + "\", another member of oneof \"" + oneof.getName() + "\".");
+ } else {
+ target.setField(field, value);
+ }
+ }
- case ENUM:
- final EnumDescriptor enumType = field.getEnumType();
-
- if (tokenizer.lookingAtInteger()) {
- final int number = tokenizer.consumeInt32();
- value = enumType.findValueByNumber(number);
- if (value == null) {
- throw tokenizer.parseExceptionPreviousToken(
- "Enum type \"" + enumType.getFullName() +
- "\" has no value with number " + number + '.');
- }
- } else {
- final String id = tokenizer.consumeIdentifier();
- value = enumType.findValueByName(id);
- if (value == null) {
- throw tokenizer.parseExceptionPreviousToken(
- "Enum type \"" + enumType.getFullName() +
- "\" has no value named \"" + id + "\".");
- }
- }
+ /**
+ * Skips the next field including the field's name and value.
+ */
+ private void skipField(Tokenizer tokenizer) throws ParseException {
+ if (tokenizer.tryConsume("[")) {
+ // Extension name.
+ do {
+ tokenizer.consumeIdentifier();
+ } while (tokenizer.tryConsume("."));
+ tokenizer.consume("]");
+ } else {
+ tokenizer.consumeIdentifier();
+ }
- break;
+ // Try to guess the type of this field.
+ // If this field is not a message, there should be a ":" between the
+ // field name and the field value and also the field value should not
+ // start with "{" or "<" which indicates the beginning of a message body.
+ // If there is no ":" or there is a "{" or "<" after ":", this field has
+ // to be a message or the input is ill-formed.
+ if (tokenizer.tryConsume(":")
+ && !tokenizer.lookingAt("<")
+ && !tokenizer.lookingAt("{")) {
+ skipFieldValue(tokenizer);
+ } else {
+ skipFieldMessage(tokenizer);
+ }
+ // For historical reasons, fields may optionally be separated by commas or
+ // semicolons.
+ if (!tokenizer.tryConsume(";")) {
+ tokenizer.tryConsume(",");
+ }
+ }
- case MESSAGE:
- case GROUP:
- throw new RuntimeException("Can't get here.");
+ /**
+ * Skips the whole body of a message including the beginning delimiter and
+ * the ending delimiter.
+ */
+ private void skipFieldMessage(Tokenizer tokenizer) throws ParseException {
+ final String delimiter;
+ if (tokenizer.tryConsume("<")) {
+ delimiter = ">";
+ } else {
+ tokenizer.consume("{");
+ delimiter = "}";
}
+ while (!tokenizer.lookingAt(">") && !tokenizer.lookingAt("}")) {
+ skipField(tokenizer);
+ }
+ tokenizer.consume(delimiter);
}
- if (field.isRepeated()) {
- builder.addRepeatedField(field, value);
- } else {
- builder.setField(field, value);
+ /**
+ * Skips a field value.
+ */
+ private void skipFieldValue(Tokenizer tokenizer) throws ParseException {
+ if (tokenizer.tryConsumeString()) {
+ while (tokenizer.tryConsumeString()) {}
+ return;
+ }
+ if (!tokenizer.tryConsumeIdentifier() // includes enum & boolean
+ && !tokenizer.tryConsumeInt64() // includes int32
+ && !tokenizer.tryConsumeUInt64() // includes uint32
+ && !tokenizer.tryConsumeDouble()
+ && !tokenizer.tryConsumeFloat()) {
+ throw tokenizer.parseException(
+ "Invalid field value: " + tokenizer.currentToken);
+ }
}
}
@@ -1163,6 +1637,11 @@ public final class TextFormat {
// Some of these methods are package-private because Descriptors.java uses
// them.
+ private interface ByteSequence {
+ int size();
+ byte byteAt(int offset);
+ }
+
/**
* Escapes bytes in the format used in protocol buffer text format, which
* is the same as the format used for C string literals. All bytes
@@ -1171,27 +1650,26 @@ public final class TextFormat {
* which no defined short-hand escape sequence is defined will be escaped
* using 3-digit octal sequences.
*/
- static String escapeBytes(final ByteString input) {
+ public static String escapeBytes(final ByteSequence input) {
final StringBuilder builder = new StringBuilder(input.size());
for (int i = 0; i < input.size(); i++) {
final byte b = input.byteAt(i);
switch (b) {
// Java does not recognize \a or \v, apparently.
- case 0x07: builder.append("\\a" ); break;
- case '\b': builder.append("\\b" ); break;
- case '\f': builder.append("\\f" ); break;
- case '\n': builder.append("\\n" ); break;
- case '\r': builder.append("\\r" ); break;
- case '\t': builder.append("\\t" ); break;
- case 0x0b: builder.append("\\v" ); break;
+ case 0x07: builder.append("\\a"); break;
+ case '\b': builder.append("\\b"); break;
+ case '\f': builder.append("\\f"); break;
+ case '\n': builder.append("\\n"); break;
+ case '\r': builder.append("\\r"); break;
+ case '\t': builder.append("\\t"); break;
+ case 0x0b: builder.append("\\v"); break;
case '\\': builder.append("\\\\"); break;
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('\\');
@@ -1206,13 +1684,50 @@ public final class TextFormat {
}
/**
+ * Escapes bytes in the format used in protocol buffer text format, which
+ * is the same as the format used for C string literals. All bytes
+ * that are not printable 7-bit ASCII characters are escaped, as well as
+ * backslash, single-quote, and double-quote characters. Characters for
+ * which no defined short-hand escape sequence is defined will be escaped
+ * using 3-digit octal sequences.
+ */
+ public static String escapeBytes(final ByteString input) {
+ return escapeBytes(new ByteSequence() {
+ @Override
+ public int size() {
+ return input.size();
+ }
+ @Override
+ public byte byteAt(int offset) {
+ return input.byteAt(offset);
+ }
+ });
+ }
+
+ /**
+ * Like {@link #escapeBytes(ByteString)}, but used for byte array.
+ */
+ public static String escapeBytes(final byte[] input) {
+ return escapeBytes(new ByteSequence() {
+ @Override
+ public int size() {
+ return input.length;
+ }
+ @Override
+ public byte byteAt(int offset) {
+ return input[offset];
+ }
+ });
+ }
+
+ /**
* Un-escape a byte sequence as escaped using
* {@link #escapeBytes(ByteString)}. Two-digit hex escapes (starting with
* "\x") are also recognized.
*/
static ByteString unescapeBytes(final CharSequence charString)
throws InvalidEscapeSequenceException {
- // First convert the Java characater sequence to UTF-8 bytes.
+ // First convert the Java character sequence to UTF-8 bytes.
ByteString input = ByteString.copyFromUtf8(charString.toString());
// Then unescape certain byte sequences introduced by ASCII '\\'. The valid
// escapes can all be expressed with ASCII characters, so it is safe to
@@ -1241,7 +1756,7 @@ public final class TextFormat {
code = code * 8 + digitValue(input.byteAt(i));
}
// TODO: Check that 0 <= code && code <= 0xFF.
- result[pos++] = (byte)code;
+ result[pos++] = (byte) code;
} else {
switch (c) {
case 'a' : result[pos++] = 0x07; break;
@@ -1269,12 +1784,12 @@ public final class TextFormat {
++i;
code = code * 16 + digitValue(input.byteAt(i));
}
- result[pos++] = (byte)code;
+ result[pos++] = (byte) code;
break;
default:
throw new InvalidEscapeSequenceException(
- "Invalid escape sequence: '\\" + (char)c + '\'');
+ "Invalid escape sequence: '\\" + (char) c + '\'');
}
}
} else {
@@ -1311,6 +1826,13 @@ public final class TextFormat {
}
/**
+ * Escape double quotes and backslashes in a String for unicode output of a message.
+ */
+ public static String escapeDoubleQuotesAndBackslashes(final String input) {
+ return input.replace("\\", "\\\\").replace("\"", "\\\"");
+ }
+
+ /**
* Un-escape a text string as escaped using {@link #escapeText(String)}.
* Two-digit hex escapes (starting with "\x") are also recognized.
*/
@@ -1326,9 +1848,9 @@ public final class TextFormat {
/** Is this a hex digit? */
private static boolean isHex(final byte c) {
- return ('0' <= c && c <= '9') ||
- ('a' <= c && c <= 'f') ||
- ('A' <= c && c <= 'F');
+ return ('0' <= c && c <= '9')
+ || ('a' <= c && c <= 'f')
+ || ('A' <= c && c <= 'F');
}
/**
@@ -1349,7 +1871,7 @@ public final class TextFormat {
/**
* Parse a 32-bit signed integer from the text. Unlike the Java standard
* {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
- * and "0" to signify hexidecimal and octal numbers, respectively.
+ * and "0" to signify hexadecimal and octal numbers, respectively.
*/
static int parseInt32(final String text) throws NumberFormatException {
return (int) parseInteger(text, true, false);
@@ -1358,7 +1880,7 @@ public final class TextFormat {
/**
* Parse a 32-bit unsigned integer from the text. Unlike the Java standard
* {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
- * and "0" to signify hexidecimal and octal numbers, respectively. The
+ * and "0" to signify hexadecimal and octal numbers, respectively. The
* result is coerced to a (signed) {@code int} when returned since Java has
* no unsigned integer type.
*/
@@ -1369,7 +1891,7 @@ public final class TextFormat {
/**
* Parse a 64-bit signed integer from the text. Unlike the Java standard
* {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
- * and "0" to signify hexidecimal and octal numbers, respectively.
+ * and "0" to signify hexadecimal and octal numbers, respectively.
*/
static long parseInt64(final String text) throws NumberFormatException {
return parseInteger(text, true, true);
@@ -1378,7 +1900,7 @@ public final class TextFormat {
/**
* Parse a 64-bit unsigned integer from the text. Unlike the Java standard
* {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
- * and "0" to signify hexidecimal and octal numbers, respectively. The
+ * and "0" to signify hexadecimal and octal numbers, respectively. The
* result is coerced to a (signed) {@code long} when returned since Java has
* no unsigned long type.
*/
diff --git a/java/src/main/java/com/google/protobuf/UninitializedMessageException.java b/java/src/main/java/com/google/protobuf/UninitializedMessageException.java
index 8743c120..5714c063 100644
--- a/java/src/main/java/com/google/protobuf/UninitializedMessageException.java
+++ b/java/src/main/java/com/google/protobuf/UninitializedMessageException.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
index 26a15d00..7cd2250e 100644
--- a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,7 +46,7 @@ import java.util.TreeMap;
* {@code UnknownFieldSet} 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 feilds are read by old software that was
+ * and then messages containing those fields are read by old software that was
* compiled before the new types were added.
*
* <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
@@ -91,6 +91,7 @@ public final class UnknownFieldSet implements MessageLite {
}
private Map<Integer, Field> fields;
+
@Override
public boolean equals(final Object other) {
if (this == other) {
@@ -367,6 +368,22 @@ public final class UnknownFieldSet implements MessageLite {
reinitialize();
return this;
}
+
+ /** Clear fields from the set with a given field number. */
+ public Builder clearField(final int number) {
+ if (number == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+ if (lastField != null && lastFieldNumber == number) {
+ // Discard this.
+ lastField = null;
+ lastFieldNumber = 0;
+ }
+ if (fields.containsKey(number)) {
+ fields.remove(number);
+ }
+ return this;
+ }
/**
* Merge the fields from {@code other} into this set. If a field number
@@ -414,6 +431,21 @@ public final class UnknownFieldSet implements MessageLite {
return this;
}
+
+ /**
+ * Convenience method for merging a length-delimited field.
+ *
+ * <p>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) {
@@ -468,7 +500,7 @@ public final class UnknownFieldSet implements MessageLite {
/**
* Parse a single field from {@code input} and merge it into this set.
* @param tag The field's tag number, which was already parsed.
- * @return {@code false} if the tag is an engroup tag.
+ * @return {@code false} if the tag is an end group tag.
*/
public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
throws IOException {
@@ -950,4 +982,29 @@ public final class UnknownFieldSet implements MessageLite {
}
}
}
+
+ /**
+ * Parser to implement MessageLite interface.
+ */
+ public static final class Parser extends AbstractParser<UnknownFieldSet> {
+ public UnknownFieldSet parsePartialFrom(
+ CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ Builder builder = newBuilder();
+ try {
+ builder.mergeFrom(input);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(builder.buildPartial());
+ } catch (IOException e) {
+ throw new InvalidProtocolBufferException(e.getMessage())
+ .setUnfinishedMessage(builder.buildPartial());
+ }
+ return builder.buildPartial();
+ }
+ }
+
+ private static final Parser PARSER = new Parser();
+ public final Parser getParserForType() {
+ return PARSER;
+ }
}
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.
+ *
+ * <p>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}.
+ *
+ * <p>For use by generated code only.
+ */
+ public static UnknownFieldSetLite getDefaultInstance() {
+ return DEFAULT_INSTANCE;
+ }
+
+ /**
+ * Create a new {@link Builder}.
+ *
+ * <p>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}.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p>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/main/java/com/google/protobuf/UnmodifiableLazyStringList.java b/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
index 83e5c796..5cc005df 100644
--- a/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
+++ b/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -31,9 +31,12 @@
package com.google.protobuf;
import java.util.AbstractList;
-import java.util.RandomAccess;
-import java.util.ListIterator;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.RandomAccess;
/**
* An implementation of {@link LazyStringList} that wraps another
@@ -71,6 +74,36 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
+ public void set(int index, ByteString element) {
+ throw new UnsupportedOperationException();
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public boolean addAllByteString(Collection<? extends ByteString> element) {
+ throw new UnsupportedOperationException();
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public byte[] getByteArray(int index) {
+ return list.getByteArray(index);
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public void add(byte[] element) {
+ throw new UnsupportedOperationException();
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public void set(int index, byte[] element) {
+ throw new UnsupportedOperationException();
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public boolean addAllByteArray(Collection<byte[]> element) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public ListIterator<String> listIterator(final int index) {
return new ListIterator<String>() {
ListIterator<String> iter = list.listIterator(index);
@@ -143,4 +176,30 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
}
};
}
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public List<?> getUnderlyingElements() {
+ // The returned value is already unmodifiable.
+ return list.getUnderlyingElements();
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public void mergeFrom(LazyStringList other) {
+ throw new UnsupportedOperationException();
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public List<byte[]> asByteArrayList() {
+ return Collections.unmodifiableList(list.asByteArrayList());
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public List<ByteString> asByteStringList() {
+ return Collections.unmodifiableList(list.asByteStringList());
+ }
+
+ //@Override (Java 1.6 override semantics, but we must support 1.5)
+ public LazyStringList getUnmodifiableView() {
+ return this;
+ }
}
diff --git a/java/src/main/java/com/google/protobuf/Utf8.java b/java/src/main/java/com/google/protobuf/Utf8.java
new file mode 100644
index 00000000..4d0ef53b
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Utf8.java
@@ -0,0 +1,349 @@
+// 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;
+
+/**
+ * A set of low-level, high-performance static utility methods related
+ * to the UTF-8 character encoding. This class has no dependencies
+ * outside of the core JDK libraries.
+ *
+ * <p>There are several variants of UTF-8. The one implemented by
+ * this class is the restricted definition of UTF-8 introduced in
+ * Unicode 3.1, which mandates the rejection of "overlong" byte
+ * sequences as well as rejection of 3-byte surrogate codepoint byte
+ * sequences. Note that the UTF-8 decoder included in Oracle's JDK
+ * has been modified to also reject "overlong" byte sequences, but (as
+ * of 2011) still accepts 3-byte surrogate codepoint byte sequences.
+ *
+ * <p>The byte sequences considered valid by this class are exactly
+ * those that can be roundtrip converted to Strings and back to bytes
+ * using the UTF-8 charset, without loss: <pre> {@code
+ * Arrays.equals(bytes, new String(bytes, "UTF-8").getBytes("UTF-8"))
+ * }</pre>
+ *
+ * <p>See the Unicode Standard,</br>
+ * Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
+ * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
+ *
+ * <p>This class supports decoding of partial byte sequences, so that the
+ * bytes in a complete UTF-8 byte sequences can be stored in multiple
+ * segments. Methods typically return {@link #MALFORMED} if the partial
+ * byte sequence is definitely not well-formed, {@link #COMPLETE} if it is
+ * well-formed in the absence of additional input, or if the byte sequence
+ * apparently terminated in the middle of a character, an opaque integer
+ * "state" value containing enough information to decode the character when
+ * passed to a subsequent invocation of a partial decoding method.
+ *
+ * @author martinrb@google.com (Martin Buchholz)
+ */
+final class Utf8 {
+ private Utf8() {}
+
+ /**
+ * State value indicating that the byte sequence is well-formed and
+ * complete (no further bytes are needed to complete a character).
+ */
+ public static final int COMPLETE = 0;
+
+ /**
+ * State value indicating that the byte sequence is definitely not
+ * well-formed.
+ */
+ public static final int MALFORMED = -1;
+
+ // Other state values include the partial bytes of the incomplete
+ // character to be decoded in the simplest way: we pack the bytes
+ // into the state int in little-endian order. For example:
+ //
+ // int state = byte1 ^ (byte2 << 8) ^ (byte3 << 16);
+ //
+ // Such a state is unpacked thus (note the ~ operation for byte2 to
+ // undo byte1's sign-extension bits):
+ //
+ // int byte1 = (byte) state;
+ // int byte2 = (byte) ~(state >> 8);
+ // int byte3 = (byte) (state >> 16);
+ //
+ // We cannot store a zero byte in the state because it would be
+ // indistinguishable from the absence of a byte. But we don't need
+ // to, because partial bytes must always be negative. When building
+ // a state, we ensure that byte1 is negative and subsequent bytes
+ // are valid trailing bytes.
+
+ /**
+ * Returns {@code true} if the given byte array is a well-formed
+ * UTF-8 byte sequence.
+ *
+ * <p>This is a convenience method, equivalent to a call to {@code
+ * isValidUtf8(bytes, 0, bytes.length)}.
+ */
+ public static boolean isValidUtf8(byte[] bytes) {
+ return isValidUtf8(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Returns {@code true} if the given byte array slice is a
+ * well-formed UTF-8 byte sequence. The range of bytes to be
+ * checked extends from index {@code index}, inclusive, to {@code
+ * limit}, exclusive.
+ *
+ * <p>This is a convenience method, equivalent to {@code
+ * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
+ */
+ public static boolean isValidUtf8(byte[] bytes, int index, int limit) {
+ return partialIsValidUtf8(bytes, index, limit) == COMPLETE;
+ }
+
+ /**
+ * Tells whether the given byte array slice is a well-formed,
+ * malformed, or incomplete UTF-8 byte sequence. The range of bytes
+ * to be checked extends from index {@code index}, inclusive, to
+ * {@code limit}, exclusive.
+ *
+ * @param state either {@link Utf8#COMPLETE} (if this is the initial decoding
+ * operation) or the value returned from a call to a partial decoding method
+ * for the previous bytes
+ *
+ * @return {@link #MALFORMED} if the partial byte sequence is
+ * definitely not well-formed, {@link #COMPLETE} if it is well-formed
+ * (no additional input needed), or if the byte sequence is
+ * "incomplete", i.e. apparently terminated in the middle of a character,
+ * an opaque integer "state" value containing enough information to
+ * decode the character when passed to a subsequent invocation of a
+ * partial decoding method.
+ */
+ public static int partialIsValidUtf8(
+ int state, byte[] bytes, int index, int limit) {
+ if (state != COMPLETE) {
+ // The previous decoding operation was incomplete (or malformed).
+ // We look for a well-formed sequence consisting of bytes from
+ // the previous decoding operation (stored in state) together
+ // with bytes from the array slice.
+ //
+ // We expect such "straddler characters" to be rare.
+
+ if (index >= limit) { // No bytes? No progress.
+ return state;
+ }
+ int byte1 = (byte) state;
+ // byte1 is never ASCII.
+ if (byte1 < (byte) 0xE0) {
+ // two-byte form
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2 ||
+ // byte2 trailing-byte test
+ bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else if (byte1 < (byte) 0xF0) {
+ // three-byte form
+
+ // Get byte2 from saved state or array
+ int byte2 = (byte) ~(state >> 8);
+ if (byte2 == 0) {
+ byte2 = bytes[index++];
+ if (index >= limit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ }
+ if (byte2 > (byte) 0xBF ||
+ // overlong? 5 most significant bits must not all be zero
+ (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
+ // illegal surrogate codepoint?
+ (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
+ // byte3 trailing-byte test
+ bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else {
+ // four-byte form
+
+ // Get byte2 and byte3 from saved state or array
+ int byte2 = (byte) ~(state >> 8);
+ int byte3 = 0;
+ if (byte2 == 0) {
+ byte2 = bytes[index++];
+ if (index >= limit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ } else {
+ byte3 = (byte) (state >> 16);
+ }
+ if (byte3 == 0) {
+ byte3 = bytes[index++];
+ if (index >= limit) {
+ return incompleteStateFor(byte1, byte2, byte3);
+ }
+ }
+
+ // If we were called with state == MALFORMED, then byte1 is 0xFF,
+ // which never occurs in well-formed UTF-8, and so we will return
+ // MALFORMED again below.
+
+ if (byte2 > (byte) 0xBF ||
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
+ // byte3 trailing-byte test
+ byte3 > (byte) 0xBF ||
+ // byte4 trailing-byte test
+ bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+
+ return partialIsValidUtf8(bytes, index, limit);
+ }
+
+ /**
+ * Tells whether the given byte array slice is a well-formed,
+ * malformed, or incomplete UTF-8 byte sequence. The range of bytes
+ * to be checked extends from index {@code index}, inclusive, to
+ * {@code limit}, exclusive.
+ *
+ * <p>This is a convenience method, equivalent to a call to {@code
+ * partialIsValidUtf8(Utf8.COMPLETE, bytes, index, limit)}.
+ *
+ * @return {@link #MALFORMED} if the partial byte sequence is
+ * definitely not well-formed, {@link #COMPLETE} if it is well-formed
+ * (no additional input needed), or if the byte sequence is
+ * "incomplete", i.e. apparently terminated in the middle of a character,
+ * an opaque integer "state" value containing enough information to
+ * decode the character when passed to a subsequent invocation of a
+ * partial decoding method.
+ */
+ public static int partialIsValidUtf8(
+ byte[] bytes, int index, int limit) {
+ // Optimize for 100% ASCII.
+ // Hotspot loves small simple top-level loops like this.
+ while (index < limit && bytes[index] >= 0) {
+ index++;
+ }
+
+ return (index >= limit) ? COMPLETE :
+ partialIsValidUtf8NonAscii(bytes, index, limit);
+ }
+
+ private static int partialIsValidUtf8NonAscii(
+ byte[] bytes, int index, int limit) {
+ for (;;) {
+ int byte1, byte2;
+
+ // Optimize for interior runs of ASCII bytes.
+ do {
+ if (index >= limit) {
+ return COMPLETE;
+ }
+ } while ((byte1 = bytes[index++]) >= 0);
+
+ if (byte1 < (byte) 0xE0) {
+ // two-byte form
+
+ if (index >= limit) {
+ return byte1;
+ }
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2 ||
+ bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else if (byte1 < (byte) 0xF0) {
+ // three-byte form
+
+ if (index >= limit - 1) { // incomplete sequence
+ return incompleteStateFor(bytes, index, limit);
+ }
+ if ((byte2 = bytes[index++]) > (byte) 0xBF ||
+ // overlong? 5 most significant bits must not all be zero
+ (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
+ // check for illegal surrogate codepoints
+ (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
+ // byte3 trailing-byte test
+ bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else {
+ // four-byte form
+
+ if (index >= limit - 2) { // incomplete sequence
+ return incompleteStateFor(bytes, index, limit);
+ }
+ if ((byte2 = bytes[index++]) > (byte) 0xBF ||
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
+ // byte3 trailing-byte test
+ bytes[index++] > (byte) 0xBF ||
+ // byte4 trailing-byte test
+ bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+ }
+
+ private static int incompleteStateFor(int byte1) {
+ return (byte1 > (byte) 0xF4) ?
+ MALFORMED : byte1;
+ }
+
+ private static int incompleteStateFor(int byte1, int byte2) {
+ return (byte1 > (byte) 0xF4 ||
+ byte2 > (byte) 0xBF) ?
+ MALFORMED : byte1 ^ (byte2 << 8);
+ }
+
+ private static int incompleteStateFor(int byte1, int byte2, int byte3) {
+ return (byte1 > (byte) 0xF4 ||
+ byte2 > (byte) 0xBF ||
+ byte3 > (byte) 0xBF) ?
+ MALFORMED : byte1 ^ (byte2 << 8) ^ (byte3 << 16);
+ }
+
+ private static int incompleteStateFor(byte[] bytes, int index, int limit) {
+ int byte1 = bytes[index - 1];
+ switch (limit - index) {
+ case 0: return incompleteStateFor(byte1);
+ case 1: return incompleteStateFor(byte1, bytes[index]);
+ case 2: return incompleteStateFor(byte1, bytes[index], bytes[index + 1]);
+ default: throw new AssertionError();
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/WireFormat.java b/java/src/main/java/com/google/protobuf/WireFormat.java
index a30f2a3c..ba83b666 100644
--- a/java/src/main/java/com/google/protobuf/WireFormat.java
+++ b/java/src/main/java/com/google/protobuf/WireFormat.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import java.io.IOException;
+
/**
* This class is used internally by the Protocol Buffer library and generated
* message implementations. It is public only because those generated messages
@@ -146,7 +148,7 @@ public final class WireFormat {
public boolean isPackable() { return true; }
}
- // Field numbers for feilds in MessageSet wire format.
+ // Field numbers for fields in MessageSet wire format.
static final int MESSAGE_SET_ITEM = 1;
static final int MESSAGE_SET_TYPE_ID = 2;
static final int MESSAGE_SET_MESSAGE = 3;
@@ -160,4 +162,84 @@ public final class WireFormat {
makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
static final int MESSAGE_SET_MESSAGE_TAG =
makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
+
+ /**
+ * Validation level for handling incoming string field data which potentially
+ * contain non-UTF8 bytes.
+ */
+ enum Utf8Validation {
+ /** Eagerly parses to String; silently accepts invalid UTF8 bytes. */
+ LOOSE {
+ Object readString(CodedInputStream input) throws IOException {
+ return input.readString();
+ }
+ },
+ /** Eagerly parses to String; throws an IOException on invalid bytes. */
+ STRICT {
+ Object readString(CodedInputStream input) throws IOException {
+ return input.readStringRequireUtf8();
+ }
+ },
+ /** Keep data as ByteString; validation/conversion to String is lazy. */
+ LAZY {
+ Object readString(CodedInputStream input) throws IOException {
+ return input.readBytes();
+ }
+ };
+
+ /** Read a string field from the input with the proper UTF8 validation. */
+ abstract Object readString(CodedInputStream input) throws IOException;
+ }
+
+ /**
+ * Read a field of any primitive type for immutable messages from a
+ * CodedInputStream. Enums, groups, and embedded messages are not handled by
+ * this method.
+ *
+ * @param input The stream from which to read.
+ * @param type Declared type of the field.
+ * @param utf8Validation Different string UTF8 validation level for handling
+ * string fields.
+ * @return An object representing the field's value, of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ static Object readPrimitiveField(
+ CodedInputStream input,
+ FieldType type,
+ Utf8Validation utf8Validation) throws IOException {
+ switch (type) {
+ case DOUBLE : return input.readDouble ();
+ case FLOAT : return input.readFloat ();
+ case INT64 : return input.readInt64 ();
+ case UINT64 : return input.readUInt64 ();
+ case INT32 : return input.readInt32 ();
+ case FIXED64 : return input.readFixed64 ();
+ case FIXED32 : return input.readFixed32 ();
+ case BOOL : return input.readBool ();
+ case BYTES : return input.readBytes ();
+ case UINT32 : return input.readUInt32 ();
+ case SFIXED32: return input.readSFixed32();
+ case SFIXED64: return input.readSFixed64();
+ case SINT32 : return input.readSInt32 ();
+ case SINT64 : return input.readSInt64 ();
+
+ case STRING : return utf8Validation.readString(input);
+ case GROUP:
+ throw new IllegalArgumentException(
+ "readPrimitiveField() cannot handle nested groups.");
+ case MESSAGE:
+ throw new IllegalArgumentException(
+ "readPrimitiveField() cannot handle embedded messages.");
+ case ENUM:
+ // We don't handle enums because we don't know what to do if the
+ // value is not recognized.
+ throw new IllegalArgumentException(
+ "readPrimitiveField() cannot handle enums.");
+ }
+
+ throw new RuntimeException(
+ "There is no way to get here, but the compiler thinks otherwise.");
+ }
}
diff --git a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java
index d53ce8d7..d964ef59 100644
--- a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java
+++ b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,6 +30,7 @@
package com.google.protobuf;
+import com.google.protobuf.Descriptors.FieldDescriptor;
import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.ForeignMessage;
@@ -167,6 +168,13 @@ public class AbstractMessageTest extends TestCase {
wrappedBuilder.setUnknownFields(unknownFields);
return this;
}
+ @Override
+ public Message.Builder getFieldBuilder(FieldDescriptor field) {
+ return wrappedBuilder.getFieldBuilder(field);
+ }
+ }
+ public Parser<? extends Message> getParserForType() {
+ return wrappedMessage.getParserForType();
}
}
@@ -220,6 +228,34 @@ public class AbstractMessageTest extends TestCase {
TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
}
+ public void testParsingUninitialized() throws Exception {
+ TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+ builder.getOptionalMessageBuilder().setDummy2(10);
+ ByteString bytes = builder.buildPartial().toByteString();
+ Message.Builder abstractMessageBuilder =
+ new AbstractMessageWrapper.Builder(TestRequiredForeign.newBuilder());
+ // mergeFrom() should not throw initialization error.
+ abstractMessageBuilder.mergeFrom(bytes).buildPartial();
+ try {
+ abstractMessageBuilder.mergeFrom(bytes).build();
+ fail();
+ } catch (UninitializedMessageException ex) {
+ // pass
+ }
+
+ // test DynamicMessage directly.
+ Message.Builder dynamicMessageBuilder = DynamicMessage.newBuilder(
+ TestRequiredForeign.getDescriptor());
+ // mergeFrom() should not throw initialization error.
+ dynamicMessageBuilder.mergeFrom(bytes).buildPartial();
+ try {
+ dynamicMessageBuilder.mergeFrom(bytes).build();
+ fail();
+ } catch (UninitializedMessageException ex) {
+ // pass
+ }
+ }
+
public void testPackedSerialization() throws Exception {
Message abstractMessage =
new AbstractMessageWrapper(TestUtil.getPackedSet());
@@ -298,12 +334,16 @@ public class AbstractMessageTest extends TestCase {
new AbstractMessageWrapper.Builder(builder);
assertFalse(abstractBuilder.isInitialized());
+ assertEquals("a, b, c", abstractBuilder.getInitializationErrorString());
builder.setA(1);
assertFalse(abstractBuilder.isInitialized());
+ assertEquals("b, c", abstractBuilder.getInitializationErrorString());
builder.setB(1);
assertFalse(abstractBuilder.isInitialized());
+ assertEquals("c", abstractBuilder.getInitializationErrorString());
builder.setC(1);
assertTrue(abstractBuilder.isInitialized());
+ assertEquals("", abstractBuilder.getInitializationErrorString());
}
public void testForeignIsInitialized() throws Exception {
@@ -312,18 +352,27 @@ public class AbstractMessageTest extends TestCase {
new AbstractMessageWrapper.Builder(builder);
assertTrue(abstractBuilder.isInitialized());
+ assertEquals("", abstractBuilder.getInitializationErrorString());
builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
assertFalse(abstractBuilder.isInitialized());
+ assertEquals(
+ "optional_message.a, optional_message.b, optional_message.c",
+ abstractBuilder.getInitializationErrorString());
builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
assertTrue(abstractBuilder.isInitialized());
+ assertEquals("", abstractBuilder.getInitializationErrorString());
builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
assertFalse(abstractBuilder.isInitialized());
+ assertEquals(
+ "repeated_message[0].a, repeated_message[0].b, repeated_message[0].c",
+ abstractBuilder.getInitializationErrorString());
builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
assertTrue(abstractBuilder.isInitialized());
+ assertEquals("", abstractBuilder.getInitializationErrorString());
}
// -----------------------------------------------------------------
@@ -421,7 +470,7 @@ public class AbstractMessageTest extends TestCase {
/**
- * Asserts that the given proto has symetric equals and hashCode methods.
+ * Asserts that the given proto has symmetric equals and hashCode methods.
*/
private void checkEqualsIsConsistent(Message message) {
// Object should be equal to itself.
@@ -457,4 +506,22 @@ public class AbstractMessageTest extends TestCase {
String.format("%s should have a different hash code from %s", m1, m2),
m1.hashCode() == m2.hashCode());
}
+
+ public void testCheckByteStringIsUtf8OnUtf8() {
+ ByteString byteString = ByteString.copyFromUtf8("some text");
+ AbstractMessageLite.checkByteStringIsUtf8(byteString);
+ // No exception thrown.
+ }
+
+ public void testCheckByteStringIsUtf8OnNonUtf8() {
+ ByteString byteString =
+ ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
+ try {
+ AbstractMessageLite.checkByteStringIsUtf8(byteString);
+ fail("Expected AbstractMessageLite.checkByteStringIsUtf8 to throw IllegalArgumentException");
+ } catch (IllegalArgumentException exception) {
+ assertEquals("Byte string is not UTF-8.", exception.getMessage());
+ }
+ }
+
}
diff --git a/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java b/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java
new file mode 100644
index 00000000..6c9596ca
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java
@@ -0,0 +1,87 @@
+// 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * This class tests {@link BoundedByteString}, which extends {@link LiteralByteString},
+ * by inheriting the tests from {@link LiteralByteStringTest}. The only method which
+ * is strange enough that it needs to be overridden here is {@link #testToString()}.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class BoundedByteStringTest extends LiteralByteStringTest {
+
+ @Override
+ protected void setUp() throws Exception {
+ classUnderTest = "BoundedByteString";
+ byte[] sourceBytes = ByteStringTest.getTestBytes(2341, 11337766L);
+ int from = 100;
+ int to = sourceBytes.length - 100;
+ stringUnderTest = ByteString.copyFrom(sourceBytes).substring(from, to);
+ referenceBytes = new byte[to - from];
+ System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
+ expectedHashCode = 727575887;
+ }
+
+ @Override
+ public void testToString() throws UnsupportedEncodingException {
+ String testString = "I love unicode \u1234\u5678 characters";
+ LiteralByteString unicode = new LiteralByteString(testString.getBytes(UTF_8));
+ ByteString chopped = unicode.substring(2, unicode.size() - 6);
+ assertEquals(classUnderTest + ".substring() must have the expected type",
+ classUnderTest, getActualClassName(chopped));
+
+ String roundTripString = chopped.toString(UTF_8);
+ assertEquals(classUnderTest + " unicode bytes must match",
+ testString.substring(2, testString.length() - 6), roundTripString);
+ }
+
+ public void testJavaSerialization() throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(out);
+ oos.writeObject(stringUnderTest);
+ oos.close();
+ byte[] pickled = out.toByteArray();
+ InputStream in = new ByteArrayInputStream(pickled);
+ ObjectInputStream ois = new ObjectInputStream(in);
+ Object o = ois.readObject();
+ assertTrue("Didn't get a ByteString back", o instanceof ByteString);
+ assertEquals("Should get an equal ByteString back", stringUnderTest, o);
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/ByteStringTest.java b/java/src/test/java/com/google/protobuf/ByteStringTest.java
new file mode 100644
index 00000000..15de17cd
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/ByteStringTest.java
@@ -0,0 +1,759 @@
+// 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.ByteString.Output;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Random;
+
+/**
+ * Test methods with implementations in {@link ByteString}, plus do some top-level "integration"
+ * tests.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class ByteStringTest extends TestCase {
+
+ private static final String UTF_16 = "UTF-16";
+
+ static byte[] getTestBytes(int size, long seed) {
+ Random random = new Random(seed);
+ byte[] result = new byte[size];
+ random.nextBytes(result);
+ return result;
+ }
+
+ private byte[] getTestBytes(int size) {
+ return getTestBytes(size, 445566L);
+ }
+
+ private byte[] getTestBytes() {
+ return getTestBytes(1000);
+ }
+
+ // Compare the entire left array with a subset of the right array.
+ private boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int length) {
+ boolean stillEqual = (left.length == length);
+ for (int i = 0; (stillEqual && i < length); ++i) {
+ stillEqual = (left[i] == right[rightOffset + i]);
+ }
+ return stillEqual;
+ }
+
+ // Returns true only if the given two arrays have identical contents.
+ private boolean isArray(byte[] left, byte[] right) {
+ return left.length == right.length && isArrayRange(left, right, 0, left.length);
+ }
+
+ public void testSubstring_BeginIndex() {
+ byte[] bytes = getTestBytes();
+ ByteString substring = ByteString.copyFrom(bytes).substring(500);
+ assertTrue("substring must contain the tail of the string",
+ isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500));
+ }
+
+ public void testCopyFrom_BytesOffsetSize() {
+ byte[] bytes = getTestBytes();
+ ByteString byteString = ByteString.copyFrom(bytes, 500, 200);
+ assertTrue("copyFrom sub-range must contain the expected bytes",
+ isArrayRange(byteString.toByteArray(), bytes, 500, 200));
+ }
+
+ public void testCopyFrom_Bytes() {
+ byte[] bytes = getTestBytes();
+ ByteString byteString = ByteString.copyFrom(bytes);
+ assertTrue("copyFrom must contain the expected bytes",
+ isArray(byteString.toByteArray(), bytes));
+ }
+
+ public void testCopyFrom_ByteBufferSize() {
+ byte[] bytes = getTestBytes();
+ ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
+ byteBuffer.put(bytes);
+ byteBuffer.position(500);
+ ByteString byteString = ByteString.copyFrom(byteBuffer, 200);
+ assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
+ isArrayRange(byteString.toByteArray(), bytes, 500, 200));
+ }
+
+ public void testCopyFrom_ByteBuffer() {
+ byte[] bytes = getTestBytes();
+ ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
+ byteBuffer.put(bytes);
+ byteBuffer.position(500);
+ ByteString byteString = ByteString.copyFrom(byteBuffer);
+ assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
+ isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500));
+ }
+
+ public void testCopyFrom_StringEncoding() throws UnsupportedEncodingException {
+ String testString = "I love unicode \u1234\u5678 characters";
+ ByteString byteString = ByteString.copyFrom(testString, UTF_16);
+ byte[] testBytes = testString.getBytes(UTF_16);
+ assertTrue("copyFrom string must respect the charset",
+ isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+ }
+
+ public void testCopyFrom_Utf8() throws UnsupportedEncodingException {
+ String testString = "I love unicode \u1234\u5678 characters";
+ ByteString byteString = ByteString.copyFromUtf8(testString);
+ byte[] testBytes = testString.getBytes("UTF-8");
+ assertTrue("copyFromUtf8 string must respect the charset",
+ isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+ }
+
+ public void testCopyFrom_Iterable() {
+ byte[] testBytes = getTestBytes(77777, 113344L);
+ final List<ByteString> pieces = makeConcretePieces(testBytes);
+ // Call copyFrom() on a Collection
+ ByteString byteString = ByteString.copyFrom(pieces);
+ assertTrue("copyFrom a List must contain the expected bytes",
+ isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+ // Call copyFrom on an iteration that's not a collection
+ ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() {
+ public Iterator<ByteString> iterator() {
+ return pieces.iterator();
+ }
+ });
+ assertEquals("copyFrom from an Iteration must contain the expected bytes",
+ byteString, byteStringAlt);
+ }
+
+ public void testCopyTo_TargetOffset() {
+ byte[] bytes = getTestBytes();
+ ByteString byteString = ByteString.copyFrom(bytes);
+ byte[] target = new byte[bytes.length + 1000];
+ byteString.copyTo(target, 400);
+ assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
+ isArrayRange(bytes, target, 400, bytes.length));
+ }
+
+ public void testReadFrom_emptyStream() throws IOException {
+ ByteString byteString =
+ ByteString.readFrom(new ByteArrayInputStream(new byte[0]));
+ assertSame("reading an empty stream must result in the EMPTY constant "
+ + "byte string", ByteString.EMPTY, byteString);
+ }
+
+ public void testReadFrom_smallStream() throws IOException {
+ assertReadFrom(getTestBytes(10));
+ }
+
+ public void testReadFrom_mutating() throws IOException {
+ byte[] capturedArray = null;
+ EvilInputStream eis = new EvilInputStream();
+ ByteString byteString = ByteString.readFrom(eis);
+
+ capturedArray = eis.capturedArray;
+ byte[] originalValue = byteString.toByteArray();
+ for (int x = 0; x < capturedArray.length; ++x) {
+ capturedArray[x] = (byte) 0;
+ }
+
+ byte[] newValue = byteString.toByteArray();
+ assertTrue("copyFrom byteBuffer must not grant access to underlying array",
+ Arrays.equals(originalValue, newValue));
+ }
+
+ // Tests sizes that are near the rope copy-out threshold.
+ public void testReadFrom_mediumStream() throws IOException {
+ assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE - 1));
+ assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE));
+ assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE + 1));
+ assertReadFrom(getTestBytes(200));
+ }
+
+ // Tests sizes that are over multi-segment rope threshold.
+ public void testReadFrom_largeStream() throws IOException {
+ assertReadFrom(getTestBytes(0x100));
+ assertReadFrom(getTestBytes(0x101));
+ assertReadFrom(getTestBytes(0x110));
+ assertReadFrom(getTestBytes(0x1000));
+ assertReadFrom(getTestBytes(0x1001));
+ assertReadFrom(getTestBytes(0x1010));
+ assertReadFrom(getTestBytes(0x10000));
+ assertReadFrom(getTestBytes(0x10001));
+ assertReadFrom(getTestBytes(0x10010));
+ }
+
+ // Tests sizes that are near the read buffer size.
+ public void testReadFrom_byteBoundaries() throws IOException {
+ final int min = ByteString.MIN_READ_FROM_CHUNK_SIZE;
+ final int max = ByteString.MAX_READ_FROM_CHUNK_SIZE;
+
+ assertReadFrom(getTestBytes(min - 1));
+ assertReadFrom(getTestBytes(min));
+ assertReadFrom(getTestBytes(min + 1));
+
+ assertReadFrom(getTestBytes(min * 2 - 1));
+ assertReadFrom(getTestBytes(min * 2));
+ assertReadFrom(getTestBytes(min * 2 + 1));
+
+ assertReadFrom(getTestBytes(min * 4 - 1));
+ assertReadFrom(getTestBytes(min * 4));
+ assertReadFrom(getTestBytes(min * 4 + 1));
+
+ assertReadFrom(getTestBytes(min * 8 - 1));
+ assertReadFrom(getTestBytes(min * 8));
+ assertReadFrom(getTestBytes(min * 8 + 1));
+
+ assertReadFrom(getTestBytes(max - 1));
+ assertReadFrom(getTestBytes(max));
+ assertReadFrom(getTestBytes(max + 1));
+
+ assertReadFrom(getTestBytes(max * 2 - 1));
+ assertReadFrom(getTestBytes(max * 2));
+ assertReadFrom(getTestBytes(max * 2 + 1));
+ }
+
+ // Tests that IOExceptions propagate through ByteString.readFrom().
+ public void testReadFrom_IOExceptions() {
+ try {
+ ByteString.readFrom(new FailStream());
+ fail("readFrom must throw the underlying IOException");
+
+ } catch (IOException e) {
+ assertEquals("readFrom must throw the expected exception",
+ "synthetic failure", e.getMessage());
+ }
+ }
+
+ // Tests that ByteString.readFrom works with streams that don't
+ // always fill their buffers.
+ public void testReadFrom_reluctantStream() throws IOException {
+ final byte[] data = getTestBytes(0x1000);
+
+ ByteString byteString = ByteString.readFrom(new ReluctantStream(data));
+ assertTrue("readFrom byte stream must contain the expected bytes",
+ isArray(byteString.toByteArray(), data));
+
+ // Same test as above, but with some specific chunk sizes.
+ assertReadFromReluctantStream(data, 100);
+ assertReadFromReluctantStream(data, 248);
+ assertReadFromReluctantStream(data, 249);
+ assertReadFromReluctantStream(data, 250);
+ assertReadFromReluctantStream(data, 251);
+ assertReadFromReluctantStream(data, 0x1000);
+ assertReadFromReluctantStream(data, 0x1001);
+ }
+
+ // Fails unless ByteString.readFrom reads the bytes correctly from a
+ // reluctant stream with the given chunkSize parameter.
+ private void assertReadFromReluctantStream(byte[] bytes, int chunkSize)
+ throws IOException {
+ ByteString b = ByteString.readFrom(new ReluctantStream(bytes), chunkSize);
+ assertTrue("readFrom byte stream must contain the expected bytes",
+ isArray(b.toByteArray(), bytes));
+ }
+
+ // Tests that ByteString.readFrom works with streams that implement
+ // available().
+ public void testReadFrom_available() throws IOException {
+ final byte[] data = getTestBytes(0x1001);
+
+ ByteString byteString = ByteString.readFrom(new AvailableStream(data));
+ assertTrue("readFrom byte stream must contain the expected bytes",
+ isArray(byteString.toByteArray(), data));
+ }
+
+ // Fails unless ByteString.readFrom reads the bytes correctly.
+ private void assertReadFrom(byte[] bytes) throws IOException {
+ ByteString byteString =
+ ByteString.readFrom(new ByteArrayInputStream(bytes));
+ assertTrue("readFrom byte stream must contain the expected bytes",
+ isArray(byteString.toByteArray(), bytes));
+ }
+
+ // A stream that fails when read.
+ private static final class FailStream extends InputStream {
+ @Override public int read() throws IOException {
+ throw new IOException("synthetic failure");
+ }
+ }
+
+ // A stream that simulates blocking by only producing 250 characters
+ // per call to read(byte[]).
+ private static class ReluctantStream extends InputStream {
+ protected final byte[] data;
+ protected int pos = 0;
+
+ public ReluctantStream(byte[] data) {
+ this.data = data;
+ }
+
+ @Override public int read() {
+ if (pos == data.length) {
+ return -1;
+ } else {
+ return data[pos++];
+ }
+ }
+
+ @Override public int read(byte[] buf) {
+ return read(buf, 0, buf.length);
+ }
+
+ @Override public int read(byte[] buf, int offset, int size) {
+ if (pos == data.length) {
+ return -1;
+ }
+ int count = Math.min(Math.min(size, data.length - pos), 250);
+ System.arraycopy(data, pos, buf, offset, count);
+ pos += count;
+ return count;
+ }
+ }
+
+ // Same as above, but also implements available().
+ private static final class AvailableStream extends ReluctantStream {
+ public AvailableStream(byte[] data) {
+ super(data);
+ }
+
+ @Override public int available() {
+ return Math.min(250, data.length - pos);
+ }
+ }
+
+ // A stream which exposes the byte array passed into read(byte[], int, int).
+ private static class EvilInputStream extends InputStream {
+ public byte[] capturedArray = null;
+
+ @Override
+ public int read(byte[] buf, int off, int len) {
+ if (capturedArray != null) {
+ return -1;
+ } else {
+ capturedArray = buf;
+ for (int x = 0; x < len; ++x) {
+ buf[x] = (byte) x;
+ }
+ return len;
+ }
+ }
+
+ @Override
+ public int read() {
+ // Purposefully do nothing.
+ return -1;
+ }
+ }
+
+ // A stream which exposes the byte array passed into write(byte[], int, int).
+ private static class EvilOutputStream extends OutputStream {
+ public byte[] capturedArray = null;
+
+ @Override
+ public void write(byte[] buf, int off, int len) {
+ if (capturedArray == null) {
+ capturedArray = buf;
+ }
+ }
+
+ @Override
+ public void write(int ignored) {
+ // Purposefully do nothing.
+ }
+ }
+
+ public void testToStringUtf8() throws UnsupportedEncodingException {
+ String testString = "I love unicode \u1234\u5678 characters";
+ byte[] testBytes = testString.getBytes("UTF-8");
+ ByteString byteString = ByteString.copyFrom(testBytes);
+ assertEquals("copyToStringUtf8 must respect the charset",
+ testString, byteString.toStringUtf8());
+ }
+
+ public void testNewOutput_InitialCapacity() throws IOException {
+ byte[] bytes = getTestBytes();
+ ByteString.Output output = ByteString.newOutput(bytes.length + 100);
+ output.write(bytes);
+ ByteString byteString = output.toByteString();
+ assertTrue(
+ "String built from newOutput(int) must contain the expected bytes",
+ isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+ }
+
+ // Test newOutput() using a variety of buffer sizes and a variety of (fixed)
+ // write sizes
+ public void testNewOutput_ArrayWrite() throws IOException {
+ byte[] bytes = getTestBytes();
+ int length = bytes.length;
+ int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1,
+ 2 * length, 3 * length};
+ int[] writeSizes = {1, 4, 5, 7, 23, bytes.length};
+
+ for (int bufferSize : bufferSizes) {
+ for (int writeSize : writeSizes) {
+ // Test writing the entire output writeSize bytes at a time.
+ ByteString.Output output = ByteString.newOutput(bufferSize);
+ for (int i = 0; i < length; i += writeSize) {
+ output.write(bytes, i, Math.min(writeSize, length - i));
+ }
+ ByteString byteString = output.toByteString();
+ assertTrue("String built from newOutput() must contain the expected bytes",
+ isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+ }
+ }
+ }
+
+ // Test newOutput() using a variety of buffer sizes, but writing all the
+ // characters using write(byte);
+ public void testNewOutput_WriteChar() throws IOException {
+ byte[] bytes = getTestBytes();
+ int length = bytes.length;
+ int[] bufferSizes = {0, 1, 128, 256, length / 2,
+ length - 1, length, length + 1,
+ 2 * length, 3 * length};
+ for (int bufferSize : bufferSizes) {
+ ByteString.Output output = ByteString.newOutput(bufferSize);
+ for (byte byteValue : bytes) {
+ output.write(byteValue);
+ }
+ ByteString byteString = output.toByteString();
+ assertTrue("String built from newOutput() must contain the expected bytes",
+ isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+ }
+ }
+
+ // Test newOutput() in which we write the bytes using a variety of methods
+ // and sizes, and in which we repeatedly call toByteString() in the middle.
+ public void testNewOutput_Mixed() throws IOException {
+ Random rng = new Random(1);
+ byte[] bytes = getTestBytes();
+ int length = bytes.length;
+ int[] bufferSizes = {0, 1, 128, 256, length / 2,
+ length - 1, length, length + 1,
+ 2 * length, 3 * length};
+
+ for (int bufferSize : bufferSizes) {
+ // Test writing the entire output using a mixture of write sizes and
+ // methods;
+ ByteString.Output output = ByteString.newOutput(bufferSize);
+ int position = 0;
+ while (position < bytes.length) {
+ if (rng.nextBoolean()) {
+ int count = 1 + rng.nextInt(bytes.length - position);
+ output.write(bytes, position, count);
+ position += count;
+ } else {
+ output.write(bytes[position]);
+ position++;
+ }
+ assertEquals("size() returns the right value", position, output.size());
+ assertTrue("newOutput() substring must have correct bytes",
+ isArrayRange(output.toByteString().toByteArray(),
+ bytes, 0, position));
+ }
+ ByteString byteString = output.toByteString();
+ assertTrue("String built from newOutput() must contain the expected bytes",
+ isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+ }
+ }
+
+ public void testNewOutputEmpty() throws IOException {
+ // Make sure newOutput() correctly builds empty byte strings
+ ByteString byteString = ByteString.newOutput().toByteString();
+ assertEquals(ByteString.EMPTY, byteString);
+ }
+
+ public void testNewOutput_Mutating() throws IOException {
+ Output os = ByteString.newOutput(5);
+ os.write(new byte[] {1, 2, 3, 4, 5});
+ EvilOutputStream eos = new EvilOutputStream();
+ os.writeTo(eos);
+ byte[] capturedArray = eos.capturedArray;
+ ByteString byteString = os.toByteString();
+ byte[] oldValue = byteString.toByteArray();
+ Arrays.fill(capturedArray, (byte) 0);
+ byte[] newValue = byteString.toByteArray();
+ assertTrue("Output must not provide access to the underlying byte array",
+ Arrays.equals(oldValue, newValue));
+ }
+
+ public void testNewCodedBuilder() throws IOException {
+ byte[] bytes = getTestBytes();
+ ByteString.CodedBuilder builder = ByteString.newCodedBuilder(bytes.length);
+ builder.getCodedOutput().writeRawBytes(bytes);
+ ByteString byteString = builder.build();
+ assertTrue("String built from newCodedBuilder() must contain the expected bytes",
+ isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+ }
+
+ public void testSubstringParity() {
+ byte[] bigBytes = getTestBytes(2048 * 1024, 113344L);
+ int start = 512 * 1024 - 3333;
+ int end = 512 * 1024 + 7777;
+ ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start, end);
+ boolean ok = true;
+ for (int i = start; ok && i < end; ++i) {
+ ok = (bigBytes[i] == concreteSubstring.byteAt(i - start));
+ }
+ assertTrue("Concrete substring didn't capture the right bytes", ok);
+
+ ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start);
+ assertTrue("Substring must be equal to literal string",
+ concreteSubstring.equals(literalString));
+ assertEquals("Substring must have same hashcode as literal string",
+ literalString.hashCode(), concreteSubstring.hashCode());
+ }
+
+ public void testCompositeSubstring() {
+ byte[] referenceBytes = getTestBytes(77748, 113344L);
+
+ List<ByteString> pieces = makeConcretePieces(referenceBytes);
+ ByteString listString = ByteString.copyFrom(pieces);
+
+ int from = 1000;
+ int to = 40000;
+ ByteString compositeSubstring = listString.substring(from, to);
+ byte[] substringBytes = compositeSubstring.toByteArray();
+ boolean stillEqual = true;
+ for (int i = 0; stillEqual && i < to - from; ++i) {
+ stillEqual = referenceBytes[from + i] == substringBytes[i];
+ }
+ assertTrue("Substring must return correct bytes", stillEqual);
+
+ stillEqual = true;
+ for (int i = 0; stillEqual && i < to - from; ++i) {
+ stillEqual = referenceBytes[from + i] == compositeSubstring.byteAt(i);
+ }
+ assertTrue("Substring must support byteAt() correctly", stillEqual);
+
+ ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to - from);
+ assertTrue("Composite substring must equal a literal substring over the same bytes",
+ compositeSubstring.equals(literalSubstring));
+ assertTrue("Literal substring must equal a composite substring over the same bytes",
+ literalSubstring.equals(compositeSubstring));
+
+ assertEquals("We must get the same hashcodes for composite and literal substrings",
+ literalSubstring.hashCode(), compositeSubstring.hashCode());
+
+ assertFalse("We can't be equal to a proper substring",
+ compositeSubstring.equals(literalSubstring.substring(0, literalSubstring.size() - 1)));
+ }
+
+ public void testCopyFromList() {
+ byte[] referenceBytes = getTestBytes(77748, 113344L);
+ ByteString literalString = ByteString.copyFrom(referenceBytes);
+
+ List<ByteString> pieces = makeConcretePieces(referenceBytes);
+ ByteString listString = ByteString.copyFrom(pieces);
+
+ assertTrue("Composite string must be equal to literal string",
+ listString.equals(literalString));
+ assertEquals("Composite string must have same hashcode as literal string",
+ literalString.hashCode(), listString.hashCode());
+ }
+
+ public void testConcat() {
+ byte[] referenceBytes = getTestBytes(77748, 113344L);
+ ByteString literalString = ByteString.copyFrom(referenceBytes);
+
+ List<ByteString> pieces = makeConcretePieces(referenceBytes);
+
+ Iterator<ByteString> iter = pieces.iterator();
+ ByteString concatenatedString = iter.next();
+ while (iter.hasNext()) {
+ concatenatedString = concatenatedString.concat(iter.next());
+ }
+
+ assertTrue("Concatenated string must be equal to literal string",
+ concatenatedString.equals(literalString));
+ assertEquals("Concatenated string must have same hashcode as literal string",
+ literalString.hashCode(), concatenatedString.hashCode());
+ }
+
+ /**
+ * Test the Rope implementation can deal with Empty nodes, even though we
+ * guard against them. See also {@link LiteralByteStringTest#testConcat_empty()}.
+ */
+ public void testConcat_empty() {
+ byte[] referenceBytes = getTestBytes(7748, 113344L);
+ ByteString literalString = ByteString.copyFrom(referenceBytes);
+
+ ByteString duo = RopeByteString.newInstanceForTest(literalString, literalString);
+ ByteString temp = RopeByteString.newInstanceForTest(
+ RopeByteString.newInstanceForTest(literalString, ByteString.EMPTY),
+ RopeByteString.newInstanceForTest(ByteString.EMPTY, literalString));
+ ByteString quintet = RopeByteString.newInstanceForTest(temp, ByteString.EMPTY);
+
+ assertTrue("String with concatenated nulls must equal simple concatenate",
+ duo.equals(quintet));
+ assertEquals("String with concatenated nulls have same hashcode as simple concatenate",
+ duo.hashCode(), quintet.hashCode());
+
+ ByteString.ByteIterator duoIter = duo.iterator();
+ ByteString.ByteIterator quintetIter = quintet.iterator();
+ boolean stillEqual = true;
+ while (stillEqual && quintetIter.hasNext()) {
+ stillEqual = (duoIter.nextByte() == quintetIter.nextByte());
+ }
+ assertTrue("We must get the same characters by iterating", stillEqual);
+ assertFalse("Iterator must be exhausted", duoIter.hasNext());
+ try {
+ duoIter.nextByte();
+ fail("Should have thrown an exception.");
+ } catch (NoSuchElementException e) {
+ // This is success
+ }
+ try {
+ quintetIter.nextByte();
+ fail("Should have thrown an exception.");
+ } catch (NoSuchElementException e) {
+ // This is success
+ }
+
+ // Test that even if we force empty strings in as rope leaves in this
+ // configuration, we always get a (possibly Bounded) LiteralByteString
+ // for a length 1 substring.
+ //
+ // It is possible, using the testing factory method to create deeply nested
+ // trees of empty leaves, to make a string that will fail this test.
+ for (int i = 1; i < duo.size(); ++i) {
+ assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
+ duo.substring(i - 1, i) instanceof LiteralByteString);
+ }
+ for (int i = 1; i < quintet.size(); ++i) {
+ assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
+ quintet.substring(i - 1, i) instanceof LiteralByteString);
+ }
+ }
+
+ public void testStartsWith() {
+ byte[] bytes = getTestBytes(1000, 1234L);
+ ByteString string = ByteString.copyFrom(bytes);
+ ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
+ ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
+ assertTrue(string.startsWith(ByteString.EMPTY));
+ assertTrue(string.startsWith(string));
+ assertTrue(string.startsWith(prefix));
+ assertFalse(string.startsWith(suffix));
+ assertFalse(prefix.startsWith(suffix));
+ assertFalse(suffix.startsWith(prefix));
+ assertFalse(ByteString.EMPTY.startsWith(prefix));
+ assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY));
+ }
+
+ public void testEndsWith() {
+ byte[] bytes = getTestBytes(1000, 1234L);
+ ByteString string = ByteString.copyFrom(bytes);
+ ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
+ ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
+ assertTrue(string.endsWith(ByteString.EMPTY));
+ assertTrue(string.endsWith(string));
+ assertTrue(string.endsWith(suffix));
+ assertFalse(string.endsWith(prefix));
+ assertFalse(suffix.endsWith(prefix));
+ assertFalse(prefix.endsWith(suffix));
+ assertFalse(ByteString.EMPTY.endsWith(suffix));
+ assertTrue(ByteString.EMPTY.endsWith(ByteString.EMPTY));
+ }
+
+ static List<ByteString> makeConcretePieces(byte[] referenceBytes) {
+ List<ByteString> pieces = new ArrayList<ByteString>();
+ // Starting length should be small enough that we'll do some concatenating by
+ // copying if we just concatenate all these pieces together.
+ for (int start = 0, length = 16; start < referenceBytes.length; start += length) {
+ length = (length << 1) - 1;
+ if (start + length > referenceBytes.length) {
+ length = referenceBytes.length - start;
+ }
+ pieces.add(ByteString.copyFrom(referenceBytes, start, length));
+ }
+ return pieces;
+ }
+
+ private byte[] substringUsingWriteTo(
+ ByteString data, int offset, int length) throws IOException {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ data.writeTo(output, offset, length);
+ return output.toByteArray();
+ }
+
+ public void testWriteToOutputStream() throws Exception {
+ // Choose a size large enough so when two ByteStrings are concatenated they
+ // won't be merged into one byte array due to some optimizations.
+ final int dataSize = ByteString.CONCATENATE_BY_COPY_SIZE + 1;
+ byte[] data1 = new byte[dataSize];
+ for (int i = 0; i < data1.length; i++) {
+ data1[i] = (byte) 1;
+ }
+ data1[1] = (byte) 11;
+ // Test LiteralByteString.writeTo(OutputStream,int,int)
+ LiteralByteString left = new LiteralByteString(data1);
+ byte[] result = substringUsingWriteTo(left, 1, 1);
+ assertEquals(1, result.length);
+ assertEquals((byte) 11, result[0]);
+
+ byte[] data2 = new byte[dataSize];
+ for (int i = 0; i < data1.length; i++) {
+ data2[i] = (byte) 2;
+ }
+ LiteralByteString right = new LiteralByteString(data2);
+ // Concatenate two ByteStrings to create a RopeByteString.
+ ByteString root = left.concat(right);
+ // Make sure we are actually testing a RopeByteString with a simple tree
+ // structure.
+ assertEquals(1, root.getTreeDepth());
+ // Write parts of the left node.
+ result = substringUsingWriteTo(root, 0, dataSize);
+ assertEquals(dataSize, result.length);
+ assertEquals((byte) 1, result[0]);
+ assertEquals((byte) 1, result[dataSize - 1]);
+ // Write parts of the right node.
+ result = substringUsingWriteTo(root, dataSize, dataSize);
+ assertEquals(dataSize, result.length);
+ assertEquals((byte) 2, result[0]);
+ assertEquals((byte) 2, result[dataSize - 1]);
+ // Write a segment of bytes that runs across both nodes.
+ result = substringUsingWriteTo(root, dataSize / 2, dataSize);
+ assertEquals(dataSize, result.length);
+ assertEquals((byte) 1, result[0]);
+ assertEquals((byte) 1, result[dataSize - dataSize / 2 - 1]);
+ assertEquals((byte) 2, result[dataSize - dataSize / 2]);
+ assertEquals((byte) 2, result[dataSize - 1]);
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/src/test/java/com/google/protobuf/CheckUtf8Test.java
new file mode 100644
index 00000000..6470e9ca
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/CheckUtf8Test.java
@@ -0,0 +1,141 @@
+// 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 proto2_test_check_utf8.TestCheckUtf8.BytesWrapper;
+import proto2_test_check_utf8.TestCheckUtf8.StringWrapper;
+import proto2_test_check_utf8_size.TestCheckUtf8Size.BytesWrapperSize;
+import proto2_test_check_utf8_size.TestCheckUtf8Size.StringWrapperSize;
+import junit.framework.TestCase;
+
+/**
+ * Test that protos generated with file option java_string_check_utf8 do in
+ * fact perform appropriate UTF-8 checks.
+ *
+ * @author jbaum@google.com (Jacob Butcher)
+ */
+public class CheckUtf8Test extends TestCase {
+
+ private static final String UTF8_BYTE_STRING_TEXT = "some text";
+ private static final ByteString UTF8_BYTE_STRING =
+ ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT);
+ private static final ByteString NON_UTF8_BYTE_STRING =
+ ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
+
+ public void testBuildRequiredStringWithGoodUtf8() throws Exception {
+ assertEquals(UTF8_BYTE_STRING_TEXT,
+ StringWrapper.newBuilder().setReqBytes(UTF8_BYTE_STRING).getReq());
+ }
+
+ public void testParseRequiredStringWithGoodUtf8() throws Exception {
+ ByteString serialized =
+ BytesWrapper.newBuilder().setReq(UTF8_BYTE_STRING).build().toByteString();
+ assertEquals(UTF8_BYTE_STRING_TEXT,
+ StringWrapper.PARSER.parseFrom(serialized).getReq());
+ }
+
+ public void testBuildRequiredStringWithBadUtf8() throws Exception {
+ try {
+ StringWrapper.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
+ fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+ } catch (IllegalArgumentException exception) {
+ assertEquals("Byte string is not UTF-8.", exception.getMessage());
+ }
+ }
+
+ public void testBuildOptionalStringWithBadUtf8() throws Exception {
+ try {
+ StringWrapper.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
+ fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+ } catch (IllegalArgumentException exception) {
+ assertEquals("Byte string is not UTF-8.", exception.getMessage());
+ }
+ }
+
+ public void testBuildRepeatedStringWithBadUtf8() throws Exception {
+ try {
+ StringWrapper.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
+ fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+ } catch (IllegalArgumentException exception) {
+ assertEquals("Byte string is not UTF-8.", exception.getMessage());
+ }
+ }
+
+ public void testParseRequiredStringWithBadUtf8() throws Exception {
+ ByteString serialized =
+ BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
+ try {
+ StringWrapper.PARSER.parseFrom(serialized);
+ fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+ } catch (InvalidProtocolBufferException exception) {
+ assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+ }
+ }
+
+ public void testBuildRequiredStringWithBadUtf8Size() throws Exception {
+ try {
+ StringWrapperSize.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
+ fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+ } catch (IllegalArgumentException exception) {
+ assertEquals("Byte string is not UTF-8.", exception.getMessage());
+ }
+ }
+
+ public void testBuildOptionalStringWithBadUtf8Size() throws Exception {
+ try {
+ StringWrapperSize.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
+ fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+ } catch (IllegalArgumentException exception) {
+ assertEquals("Byte string is not UTF-8.", exception.getMessage());
+ }
+ }
+
+ public void testBuildRepeatedStringWithBadUtf8Size() throws Exception {
+ try {
+ StringWrapperSize.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
+ fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+ } catch (IllegalArgumentException exception) {
+ assertEquals("Byte string is not UTF-8.", exception.getMessage());
+ }
+ }
+
+ public void testParseRequiredStringWithBadUtf8Size() throws Exception {
+ ByteString serialized =
+ BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
+ try {
+ StringWrapperSize.PARSER.parseFrom(serialized);
+ fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+ } catch (InvalidProtocolBufferException exception) {
+ assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+ }
+ }
+
+}
diff --git a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
index 83f7f8da..18d8142c 100644
--- a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,15 +30,20 @@
package com.google.protobuf;
+import protobuf_unittest.UnittestProto.BoolMessage;
+import protobuf_unittest.UnittestProto.Int32Message;
+import protobuf_unittest.UnittestProto.Int64Message;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestRecursiveMessage;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
/**
* Unit test for {@link CodedInputStream}.
@@ -85,28 +90,54 @@ public class CodedInputStreamTest extends TestCase {
}
}
+ private void assertDataConsumed(byte[] data, CodedInputStream input)
+ throws IOException {
+ assertEquals(data.length, input.getTotalBytesRead());
+ assertTrue(input.isAtEnd());
+ }
+
/**
* Parses the given bytes using readRawVarint32() and readRawVarint64() and
* checks that the result matches the given value.
*/
private void assertReadVarint(byte[] data, long value) throws Exception {
CodedInputStream input = CodedInputStream.newInstance(data);
- assertEquals((int)value, input.readRawVarint32());
+ assertEquals((int) value, input.readRawVarint32());
+ assertDataConsumed(data, input);
input = CodedInputStream.newInstance(data);
assertEquals(value, input.readRawVarint64());
- assertTrue(input.isAtEnd());
+ assertDataConsumed(data, input);
+
+ input = CodedInputStream.newInstance(data);
+ assertEquals(value, input.readRawVarint64SlowPath());
+ assertDataConsumed(data, input);
+
+ input = CodedInputStream.newInstance(data);
+ assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
+ assertDataConsumed(data, input);
// Try different block sizes.
for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
input = CodedInputStream.newInstance(
new SmallBlockInputStream(data, blockSize));
- assertEquals((int)value, input.readRawVarint32());
+ assertEquals((int) value, input.readRawVarint32());
+ assertDataConsumed(data, input);
input = CodedInputStream.newInstance(
new SmallBlockInputStream(data, blockSize));
assertEquals(value, input.readRawVarint64());
- assertTrue(input.isAtEnd());
+ assertDataConsumed(data, input);
+
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertEquals(value, input.readRawVarint64SlowPath());
+ assertDataConsumed(data, input);
+
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
+ assertDataConsumed(data, input);
}
// Try reading direct from an InputStream. We want to verify that it
@@ -115,7 +146,7 @@ public class CodedInputStreamTest extends TestCase {
byte[] longerData = new byte[data.length + 1];
System.arraycopy(data, 0, longerData, 0, data.length);
InputStream rawInput = new ByteArrayInputStream(longerData);
- assertEquals((int)value, CodedInputStream.readRawVarint32(rawInput));
+ assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput));
assertEquals(1, rawInput.available());
}
@@ -143,6 +174,14 @@ public class CodedInputStreamTest extends TestCase {
assertEquals(expected.getMessage(), e.getMessage());
}
+ input = CodedInputStream.newInstance(data);
+ try {
+ input.readRawVarint64SlowPath();
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals(expected.getMessage(), e.getMessage());
+ }
+
// Make sure we get the same error when reading direct from an InputStream.
try {
CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
@@ -311,6 +350,7 @@ public class CodedInputStreamTest extends TestCase {
}
}
+
/**
* Test that a bug in skipRawBytes() has been fixed: if the skip skips
* exactly up to a limit, this should not break things.
@@ -350,7 +390,7 @@ public class CodedInputStreamTest extends TestCase {
// Allocate and initialize a 1MB blob.
byte[] blob = new byte[1 << 20];
for (int i = 0; i < blob.length; i++) {
- blob[i] = (byte)i;
+ blob[i] = (byte) i;
}
// Make a message containing it.
@@ -415,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);
@@ -437,16 +477,23 @@ public class CodedInputStreamTest extends TestCase {
}
}
+ private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
+ assertEquals(
+ InvalidProtocolBufferException.sizeLimitExceeded().getMessage(),
+ e.getMessage());
+ }
+
public void testSizeLimit() throws Exception {
CodedInputStream input = CodedInputStream.newInstance(
- TestUtil.getAllSet().toByteString().newInput());
+ new SmallBlockInputStream(
+ TestUtil.getAllSet().toByteString().newInput(), 16));
input.setSizeLimit(16);
try {
TestAllTypes.parseFrom(input);
fail("Should have thrown an exception!");
- } catch (InvalidProtocolBufferException e) {
- // success.
+ } catch (InvalidProtocolBufferException expected) {
+ checkSizeLimitExceeded(expected);
}
}
@@ -460,8 +507,8 @@ public class CodedInputStreamTest extends TestCase {
try {
input.readRawByte();
fail("Should have thrown an exception!");
- } catch (InvalidProtocolBufferException e) {
- // success.
+ } catch (InvalidProtocolBufferException expected) {
+ checkSizeLimitExceeded(expected);
}
input.resetSizeCounter();
@@ -469,28 +516,50 @@ public class CodedInputStreamTest extends TestCase {
input.readRawByte(); // No exception thrown.
input.resetSizeCounter();
assertEquals(0, input.getTotalBytesRead());
+ input.readRawBytes(16);
+ assertEquals(16, input.getTotalBytesRead());
+ input.resetSizeCounter();
try {
- input.readRawBytes(16); // Hits limit again.
+ input.readRawBytes(17); // Hits limit again.
fail("Should have thrown an exception!");
- } catch (InvalidProtocolBufferException e) {
- // success.
+ } catch (InvalidProtocolBufferException expected) {
+ checkSizeLimitExceeded(expected);
+ }
+ }
+
+ public void testSizeLimitMultipleMessages() throws Exception {
+ byte[] bytes = new byte[256];
+ for (int i = 0; i < bytes.length; i++) {
+ bytes[i] = (byte) i;
+ }
+ CodedInputStream input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(bytes, 7));
+ input.setSizeLimit(16);
+ for (int i = 0; i < 256 / 16; i++) {
+ byte[] message = input.readRawBytes(16);
+ for (int j = 0; j < message.length; j++) {
+ assertEquals(i * 16 + j, message[j] & 0xff);
+ }
+ assertEquals(16, input.getTotalBytesRead());
+ input.resetSizeCounter();
+ assertEquals(0, input.getTotalBytesRead());
}
}
/**
- * Tests that if we read an string that contains invalid UTF-8, no exception
+ * Tests that if we readString invalid UTF-8 bytes, no exception
* is thrown. Instead, the invalid bytes are replaced with the Unicode
* "replacement character" U+FFFD.
*/
- public void testReadInvalidUtf8() throws Exception {
+ public void testReadStringInvalidUtf8() throws Exception {
ByteString.Output rawOutput = ByteString.newOutput();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
output.writeRawVarint32(tag);
output.writeRawVarint32(1);
- output.writeRawBytes(new byte[] { (byte)0x80 });
+ output.writeRawBytes(new byte[] { (byte) 0x80 });
output.flush();
CodedInputStream input = rawOutput.toByteString().newCodedInput();
@@ -499,13 +568,37 @@ public class CodedInputStreamTest extends TestCase {
assertEquals(0xfffd, text.charAt(0));
}
+ /**
+ * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an
+ * InvalidProtocolBufferException is thrown.
+ */
+ public void testReadStringRequireUtf8InvalidUtf8() throws Exception {
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+ int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(tag);
+ output.writeRawVarint32(1);
+ output.writeRawBytes(new byte[] { (byte) 0x80 });
+ output.flush();
+
+ CodedInputStream input = rawOutput.toByteString().newCodedInput();
+ assertEquals(tag, input.readTag());
+ try {
+ input.readStringRequireUtf8();
+ fail("Expected invalid UTF-8 exception.");
+ } catch (InvalidProtocolBufferException exception) {
+ assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+ }
+ }
+
public void testReadFromSlice() throws Exception {
byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
assertEquals(0, in.getTotalBytesRead());
for (int i = 3; i < 8; i++) {
assertEquals(i, in.readRawByte());
- assertEquals(i-2, in.getTotalBytesRead());
+ assertEquals(i - 2, in.getTotalBytesRead());
}
// eof
assertEquals(0, in.readTag());
@@ -525,4 +618,152 @@ public class CodedInputStreamTest extends TestCase {
}
}
}
+
+ public void testReadByteArray() throws Exception {
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ // Zero-sized bytes field.
+ output.writeRawVarint32(0);
+ // One one-byte bytes field
+ output.writeRawVarint32(1);
+ output.writeRawBytes(new byte[] { (byte) 23 });
+ // Another one-byte bytes field
+ output.writeRawVarint32(1);
+ output.writeRawBytes(new byte[] { (byte) 45 });
+ // A bytes field large enough that won't fit into the 4K buffer.
+ final int bytesLength = 16 * 1024;
+ byte[] bytes = new byte[bytesLength];
+ bytes[0] = (byte) 67;
+ bytes[bytesLength - 1] = (byte) 89;
+ output.writeRawVarint32(bytesLength);
+ output.writeRawBytes(bytes);
+
+ output.flush();
+ CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
+
+ byte[] result = inputStream.readByteArray();
+ assertEquals(0, result.length);
+ result = inputStream.readByteArray();
+ assertEquals(1, result.length);
+ assertEquals((byte) 23, result[0]);
+ result = inputStream.readByteArray();
+ assertEquals(1, result.length);
+ assertEquals((byte) 45, result[0]);
+ result = inputStream.readByteArray();
+ assertEquals(bytesLength, result.length);
+ assertEquals((byte) 67, result[0]);
+ assertEquals((byte) 89, result[bytesLength - 1]);
+ }
+
+ public void testReadByteBuffer() throws Exception {
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ // Zero-sized bytes field.
+ output.writeRawVarint32(0);
+ // One one-byte bytes field
+ output.writeRawVarint32(1);
+ output.writeRawBytes(new byte[]{(byte) 23});
+ // Another one-byte bytes field
+ output.writeRawVarint32(1);
+ output.writeRawBytes(new byte[]{(byte) 45});
+ // A bytes field large enough that won't fit into the 4K buffer.
+ final int bytesLength = 16 * 1024;
+ byte[] bytes = new byte[bytesLength];
+ bytes[0] = (byte) 67;
+ bytes[bytesLength - 1] = (byte) 89;
+ output.writeRawVarint32(bytesLength);
+ output.writeRawBytes(bytes);
+
+ output.flush();
+ CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
+
+ ByteBuffer result = inputStream.readByteBuffer();
+ assertEquals(0, result.capacity());
+ result = inputStream.readByteBuffer();
+ assertEquals(1, result.capacity());
+ assertEquals((byte) 23, result.get());
+ result = inputStream.readByteBuffer();
+ assertEquals(1, result.capacity());
+ assertEquals((byte) 45, result.get());
+ result = inputStream.readByteBuffer();
+ assertEquals(bytesLength, result.capacity());
+ assertEquals((byte) 67, result.get());
+ result.position(bytesLength - 1);
+ assertEquals((byte) 89, result.get());
+ }
+
+ public void testReadByteBufferAliasing() throws Exception {
+ ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream);
+ // Zero-sized bytes field.
+ output.writeRawVarint32(0);
+ // One one-byte bytes field
+ output.writeRawVarint32(1);
+ output.writeRawBytes(new byte[]{(byte) 23});
+ // Another one-byte bytes field
+ output.writeRawVarint32(1);
+ output.writeRawBytes(new byte[]{(byte) 45});
+ // A bytes field large enough that won't fit into the 4K buffer.
+ final int bytesLength = 16 * 1024;
+ byte[] bytes = new byte[bytesLength];
+ bytes[0] = (byte) 67;
+ bytes[bytesLength - 1] = (byte) 89;
+ output.writeRawVarint32(bytesLength);
+ output.writeRawBytes(bytes);
+ output.flush();
+ byte[] data = byteArrayStream.toByteArray();
+
+ // Without aliasing
+ CodedInputStream inputStream = CodedInputStream.newInstance(data);
+ ByteBuffer result = inputStream.readByteBuffer();
+ assertEquals(0, result.capacity());
+ result = inputStream.readByteBuffer();
+ assertTrue(result.array() != data);
+ assertEquals(1, result.capacity());
+ assertEquals((byte) 23, result.get());
+ result = inputStream.readByteBuffer();
+ assertTrue(result.array() != data);
+ assertEquals(1, result.capacity());
+ assertEquals((byte) 45, result.get());
+ result = inputStream.readByteBuffer();
+ assertTrue(result.array() != data);
+ assertEquals(bytesLength, result.capacity());
+ assertEquals((byte) 67, result.get());
+ result.position(bytesLength - 1);
+ assertEquals((byte) 89, result.get());
+
+ // Enable aliasing
+ inputStream = CodedInputStream.newInstance(data);
+ inputStream.enableAliasing(true);
+ result = inputStream.readByteBuffer();
+ assertEquals(0, result.capacity());
+ result = inputStream.readByteBuffer();
+ assertTrue(result.array() == data);
+ assertEquals(1, result.capacity());
+ assertEquals((byte) 23, result.get());
+ result = inputStream.readByteBuffer();
+ assertTrue(result.array() == data);
+ assertEquals(1, result.capacity());
+ assertEquals((byte) 45, result.get());
+ result = inputStream.readByteBuffer();
+ assertTrue(result.array() == data);
+ assertEquals(bytesLength, result.capacity());
+ assertEquals((byte) 67, result.get());
+ result.position(bytesLength - 1);
+ assertEquals((byte) 89, result.get());
+ }
+
+ public void testCompatibleTypes() throws Exception {
+ long data = 0x100000000L;
+ Int64Message message = Int64Message.newBuilder().setData(data).build();
+ ByteString serialized = message.toByteString();
+
+ // Test int64(long) is compatible with bool(boolean)
+ BoolMessage msg2 = BoolMessage.parseFrom(serialized);
+ assertTrue(msg2.getData());
+
+ // Test int64(long) is compatible with int32(int)
+ Int32Message msg3 = Int32Message.parseFrom(serialized);
+ assertEquals((int) data, msg3.getData());
+ }
}
diff --git a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
index 74476e36..0785cc91 100644
--- a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
+++ b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,12 +30,15 @@
package com.google.protobuf;
+import protobuf_unittest.UnittestProto.SparseEnumMessage;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestSparseEnum;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
@@ -302,17 +305,97 @@ public class CodedOutputStreamTest extends TestCase {
}
/** Test writing a message containing a negative enum value. This used to
- * fail because the size was not properly computed as a sign-extended varint. */
+ * fail because the size was not properly computed as a sign-extended varint.
+ */
public void testWriteMessageWithNegativeEnumValue() throws Exception {
- protobuf_unittest.UnittestProto.SparseEnumMessage message =
- protobuf_unittest.UnittestProto.SparseEnumMessage.newBuilder()
- .setSparseEnum(protobuf_unittest.UnittestProto.TestSparseEnum.SPARSE_E)
- .build();
+ SparseEnumMessage message = SparseEnumMessage.newBuilder()
+ .setSparseEnum(TestSparseEnum.SPARSE_E) .build();
assertTrue(message.getSparseEnum().getNumber() < 0);
byte[] rawBytes = message.toByteArray();
- protobuf_unittest.UnittestProto.SparseEnumMessage message2 =
- protobuf_unittest.UnittestProto.SparseEnumMessage.parseFrom(rawBytes);
- assertEquals(protobuf_unittest.UnittestProto.TestSparseEnum.SPARSE_E,
- message2.getSparseEnum());
+ SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
+ assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
+ }
+
+ /** Test getTotalBytesWritten() */
+ public void testGetTotalBytesWritten() throws Exception {
+ final int BUFFER_SIZE = 4 * 1024;
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(BUFFER_SIZE);
+ CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream);
+ byte[] value = "abcde".getBytes("UTF-8");
+ for (int i = 0; i < 1024; ++i) {
+ codedStream.writeRawBytes(value, 0, value.length);
+ }
+ // Make sure we have written more bytes than the buffer could hold. This is
+ // to make the test complete.
+ assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE);
+ assertEquals(value.length * 1024, codedStream.getTotalBytesWritten());
+ }
+
+ public void testWriteToByteBuffer() throws Exception {
+ final int bufferSize = 16 * 1024;
+ ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
+ CodedOutputStream codedStream = CodedOutputStream.newInstance(buffer);
+ // Write raw bytes into the ByteBuffer.
+ final int length1 = 5000;
+ for (int i = 0; i < length1; i++) {
+ codedStream.writeRawByte((byte) 1);
+ }
+ final int length2 = 8 * 1024;
+ byte[] data = new byte[length2];
+ for (int i = 0; i < length2; i++) {
+ data[i] = (byte) 2;
+ }
+ codedStream.writeRawBytes(data);
+ final int length3 = bufferSize - length1 - length2;
+ for (int i = 0; i < length3; i++) {
+ codedStream.writeRawByte((byte) 3);
+ }
+ codedStream.flush();
+
+ // Check that data is correctly written to the ByteBuffer.
+ assertEquals(0, buffer.remaining());
+ buffer.flip();
+ for (int i = 0; i < length1; i++) {
+ assertEquals((byte) 1, buffer.get());
+ }
+ for (int i = 0; i < length2; i++) {
+ assertEquals((byte) 2, buffer.get());
+ }
+ for (int i = 0; i < length3; i++) {
+ assertEquals((byte) 3, buffer.get());
+ }
+ }
+
+ public void testWriteByteBuffer() throws Exception {
+ byte[] value = "abcde".getBytes("UTF-8");
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream);
+ ByteBuffer byteBuffer = ByteBuffer.wrap(value, 0, 1);
+ // This will actually write 5 bytes into the CodedOutputStream as the
+ // ByteBuffer's capacity() is 5.
+ codedStream.writeRawBytes(byteBuffer);
+ // The above call shouldn't affect the ByteBuffer's state.
+ assertEquals(0, byteBuffer.position());
+ assertEquals(1, byteBuffer.limit());
+
+ // The correct way to write part of an array using ByteBuffer.
+ codedStream.writeRawBytes(ByteBuffer.wrap(value, 2, 1).slice());
+
+ codedStream.flush();
+ byte[] result = outputStream.toByteArray();
+ assertEquals(6, result.length);
+ for (int i = 0; i < 5; i++) {
+ assertEquals(value[i], result[i]);
+ }
+ assertEquals(value[2], result[5]);
+ }
+
+ public void testWriteByteArrayWithOffsets() throws Exception {
+ byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
+ byte[] destination = new byte[4];
+ CodedOutputStream codedStream = CodedOutputStream.newInstance(destination);
+ codedStream.writeByteArrayNoTag(fullArray, 2, 2);
+ assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination);
+ assertEquals(3, codedStream.getTotalBytesWritten());
}
}
diff --git a/java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java b/java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
index 1f8bb445..e7905f79 100644
--- a/java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
+++ b/java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
index 65d06e32..05832a12 100644
--- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -31,12 +31,15 @@
package com.google.protobuf;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
+import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
+import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.Descriptors.DescriptorValidationException;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.ServiceDescriptor;
@@ -51,15 +54,19 @@ import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestService;
import protobuf_unittest.UnittestCustomOptions;
+import protobuf_unittest.TestCustomOptions;
+
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
/**
* Unit test for {@link Descriptors}.
@@ -305,6 +312,7 @@ public class DescriptorsTest extends TestCase {
EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
assertEquals(value, enumType.getValues().get(0));
assertEquals("FOREIGN_FOO", value.getName());
+ assertEquals("FOREIGN_FOO", value.toString());
assertEquals(4, value.getNumber());
assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
assertEquals(value, enumType.findValueByNumber(4));
@@ -321,7 +329,6 @@ public class DescriptorsTest extends TestCase {
assertEquals("protobuf_unittest.TestService", service.getFullName());
assertEquals(UnittestProto.getDescriptor(), service.getFile());
- assertEquals(2, service.getMethods().size());
MethodDescriptor fooMethod = service.getMethods().get(0);
assertEquals("Foo", fooMethod.getName());
@@ -348,8 +355,12 @@ public class DescriptorsTest extends TestCase {
public void testCustomOptions() throws Exception {
+ // Get the descriptor indirectly from a dependent proto class. This is to
+ // ensure that when a proto class is loaded, custom options defined in its
+ // dependencies are also properly initialized.
Descriptor descriptor =
- UnittestCustomOptions.TestMessageWithCustomOptions.getDescriptor();
+ TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
+ .findFieldByName("field").getMessageType();
assertTrue(
descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
@@ -426,7 +437,7 @@ public class DescriptorsTest extends TestCase {
UnittestEnormousDescriptor.getDescriptor()
.toProto().getSerializedSize() > 65536);
}
-
+
/**
* Tests that the DescriptorValidationException works as intended.
*/
@@ -445,7 +456,7 @@ public class DescriptorsTest extends TestCase {
.build())
.build();
try {
- Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
+ Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
new FileDescriptor[0]);
fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) {
@@ -457,4 +468,274 @@ public class DescriptorsTest extends TestCase {
assertTrue(e.getCause().getMessage().indexOf("invalid") != -1);
}
}
+
+ /**
+ * Tests the translate/crosslink for an example where a message field's name
+ * and type name are the same.
+ */
+ public void testDescriptorComplexCrosslink() throws Exception {
+ FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addMessageType(DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setType(FieldDescriptorProto.Type.TYPE_INT32)
+ .setName("foo")
+ .setNumber(1)
+ .build())
+ .build())
+ .addMessageType(DescriptorProto.newBuilder()
+ .setName("Bar")
+ .addField(FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Foo")
+ .setName("Foo")
+ .setNumber(1)
+ .build())
+ .build())
+ .build();
+ // translate and crosslink
+ FileDescriptor file =
+ Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
+ new FileDescriptor[0]);
+ // verify resulting descriptors
+ assertNotNull(file);
+ List<Descriptor> msglist = file.getMessageTypes();
+ assertNotNull(msglist);
+ assertTrue(msglist.size() == 2);
+ boolean barFound = false;
+ for (Descriptor desc : msglist) {
+ if (desc.getName().equals("Bar")) {
+ barFound = true;
+ assertNotNull(desc.getFields());
+ List<FieldDescriptor> fieldlist = desc.getFields();
+ assertNotNull(fieldlist);
+ assertTrue(fieldlist.size() == 1);
+ assertTrue(fieldlist.get(0).getType() == FieldDescriptor.Type.MESSAGE);
+ assertTrue(fieldlist.get(0).getMessageType().getName().equals("Foo"));
+ }
+ }
+ assertTrue(barFound);
+ }
+
+ public void testDependencyOrder() throws Exception {
+ FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+ .setName("foo.proto").build();
+ FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+ .setName("bar.proto")
+ .addDependency("foo.proto")
+ .build();
+ FileDescriptorProto bazProto = FileDescriptorProto.newBuilder()
+ .setName("baz.proto")
+ .addDependency("foo.proto")
+ .addDependency("bar.proto")
+ .addPublicDependency(0)
+ .addPublicDependency(1)
+ .build();
+ FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
+ new FileDescriptor[0]);
+ FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto,
+ new FileDescriptor[] {fooFile});
+
+ // Items in the FileDescriptor array can be in any order.
+ Descriptors.FileDescriptor.buildFrom(bazProto,
+ new FileDescriptor[] {fooFile, barFile});
+ Descriptors.FileDescriptor.buildFrom(bazProto,
+ new FileDescriptor[] {barFile, fooFile});
+ }
+
+ public void testInvalidPublicDependency() throws Exception {
+ FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+ .setName("foo.proto").build();
+ FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+ .setName("boo.proto")
+ .addDependency("foo.proto")
+ .addPublicDependency(1) // Error, should be 0.
+ .build();
+ FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
+ new FileDescriptor[0]);
+ try {
+ Descriptors.FileDescriptor.buildFrom(barProto,
+ new FileDescriptor[] {fooFile});
+ fail("DescriptorValidationException expected");
+ } catch (DescriptorValidationException e) {
+ assertTrue(
+ e.getMessage().indexOf("Invalid public dependency index.") != -1);
+ }
+ }
+
+ public void testHiddenDependency() throws Exception {
+ FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+ .setName("bar.proto")
+ .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+ .build();
+ FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
+ .setName("forward.proto")
+ .addDependency("bar.proto")
+ .build();
+ FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addDependency("forward.proto")
+ .addMessageType(DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Bar")
+ .setName("bar")
+ .setNumber(1)))
+ .build();
+ FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
+ barProto, new FileDescriptor[0]);
+ FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
+ forwardProto, new FileDescriptor[] {barFile});
+
+ try {
+ Descriptors.FileDescriptor.buildFrom(
+ fooProto, new FileDescriptor[] {forwardFile});
+ fail("DescriptorValidationException expected");
+ } catch (DescriptorValidationException e) {
+ assertTrue(e.getMessage().indexOf("Bar") != -1);
+ assertTrue(e.getMessage().indexOf("is not defined") != -1);
+ }
+ }
+
+ public void testPublicDependency() throws Exception {
+ FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+ .setName("bar.proto")
+ .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+ .build();
+ FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
+ .setName("forward.proto")
+ .addDependency("bar.proto")
+ .addPublicDependency(0)
+ .build();
+ FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addDependency("forward.proto")
+ .addMessageType(DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Bar")
+ .setName("bar")
+ .setNumber(1)))
+ .build();
+ FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
+ barProto, new FileDescriptor[0]);
+ FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
+ forwardProto, new FileDescriptor[]{barFile});
+ Descriptors.FileDescriptor.buildFrom(
+ fooProto, new FileDescriptor[] {forwardFile});
+ }
+
+ /**
+ * Tests the translate/crosslink for an example with a more complex namespace
+ * referencing.
+ */
+ public void testComplexNamespacePublicDependency() throws Exception {
+ FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+ .setName("bar.proto")
+ .setPackage("a.b.c.d.bar.shared")
+ .addEnumType(EnumDescriptorProto.newBuilder()
+ .setName("MyEnum")
+ .addValue(EnumValueDescriptorProto.newBuilder()
+ .setName("BLAH")
+ .setNumber(1)))
+ .build();
+ FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addDependency("bar.proto")
+ .setPackage("a.b.c.d.foo.shared")
+ .addMessageType(DescriptorProto.newBuilder()
+ .setName("MyMessage")
+ .addField(FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
+ .setTypeName("bar.shared.MyEnum")
+ .setName("MyField")
+ .setNumber(1)))
+ .build();
+ // translate and crosslink
+ FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(
+ fooProto, new FileDescriptor[0]);
+ FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
+ barProto, new FileDescriptor[]{fooFile});
+ // verify resulting descriptors
+ assertNotNull(barFile);
+ List<Descriptor> msglist = barFile.getMessageTypes();
+ assertNotNull(msglist);
+ assertTrue(msglist.size() == 1);
+ Descriptor desc = msglist.get(0);
+ if (desc.getName().equals("MyMessage")) {
+ assertNotNull(desc.getFields());
+ List<FieldDescriptor> fieldlist = desc.getFields();
+ assertNotNull(fieldlist);
+ assertTrue(fieldlist.size() == 1);
+ FieldDescriptor field = fieldlist.get(0);
+ assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
+ assertTrue(field.getEnumType().getName().equals("MyEnum"));
+ assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
+ assertTrue(field.getEnumType().getFile().getPackage().equals(
+ "a.b.c.d.bar.shared"));
+ }
+ }
+
+ public void testOneofDescriptor() throws Exception {
+ Descriptor messageType = TestAllTypes.getDescriptor();
+ FieldDescriptor field =
+ messageType.findFieldByName("oneof_nested_message");
+ OneofDescriptor oneofDescriptor = field.getContainingOneof();
+ assertNotNull(oneofDescriptor);
+ assertSame(oneofDescriptor, messageType.getOneofs().get(0));
+ assertEquals("oneof_field", oneofDescriptor.getName());
+
+ assertEquals(4, oneofDescriptor.getFieldCount());
+ assertSame(oneofDescriptor.getField(1), field);
+ }
+
+ public void testMessageDescriptorExtensions() throws Exception {
+ assertFalse(TestAllTypes.getDescriptor().isExtendable());
+ assertTrue(TestAllExtensions.getDescriptor().isExtendable());
+ assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtendable());
+
+ assertFalse(TestAllTypes.getDescriptor().isExtensionNumber(3));
+ assertTrue(TestAllExtensions.getDescriptor().isExtensionNumber(3));
+ assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42));
+ assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43));
+ assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142));
+ 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")
+ .addEnumType(EnumDescriptorProto.newBuilder()
+ .setName("Enum")
+ .addValue(EnumValueDescriptorProto.newBuilder()
+ .setName("FOO")
+ .setNumber(1)
+ .build())
+ .build())
+ .addMessageType(DescriptorProto.newBuilder()
+ .setName("Message")
+ .addField(FieldDescriptorProto.newBuilder()
+ .setName("foo")
+ .setTypeName("Enum")
+ .setNumber(1)
+ .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
+ .setOptions(DescriptorProtos.FieldOptions.newBuilder()
+ .setPacked(true)
+ .build())
+ .build())
+ .build())
+ .build();
+ Descriptors.FileDescriptor.buildFrom(
+ fileDescriptorProto, new FileDescriptor[0]);
+ }
}
diff --git a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java
index aabccda2..55144e7c 100644
--- a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java
+++ b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,8 +30,13 @@
package com.google.protobuf;
-import protobuf_unittest.UnittestProto.TestAllTypes;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+
import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import junit.framework.TestCase;
@@ -61,28 +66,44 @@ public class DynamicMessageTest extends TestCase {
reflectionTester.assertAllFieldsSetViaReflection(message);
}
- public void testDoubleBuildError() throws Exception {
+ public void testSettersAfterBuild() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ Message firstMessage = builder.build();
+ // double build()
builder.build();
- try {
- builder.build();
- fail("Should have thrown exception.");
- } catch (IllegalStateException e) {
- // Success.
- }
+ // clear() after build()
+ builder.clear();
+ // setters after build()
+ reflectionTester.setAllFieldsViaReflection(builder);
+ Message message = builder.build();
+ reflectionTester.assertAllFieldsSetViaReflection(message);
+ // repeated setters after build()
+ reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+ message = builder.build();
+ reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
+ // firstMessage shouldn't have been modified.
+ reflectionTester.assertClearViaReflection(firstMessage);
}
- public void testClearAfterBuildError() throws Exception {
+ public void testUnknownFields() throws Exception {
Message.Builder builder =
- DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
- builder.build();
- try {
- builder.clear();
- fail("Should have thrown exception.");
- } catch (IllegalStateException e) {
- // Success.
- }
+ DynamicMessage.newBuilder(TestEmptyMessage.getDescriptor());
+ builder.setUnknownFields(UnknownFieldSet.newBuilder()
+ .addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build())
+ .addField(2, UnknownFieldSet.Field.newBuilder().addFixed32(1).build())
+ .build());
+ Message message = builder.build();
+ assertEquals(2, message.getUnknownFields().asMap().size());
+ // clone() with unknown fields
+ Message.Builder newBuilder = builder.clone();
+ assertEquals(2, newBuilder.getUnknownFields().asMap().size());
+ // clear() with unknown fields
+ newBuilder.clear();
+ assertTrue(newBuilder.getUnknownFields().asMap().isEmpty());
+ // serialize/parse with unknown fields
+ newBuilder.mergeFrom(message.toByteString());
+ assertEquals(2, newBuilder.getUnknownFields().asMap().size());
}
public void testDynamicMessageSettersRejectNull() throws Exception {
@@ -167,6 +188,23 @@ public class DynamicMessageTest extends TestCase {
Message message2 =
DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes);
reflectionTester.assertAllFieldsSetViaReflection(message2);
+
+ // Test Parser interface.
+ Message message3 = message2.getParserForType().parseFrom(rawBytes);
+ reflectionTester.assertAllFieldsSetViaReflection(message3);
+ }
+
+ public void testDynamicMessageExtensionParsing() throws Exception {
+ ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString();
+ Message message = DynamicMessage.parseFrom(
+ TestAllExtensions.getDescriptor(), rawBytes,
+ TestUtil.getExtensionRegistry());
+ extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+
+ // Test Parser interface.
+ Message message2 = message.getParserForType().parseFrom(
+ rawBytes, TestUtil.getExtensionRegistry());
+ extensionsReflectionTester.assertAllFieldsSetViaReflection(message2);
}
public void testDynamicMessagePackedSerialization() throws Exception {
@@ -194,6 +232,10 @@ public class DynamicMessageTest extends TestCase {
Message message2 =
DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes);
packedReflectionTester.assertPackedFieldsSetViaReflection(message2);
+
+ // Test Parser interface.
+ Message message3 = message2.getParserForType().parseFrom(rawBytes);
+ packedReflectionTester.assertPackedFieldsSetViaReflection(message3);
}
public void testDynamicMessageCopy() throws Exception {
@@ -203,6 +245,19 @@ public class DynamicMessageTest extends TestCase {
DynamicMessage copy = DynamicMessage.newBuilder(message).build();
reflectionTester.assertAllFieldsSetViaReflection(copy);
+
+ // Test oneof behavior
+ FieldDescriptor bytesField =
+ TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
+ FieldDescriptor uint32Field =
+ TestAllTypes.getDescriptor().findFieldByName("oneof_uint32");
+ assertTrue(copy.hasField(bytesField));
+ assertFalse(copy.hasField(uint32Field));
+ DynamicMessage copy2 =
+ DynamicMessage.newBuilder(message).setField(uint32Field, 123).build();
+ assertFalse(copy2.hasField(bytesField));
+ assertTrue(copy2.hasField(uint32Field));
+ assertEquals(123, copy2.getField(uint32Field));
}
public void testToBuilder() throws Exception {
@@ -223,4 +278,49 @@ public class DynamicMessageTest extends TestCase {
assertEquals(Arrays.asList(unknownFieldVal),
derived.getUnknownFields().getField(unknownFieldNum).getVarintList());
}
+
+ public void testDynamicOneofMessage() throws Exception {
+ DynamicMessage.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0);
+ assertFalse(builder.hasOneof(oneof));
+ assertSame(null, builder.getOneofFieldDescriptor(oneof));
+
+ reflectionTester.setAllFieldsViaReflection(builder);
+ assertTrue(builder.hasOneof(oneof));
+ FieldDescriptor field = oneof.getField(3);
+ assertSame(field, builder.getOneofFieldDescriptor(oneof));
+
+ DynamicMessage message = builder.buildPartial();
+ assertTrue(message.hasOneof(oneof));
+
+ DynamicMessage.Builder mergedBuilder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ FieldDescriptor mergedField = oneof.getField(0);
+ mergedBuilder.setField(mergedField, 123);
+ assertTrue(mergedBuilder.hasField(mergedField));
+ mergedBuilder.mergeFrom(message);
+ assertTrue(mergedBuilder.hasField(field));
+ assertFalse(mergedBuilder.hasField(mergedField));
+
+ builder.clearOneof(oneof);
+ assertSame(null, builder.getOneofFieldDescriptor(oneof));
+ message = builder.build();
+ assertSame(null, message.getOneofFieldDescriptor(oneof));
+ }
+
+ // Regression test for a bug that makes setField() not work for repeated
+ // enum fields.
+ public void testSettersForRepeatedEnumField() throws Exception {
+ DynamicMessage.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ FieldDescriptor repeatedEnumField =
+ TestAllTypes.getDescriptor().findFieldByName(
+ "repeated_nested_enum");
+ EnumDescriptor enumDescriptor = TestAllTypes.NestedEnum.getDescriptor();
+ builder.setField(repeatedEnumField, enumDescriptor.getValues());
+ DynamicMessage message = builder.build();
+ assertEquals(
+ enumDescriptor.getValues(), message.getField(repeatedEnumField));
+ }
}
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/ForceFieldBuildersPreRun.java b/java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
index 8b78893d..a92ba374 100644
--- a/java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
+++ b/java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
index b9dd40bf..2bd8d1a9 100644
--- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.test.UnittestImport;
import protobuf_unittest.EnumWithNoOuter;
@@ -43,6 +45,9 @@ import protobuf_unittest.NonNestedExtension.MyNonNestedExtension;
import protobuf_unittest.NonNestedExtensionLite;
import protobuf_unittest.NonNestedExtensionLite.MessageLiteToBeExtended;
import protobuf_unittest.NonNestedExtensionLite.MyNonNestedExtensionLite;
+import protobuf_unittest.OuterClassNameTest2OuterClass;
+import protobuf_unittest.OuterClassNameTest3OuterClass;
+import protobuf_unittest.OuterClassNameTestOuterClass;
import protobuf_unittest.ServiceWithNoOuter;
import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
import protobuf_unittest.UnittestOptimizeFor.TestOptionalOptimizedForSize;
@@ -51,10 +56,13 @@ import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.ForeignEnum;
import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.ForeignMessageOrBuilder;
+import protobuf_unittest.UnittestProto.NestedTestAllTypes;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestUnpackedTypes;
@@ -66,6 +74,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
/**
@@ -149,15 +158,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());
}
@@ -180,6 +186,33 @@ public class GeneratedMessageTest extends TestCase {
assertIsUnmodifiable(value.getRepeatedFloatList());
}
+ public void testParsedMessagesAreImmutable() throws Exception {
+ TestAllTypes value = TestAllTypes.PARSER.parseFrom(
+ TestUtil.getAllSet().toByteString());
+ assertIsUnmodifiable(value.getRepeatedInt32List());
+ assertIsUnmodifiable(value.getRepeatedInt64List());
+ assertIsUnmodifiable(value.getRepeatedUint32List());
+ assertIsUnmodifiable(value.getRepeatedUint64List());
+ assertIsUnmodifiable(value.getRepeatedSint32List());
+ assertIsUnmodifiable(value.getRepeatedSint64List());
+ assertIsUnmodifiable(value.getRepeatedFixed32List());
+ assertIsUnmodifiable(value.getRepeatedFixed64List());
+ assertIsUnmodifiable(value.getRepeatedSfixed32List());
+ assertIsUnmodifiable(value.getRepeatedSfixed64List());
+ assertIsUnmodifiable(value.getRepeatedFloatList());
+ assertIsUnmodifiable(value.getRepeatedDoubleList());
+ assertIsUnmodifiable(value.getRepeatedBoolList());
+ assertIsUnmodifiable(value.getRepeatedStringList());
+ assertIsUnmodifiable(value.getRepeatedBytesList());
+ assertIsUnmodifiable(value.getRepeatedGroupList());
+ assertIsUnmodifiable(value.getRepeatedNestedMessageList());
+ assertIsUnmodifiable(value.getRepeatedForeignMessageList());
+ assertIsUnmodifiable(value.getRepeatedImportMessageList());
+ assertIsUnmodifiable(value.getRepeatedNestedEnumList());
+ assertIsUnmodifiable(value.getRepeatedForeignEnumList());
+ assertIsUnmodifiable(value.getRepeatedImportEnumList());
+ }
+
private void assertIsUnmodifiable(List<?> list) {
if (list == Collections.emptyList()) {
// OKAY -- Need to check this b/c EmptyList allows you to call clear.
@@ -369,6 +402,44 @@ public class GeneratedMessageTest extends TestCase {
// We expect this exception.
}
}
+
+ public void testRepeatedAppendIterateOnlyOnce() throws Exception {
+ // Create a Iterable that can only be iterated once.
+ Iterable<String> stringIterable = new Iterable<String>() {
+ private boolean called = false;
+ @Override
+ public Iterator<String> iterator() {
+ if (called) {
+ throw new IllegalStateException();
+ }
+ called = true;
+ return Arrays.asList("one", "two", "three").iterator();
+ }
+ };
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ builder.addAllRepeatedString(stringIterable);
+ assertEquals(3, builder.getRepeatedStringCount());
+ assertEquals("one", builder.getRepeatedString(0));
+ assertEquals("two", builder.getRepeatedString(1));
+ assertEquals("three", builder.getRepeatedString(2));
+
+ try {
+ builder.addAllRepeatedString(stringIterable);
+ fail("Exception was not thrown");
+ } catch (IllegalStateException e) {
+ // We expect this exception.
+ }
+ }
+
+ public void testMergeFromOtherRejectsNull() throws Exception {
+ try {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ builder.mergeFrom((TestAllTypes) null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ }
public void testSettingForeignMessageUsingBuilder() throws Exception {
TestAllTypes message = TestAllTypes.newBuilder()
@@ -466,6 +537,34 @@ public class GeneratedMessageTest extends TestCase {
TestAllTypes.newBuilder().build());
}
+ public void testReflectionGetOneof() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ reflectionTester.setAllFieldsViaReflection(builder);
+ Descriptors.OneofDescriptor oneof =
+ TestAllTypes.getDescriptor().getOneofs().get(0);
+ Descriptors.FieldDescriptor field =
+ TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
+ assertSame(field, builder.getOneofFieldDescriptor(oneof));
+
+ TestAllTypes message = builder.build();
+ assertSame(field, message.getOneofFieldDescriptor(oneof));
+ }
+
+ public void testReflectionClearOneof() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ reflectionTester.setAllFieldsViaReflection(builder);
+ Descriptors.OneofDescriptor oneof =
+ TestAllTypes.getDescriptor().getOneofs().get(0);
+ Descriptors.FieldDescriptor field =
+ TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
+
+ assertTrue(builder.hasOneof(oneof));
+ assertTrue(builder.hasField(field));
+ builder.clearOneof(oneof);
+ assertFalse(builder.hasOneof(oneof));
+ assertFalse(builder.hasField(field));
+ }
+
public void testEnumInterface() throws Exception {
assertTrue(TestAllTypes.getDefaultInstance().getDefaultNestedEnum()
instanceof ProtocolMessageEnum);
@@ -667,6 +766,15 @@ public class GeneratedMessageTest extends TestCase {
// =================================================================
// multiple_files_test
+ // Test that custom options of an file level enum are properly initialized.
+ // This test needs to be put before any other access to MultipleFilesTestProto
+ // or messages defined in multiple_files_test.proto because the class loading
+ // order affects initialization process of custom options.
+ public void testEnumValueOptionsInMultipleFilesMode() throws Exception {
+ assertEquals(12345, EnumWithNoOuter.FOO.getValueDescriptor().getOptions()
+ .getExtension(MultipleFilesTestProto.enumValueOption).intValue());
+ }
+
public void testMultipleFilesOption() throws Exception {
// We mostly just want to check that things compile.
MessageWithNoOuter message =
@@ -765,7 +873,7 @@ public class GeneratedMessageTest extends TestCase {
UnittestProto.TestRecursiveMessage message =
UnittestProto.TestRecursiveMessage.getDefaultInstance();
assertTrue(message != null);
- assertTrue(message.getA() != null);
+ assertNotNull(message.getA());
assertTrue(message.getA() == message);
}
@@ -775,8 +883,11 @@ public class GeneratedMessageTest extends TestCase {
TestUtil.setAllFields(builder);
TestAllTypes expected = builder.build();
ObjectOutputStream out = new ObjectOutputStream(baos);
- out.writeObject(expected);
- out.close();
+ try {
+ out.writeObject(expected);
+ } finally {
+ out.close();
+ }
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bais);
TestAllTypes actual = (TestAllTypes) in.readObject();
@@ -788,8 +899,11 @@ public class GeneratedMessageTest extends TestCase {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TestAllTypes expected = builder.buildPartial();
ObjectOutputStream out = new ObjectOutputStream(baos);
- out.writeObject(expected);
- out.close();
+ try {
+ out.writeObject(expected);
+ } finally {
+ out.close();
+ }
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bais);
TestAllTypes actual = (TestAllTypes) in.readObject();
@@ -875,7 +989,7 @@ public class GeneratedMessageTest extends TestCase {
builder.setOptionalNestedMessage(nestedMessage1);
assertEquals(3, mockParent.getInvalidationCount());
- // primitive repated
+ // primitive repeated
builder.buildPartial();
builder.addRepeatedInt32(2);
builder.addRepeatedInt32(3);
@@ -971,4 +1085,578 @@ public class GeneratedMessageTest extends TestCase {
assertSame(b1, messageOrBuilderList.get(1));
assertSame(m2, messageOrBuilderList.get(2));
}
+
+ public void testGetFieldBuilder() {
+ Descriptor descriptor = TestAllTypes.getDescriptor();
+
+ FieldDescriptor fieldDescriptor =
+ descriptor.findFieldByName("optional_nested_message");
+ FieldDescriptor foreignFieldDescriptor =
+ descriptor.findFieldByName("optional_foreign_message");
+ FieldDescriptor importFieldDescriptor =
+ descriptor.findFieldByName("optional_import_message");
+
+ // Mutate the message with new field builder
+ // Mutate nested message
+ TestAllTypes.Builder builder1 = TestAllTypes.newBuilder();
+ Message.Builder fieldBuilder1 = builder1.newBuilderForField(fieldDescriptor)
+ .mergeFrom((Message) builder1.getField(fieldDescriptor));
+ FieldDescriptor subFieldDescriptor1 =
+ fieldBuilder1.getDescriptorForType().findFieldByName("bb");
+ fieldBuilder1.setField(subFieldDescriptor1, 1);
+ builder1.setField(fieldDescriptor, fieldBuilder1.build());
+
+ // Mutate foreign message
+ Message.Builder foreignFieldBuilder1 = builder1.newBuilderForField(
+ foreignFieldDescriptor)
+ .mergeFrom((Message) builder1.getField(foreignFieldDescriptor));
+ FieldDescriptor subForeignFieldDescriptor1 =
+ foreignFieldBuilder1.getDescriptorForType().findFieldByName("c");
+ foreignFieldBuilder1.setField(subForeignFieldDescriptor1, 2);
+ builder1.setField(foreignFieldDescriptor, foreignFieldBuilder1.build());
+
+ // Mutate import message
+ Message.Builder importFieldBuilder1 = builder1.newBuilderForField(
+ importFieldDescriptor)
+ .mergeFrom((Message) builder1.getField(importFieldDescriptor));
+ FieldDescriptor subImportFieldDescriptor1 =
+ importFieldBuilder1.getDescriptorForType().findFieldByName("d");
+ importFieldBuilder1.setField(subImportFieldDescriptor1, 3);
+ builder1.setField(importFieldDescriptor, importFieldBuilder1.build());
+
+ Message newMessage1 = builder1.build();
+
+ // Mutate the message with existing field builder
+ // Mutate nested message
+ TestAllTypes.Builder builder2 = TestAllTypes.newBuilder();
+ Message.Builder fieldBuilder2 = builder2.getFieldBuilder(fieldDescriptor);
+ FieldDescriptor subFieldDescriptor2 =
+ fieldBuilder2.getDescriptorForType().findFieldByName("bb");
+ fieldBuilder2.setField(subFieldDescriptor2, 1);
+ builder2.setField(fieldDescriptor, fieldBuilder2.build());
+
+ // Mutate foreign message
+ Message.Builder foreignFieldBuilder2 = builder2.newBuilderForField(
+ foreignFieldDescriptor)
+ .mergeFrom((Message) builder2.getField(foreignFieldDescriptor));
+ FieldDescriptor subForeignFieldDescriptor2 =
+ foreignFieldBuilder2.getDescriptorForType().findFieldByName("c");
+ foreignFieldBuilder2.setField(subForeignFieldDescriptor2, 2);
+ builder2.setField(foreignFieldDescriptor, foreignFieldBuilder2.build());
+
+ // Mutate import message
+ Message.Builder importFieldBuilder2 = builder2.newBuilderForField(
+ importFieldDescriptor)
+ .mergeFrom((Message) builder2.getField(importFieldDescriptor));
+ FieldDescriptor subImportFieldDescriptor2 =
+ importFieldBuilder2.getDescriptorForType().findFieldByName("d");
+ importFieldBuilder2.setField(subImportFieldDescriptor2, 3);
+ builder2.setField(importFieldDescriptor, importFieldBuilder2.build());
+
+ Message newMessage2 = builder2.build();
+
+ // These two messages should be equal.
+ assertEquals(newMessage1, newMessage2);
+ }
+
+ public void testGetFieldBuilderWithInitializedValue() {
+ Descriptor descriptor = TestAllTypes.getDescriptor();
+ FieldDescriptor fieldDescriptor =
+ descriptor.findFieldByName("optional_nested_message");
+
+ // Before setting field, builder is initialized by default value.
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ NestedMessage.Builder fieldBuilder =
+ (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
+ assertEquals(0, fieldBuilder.getBb());
+
+ // Setting field value with new field builder instance.
+ builder = TestAllTypes.newBuilder();
+ NestedMessage.Builder newFieldBuilder =
+ builder.getOptionalNestedMessageBuilder();
+ newFieldBuilder.setBb(2);
+ // Then get the field builder instance by getFieldBuilder().
+ fieldBuilder =
+ (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
+ // It should contain new value.
+ assertEquals(2, fieldBuilder.getBb());
+ // These two builder should be equal.
+ assertSame(fieldBuilder, newFieldBuilder);
+ }
+
+ public void testGetFieldBuilderNotSupportedException() {
+ Descriptor descriptor = TestAllTypes.getDescriptor();
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ try {
+ builder.getFieldBuilder(descriptor.findFieldByName("optional_int32"));
+ fail("Exception was not thrown");
+ } catch (UnsupportedOperationException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.getFieldBuilder(
+ descriptor.findFieldByName("optional_nested_enum"));
+ fail("Exception was not thrown");
+ } catch (UnsupportedOperationException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.getFieldBuilder(descriptor.findFieldByName("repeated_int32"));
+ fail("Exception was not thrown");
+ } catch (UnsupportedOperationException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.getFieldBuilder(
+ descriptor.findFieldByName("repeated_nested_enum"));
+ fail("Exception was not thrown");
+ } catch (UnsupportedOperationException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.getFieldBuilder(
+ descriptor.findFieldByName("repeated_nested_message"));
+ fail("Exception was not thrown");
+ } catch (UnsupportedOperationException e) {
+ // We expect this exception.
+ }
+ }
+
+ // Test that when the default outer class name conflicts with another type
+ // defined in the proto the compiler will append a suffix to avoid the
+ // conflict.
+ public void testConflictingOuterClassName() {
+ // We just need to make sure we can refer to the outer class with the
+ // expected name. There is nothing else to test.
+ OuterClassNameTestOuterClass.OuterClassNameTest message =
+ OuterClassNameTestOuterClass.OuterClassNameTest.newBuilder().build();
+ assertTrue(message.getDescriptorForType() ==
+ OuterClassNameTestOuterClass.OuterClassNameTest.getDescriptor());
+
+ OuterClassNameTest2OuterClass.TestMessage2.NestedMessage.OuterClassNameTest2
+ message2 = OuterClassNameTest2OuterClass.TestMessage2.NestedMessage
+ .OuterClassNameTest2.newBuilder().build();
+ assertEquals(0, message2.getSerializedSize());
+
+ OuterClassNameTest3OuterClass.TestMessage3.NestedMessage.OuterClassNameTest3
+ enumValue = OuterClassNameTest3OuterClass.TestMessage3.NestedMessage
+ .OuterClassNameTest3.DUMMY_VALUE;
+ assertEquals(1, enumValue.getNumber());
+ }
+
+ // =================================================================
+ // oneof generated code test
+ public void testOneofEnumCase() throws Exception {
+ TestOneof2 message = TestOneof2.newBuilder()
+ .setFooInt(123).setFooString("foo").setFooCord("bar").build();
+ TestUtil.assertAtMostOneFieldSetOneof(message);
+ }
+
+ public void testClearOneof() throws Exception {
+ TestOneof2.Builder builder = TestOneof2.newBuilder().setFooInt(123);
+ assertEquals(TestOneof2.FooCase.FOO_INT, builder.getFooCase());
+ builder.clearFoo();
+ assertEquals(TestOneof2.FooCase.FOO_NOT_SET, builder.getFooCase());
+ }
+
+ public void testSetOneofClearsOthers() throws Exception {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestOneof2 message =
+ builder.setFooInt(123).setFooString("foo").buildPartial();
+ assertTrue(message.hasFooString());
+ TestUtil.assertAtMostOneFieldSetOneof(message);
+
+ message = builder.setFooCord("bar").buildPartial();
+ assertTrue(message.hasFooCord());
+ TestUtil.assertAtMostOneFieldSetOneof(message);
+
+ message = builder.setFooStringPiece("baz").buildPartial();
+ assertTrue(message.hasFooStringPiece());
+ TestUtil.assertAtMostOneFieldSetOneof(message);
+
+ message = builder.setFooBytes(TestUtil.toBytes("qux")).buildPartial();
+ assertTrue(message.hasFooBytes());
+ TestUtil.assertAtMostOneFieldSetOneof(message);
+
+ message = builder.setFooEnum(TestOneof2.NestedEnum.FOO).buildPartial();
+ assertTrue(message.hasFooEnum());
+ TestUtil.assertAtMostOneFieldSetOneof(message);
+
+ message = builder.setFooMessage(
+ TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).buildPartial();
+ assertTrue(message.hasFooMessage());
+ TestUtil.assertAtMostOneFieldSetOneof(message);
+
+ message = builder.setFooInt(123).buildPartial();
+ assertTrue(message.hasFooInt());
+ TestUtil.assertAtMostOneFieldSetOneof(message);
+ }
+
+ public void testOneofTypes() throws Exception {
+ // Primitive
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ assertEquals(builder.getFooInt(), 0);
+ assertFalse(builder.hasFooInt());
+ assertTrue(builder.setFooInt(123).hasFooInt());
+ assertEquals(builder.getFooInt(), 123);
+ TestOneof2 message = builder.buildPartial();
+ assertTrue(message.hasFooInt());
+ assertEquals(message.getFooInt(), 123);
+
+ assertFalse(builder.clearFooInt().hasFooInt());
+ TestOneof2 message2 = builder.build();
+ assertFalse(message2.hasFooInt());
+ assertEquals(message2.getFooInt(), 0);
+ }
+
+ // Enum
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.FOO);
+ assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum());
+ assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.BAR);
+ TestOneof2 message = builder.buildPartial();
+ assertTrue(message.hasFooEnum());
+ assertEquals(message.getFooEnum(), TestOneof2.NestedEnum.BAR);
+
+ assertFalse(builder.clearFooEnum().hasFooEnum());
+ TestOneof2 message2 = builder.build();
+ assertFalse(message2.hasFooEnum());
+ assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.FOO);
+ }
+
+ // String
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ assertEquals(builder.getFooString(), "");
+ builder.setFooString("foo");
+ assertTrue(builder.hasFooString());
+ assertEquals(builder.getFooString(), "foo");
+ TestOneof2 message = builder.buildPartial();
+ assertTrue(message.hasFooString());
+ assertEquals(message.getFooString(), "foo");
+ assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo"));
+
+ assertFalse(builder.clearFooString().hasFooString());
+ TestOneof2 message2 = builder.buildPartial();
+ assertFalse(message2.hasFooString());
+ assertEquals(message2.getFooString(), "");
+ assertEquals(message2.getFooStringBytes(), TestUtil.toBytes(""));
+
+ // Get method should not change the oneof value.
+ builder.setFooInt(123);
+ assertEquals(builder.getFooString(), "");
+ assertEquals(builder.getFooStringBytes(), TestUtil.toBytes(""));
+ assertEquals(123, builder.getFooInt());
+
+ message = builder.build();
+ assertEquals(message.getFooString(), "");
+ assertEquals(message.getFooStringBytes(), TestUtil.toBytes(""));
+ assertEquals(123, message.getFooInt());
+ }
+
+ // Cord
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ assertEquals(builder.getFooCord(), "");
+ builder.setFooCord("foo");
+ assertTrue(builder.hasFooCord());
+ assertEquals(builder.getFooCord(), "foo");
+ TestOneof2 message = builder.buildPartial();
+ assertTrue(message.hasFooCord());
+ assertEquals(message.getFooCord(), "foo");
+ assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo"));
+
+ assertFalse(builder.clearFooCord().hasFooCord());
+ TestOneof2 message2 = builder.build();
+ assertFalse(message2.hasFooCord());
+ assertEquals(message2.getFooCord(), "");
+ assertEquals(message2.getFooCordBytes(), TestUtil.toBytes(""));
+ }
+
+ // StringPiece
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ assertEquals(builder.getFooStringPiece(), "");
+ builder.setFooStringPiece("foo");
+ assertTrue(builder.hasFooStringPiece());
+ assertEquals(builder.getFooStringPiece(), "foo");
+ TestOneof2 message = builder.buildPartial();
+ assertTrue(message.hasFooStringPiece());
+ assertEquals(message.getFooStringPiece(), "foo");
+ assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo"));
+
+ assertFalse(builder.clearFooStringPiece().hasFooStringPiece());
+ TestOneof2 message2 = builder.build();
+ assertFalse(message2.hasFooStringPiece());
+ assertEquals(message2.getFooStringPiece(), "");
+ assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes(""));
+ }
+
+ // Message
+ {
+ // set
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ assertEquals(builder.getFooMessage().getQuxInt(), 0);
+ builder.setFooMessage(
+ TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build());
+ assertTrue(builder.hasFooMessage());
+ assertEquals(builder.getFooMessage().getQuxInt(), 234);
+ TestOneof2 message = builder.buildPartial();
+ assertTrue(message.hasFooMessage());
+ assertEquals(message.getFooMessage().getQuxInt(), 234);
+
+ // clear
+ assertFalse(builder.clearFooMessage().hasFooString());
+ message = builder.build();
+ assertFalse(message.hasFooMessage());
+ assertEquals(message.getFooMessage().getQuxInt(), 0);
+
+ // nested builder
+ builder = TestOneof2.newBuilder();
+ assertSame(builder.getFooMessageOrBuilder(),
+ TestOneof2.NestedMessage.getDefaultInstance());
+ assertFalse(builder.hasFooMessage());
+ builder.getFooMessageBuilder().setQuxInt(123);
+ assertTrue(builder.hasFooMessage());
+ assertEquals(builder.getFooMessage().getQuxInt(), 123);
+ message = builder.build();
+ assertTrue(message.hasFooMessage());
+ assertEquals(message.getFooMessage().getQuxInt(), 123);
+ }
+
+ // LazyMessage is tested in LazyMessageLiteTest.java
+ }
+
+ public void testOneofMerge() throws Exception {
+ // Primitive Type
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestOneof2 message = builder.setFooInt(123).build();
+ TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+ assertTrue(message2.hasFooInt());
+ assertEquals(message2.getFooInt(), 123);
+ }
+
+ // String
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestOneof2 message = builder.setFooString("foo").build();
+ TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+ assertTrue(message2.hasFooString());
+ assertEquals(message2.getFooString(), "foo");
+ }
+
+ // Enum
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
+ TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+ assertTrue(message2.hasFooEnum());
+ assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+ }
+
+ // Message
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestOneof2 message = builder.setFooMessage(
+ TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
+ TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+ assertTrue(message2.hasFooMessage());
+ assertEquals(message2.getFooMessage().getQuxInt(), 234);
+ }
+ }
+
+ public void testOneofSerialization() throws Exception {
+ // Primitive Type
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestOneof2 message = builder.setFooInt(123).build();
+ ByteString serialized = message.toByteString();
+ TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+ assertTrue(message2.hasFooInt());
+ assertEquals(message2.getFooInt(), 123);
+ }
+
+ // String
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestOneof2 message = builder.setFooString("foo").build();
+ ByteString serialized = message.toByteString();
+ TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+ assertTrue(message2.hasFooString());
+ assertEquals(message2.getFooString(), "foo");
+ }
+
+ // Enum
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
+ ByteString serialized = message.toByteString();
+ TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+ assertTrue(message2.hasFooEnum());
+ assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+ }
+
+ // Message
+ {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestOneof2 message = builder.setFooMessage(
+ TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
+ ByteString serialized = message.toByteString();
+ TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+ assertTrue(message2.hasFooMessage());
+ assertEquals(message2.getFooMessage().getQuxInt(), 234);
+ }
+ }
+
+ public void testOneofNestedBuilderOnChangePropagation() {
+ NestedTestAllTypes.Builder parentBuilder = NestedTestAllTypes.newBuilder();
+ TestAllTypes.Builder builder = parentBuilder.getPayloadBuilder();
+ builder.getOneofNestedMessageBuilder();
+ assertTrue(builder.hasOneofNestedMessage());
+ assertTrue(parentBuilder.hasPayload());
+ NestedTestAllTypes message = parentBuilder.build();
+ assertTrue(message.hasPayload());
+ assertTrue(message.getPayload().hasOneofNestedMessage());
+ }
+
+ 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/IsValidUtf8Test.java b/java/src/test/java/com/google/protobuf/IsValidUtf8Test.java
new file mode 100644
index 00000000..89b64519
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/IsValidUtf8Test.java
@@ -0,0 +1,180 @@
+// 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.IsValidUtf8TestUtil.Shard;
+
+import junit.framework.TestCase;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Tests cases for {@link ByteString#isValidUtf8()}. This includes three
+ * brute force tests that actually test every permutation of one byte, two byte,
+ * and three byte sequences to ensure that the method produces the right result
+ * for every possible byte encoding where "right" means it's consistent with
+ * java's UTF-8 string encoding/decoding such that the method returns true for
+ * any sequence that will round trip when converted to a String and then back to
+ * bytes and will return false for any sequence that will not round trip.
+ * See also {@link IsValidUtf8FourByteTest}. It also includes some
+ * other more targeted tests.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ * @author martinrb@google.com (Martin Buchholz)
+ */
+public class IsValidUtf8Test extends TestCase {
+
+ /**
+ * Tests that round tripping of all two byte permutations work.
+ */
+ public void testIsValidUtf8_1Byte() throws UnsupportedEncodingException {
+ IsValidUtf8TestUtil.testBytes(1,
+ IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+ }
+
+ /**
+ * Tests that round tripping of all two byte permutations work.
+ */
+ public void testIsValidUtf8_2Bytes() throws UnsupportedEncodingException {
+ IsValidUtf8TestUtil.testBytes(2,
+ IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
+ }
+
+ /**
+ * Tests that round tripping of all three byte permutations work.
+ */
+ public void testIsValidUtf8_3Bytes() throws UnsupportedEncodingException {
+ IsValidUtf8TestUtil.testBytes(3,
+ IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+ }
+
+ /**
+ * Tests that round tripping of a sample of four byte permutations work.
+ * All permutations are prohibitively expensive to test for automated runs;
+ * {@link IsValidUtf8FourByteTest} is used for full coverage. This method
+ * tests specific four-byte cases.
+ */
+ public void testIsValidUtf8_4BytesSamples()
+ throws UnsupportedEncodingException {
+ // Valid 4 byte.
+ assertValidUtf8(0xF0, 0xA4, 0xAD, 0xA2);
+
+ // Bad trailing bytes
+ assertInvalidUtf8(0xF0, 0xA4, 0xAD, 0x7F);
+ assertInvalidUtf8(0xF0, 0xA4, 0xAD, 0xC0);
+
+ // Special cases for byte2
+ assertInvalidUtf8(0xF0, 0x8F, 0xAD, 0xA2);
+ assertInvalidUtf8(0xF4, 0x90, 0xAD, 0xA2);
+ }
+
+ /**
+ * Tests some hard-coded test cases.
+ */
+ public void testSomeSequences() {
+ // Empty
+ assertTrue(asBytes("").isValidUtf8());
+
+ // One-byte characters, including control characters
+ assertTrue(asBytes("\u0000abc\u007f").isValidUtf8());
+
+ // Two-byte characters
+ assertTrue(asBytes("\u00a2\u00a2").isValidUtf8());
+
+ // Three-byte characters
+ assertTrue(asBytes("\u020ac\u020ac").isValidUtf8());
+
+ // Four-byte characters
+ assertTrue(asBytes("\u024B62\u024B62").isValidUtf8());
+
+ // Mixed string
+ assertTrue(
+ asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62")
+ .isValidUtf8());
+
+ // Not a valid string
+ assertInvalidUtf8(-1, 0, -1, 0);
+ }
+
+ private byte[] toByteArray(int... bytes) {
+ byte[] realBytes = new byte[bytes.length];
+ for (int i = 0; i < bytes.length; i++) {
+ realBytes[i] = (byte) bytes[i];
+ }
+ return realBytes;
+ }
+
+ private ByteString toByteString(int... bytes) {
+ return ByteString.copyFrom(toByteArray(bytes));
+ }
+
+ private void assertValidUtf8(int[] bytes, boolean not) {
+ byte[] realBytes = toByteArray(bytes);
+ assertTrue(not ^ Utf8.isValidUtf8(realBytes));
+ assertTrue(not ^ Utf8.isValidUtf8(realBytes, 0, bytes.length));
+ ByteString lit = ByteString.copyFrom(realBytes);
+ ByteString sub = lit.substring(0, bytes.length);
+ assertTrue(not ^ lit.isValidUtf8());
+ assertTrue(not ^ sub.isValidUtf8());
+ ByteString[] ropes = {
+ RopeByteString.newInstanceForTest(ByteString.EMPTY, lit),
+ RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
+ RopeByteString.newInstanceForTest(lit, ByteString.EMPTY),
+ RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
+ RopeByteString.newInstanceForTest(sub, lit)
+ };
+ for (ByteString rope : ropes) {
+ assertTrue(not ^ rope.isValidUtf8());
+ }
+ }
+
+ private void assertValidUtf8(int... bytes) {
+ assertValidUtf8(bytes, false);
+ }
+
+ private void assertInvalidUtf8(int... bytes) {
+ assertValidUtf8(bytes, true);
+ }
+
+ private static ByteString asBytes(String s) {
+ return ByteString.copyFromUtf8(s);
+ }
+
+ public void testShardsHaveExpectedRoundTrippables() {
+ // A sanity check.
+ int actual = 0;
+ for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
+ actual += shard.expected;
+ }
+ assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT,
+ actual);
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
new file mode 100644
index 00000000..f41595ec
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
@@ -0,0 +1,421 @@
+// 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 static junit.framework.Assert.*;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.logging.Logger;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.Charset;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+/**
+ * Shared testing code for {@link IsValidUtf8Test} and
+ * {@link IsValidUtf8FourByteTest}.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ * @author martinrb@google.com (Martin Buchholz)
+ */
+class IsValidUtf8TestUtil {
+ private static Logger logger = Logger.getLogger(
+ IsValidUtf8TestUtil.class.getName());
+
+ // 128 - [chars 0x0000 to 0x007f]
+ static long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
+
+ // 128
+ static long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT =
+ ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+ // 1920 [chars 0x0080 to 0x07FF]
+ static long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1;
+
+ // 18,304
+ static long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
+ // Both bytes are one byte characters
+ (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2) +
+ // The possible number of two byte characters
+ TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+ // 2048
+ static long THREE_BYTE_SURROGATES = 2 * 1024;
+
+ // 61,440 [chars 0x0800 to 0xFFFF, minus surrogates]
+ static long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
+ 0xFFFF - 0x0800 + 1 - THREE_BYTE_SURROGATES;
+
+ // 2,650,112
+ static long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
+ // All one byte characters
+ (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3) +
+ // One two byte character and a one byte character
+ 2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
+ ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+ // Three byte characters
+ THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+ // 1,048,576 [chars 0x10000L to 0x10FFFF]
+ static long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1;
+
+ // 289,571,839
+ static long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT =
+ // All one byte characters
+ (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 4) +
+ // One and three byte characters
+ 2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
+ ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+ // Two two byte characters
+ TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+ // Permutations of one and two byte characters
+ 3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
+ ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
+ ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+ // Four byte characters
+ FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+ static class Shard {
+ final long index;
+ final long start;
+ final long lim;
+ final long expected;
+
+
+ public Shard(long index, long start, long lim, long expected) {
+ assertTrue(start < lim);
+ this.index = index;
+ this.start = start;
+ this.lim = lim;
+ this.expected = expected;
+ }
+ }
+
+ static final long[] FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES =
+ generateFourByteShardsExpectedRunnables();
+
+ private static long[] generateFourByteShardsExpectedRunnables() {
+ long[] expected = new long[128];
+
+ // 0-63 are all 5300224
+ for (int i = 0; i <= 63; i++) {
+ expected[i] = 5300224;
+ }
+
+ // 97-111 are all 2342912
+ for (int i = 97; i <= 111; i++) {
+ expected[i] = 2342912;
+ }
+
+ // 113-117 are all 1048576
+ for (int i = 113; i <= 117; i++) {
+ expected[i] = 1048576;
+ }
+
+ // One offs
+ expected[112] = 786432;
+ expected[118] = 786432;
+ expected[119] = 1048576;
+ expected[120] = 458752;
+ expected[121] = 524288;
+ expected[122] = 65536;
+
+ // Anything not assigned was the default 0.
+ return expected;
+ }
+
+ static final List<Shard> FOUR_BYTE_SHARDS = generateFourByteShards(
+ 128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
+
+
+ private static List<Shard> generateFourByteShards(
+ int numShards, long[] expected) {
+ assertEquals(numShards, expected.length);
+ List<Shard> shards = new ArrayList<Shard>(numShards);
+ long LIM = 1L << 32;
+ long increment = LIM / numShards;
+ assertTrue(LIM % numShards == 0);
+ for (int i = 0; i < numShards; i++) {
+ shards.add(new Shard(i,
+ increment * i,
+ increment * (i + 1),
+ expected[i]));
+ }
+ return shards;
+ }
+
+ /**
+ * Helper to run the loop to test all the permutations for the number of bytes
+ * specified.
+ *
+ * @param numBytes the number of bytes in the byte array
+ * @param expectedCount the expected number of roundtrippable permutations
+ */
+ static void testBytes(int numBytes, long expectedCount)
+ throws UnsupportedEncodingException {
+ testBytes(numBytes, expectedCount, 0, -1);
+ }
+
+ /**
+ * Helper to run the loop to test all the permutations for the number of bytes
+ * specified. This overload is useful for debugging to get the loop to start
+ * at a certain character.
+ *
+ * @param numBytes the number of bytes in the byte array
+ * @param expectedCount the expected number of roundtrippable permutations
+ * @param start the starting bytes encoded as a long as big-endian
+ * @param lim the limit of bytes to process encoded as a long as big-endian,
+ * or -1 to mean the max limit for numBytes
+ */
+ static void testBytes(int numBytes, long expectedCount, long start, long lim)
+ throws UnsupportedEncodingException {
+ Random rnd = new Random();
+ byte[] bytes = new byte[numBytes];
+
+ if (lim == -1) {
+ lim = 1L << (numBytes * 8);
+ }
+ long count = 0;
+ long countRoundTripped = 0;
+ for (long byteChar = start; byteChar < lim; byteChar++) {
+ long tmpByteChar = byteChar;
+ for (int i = 0; i < numBytes; i++) {
+ bytes[bytes.length - i - 1] = (byte) tmpByteChar;
+ tmpByteChar = tmpByteChar >> 8;
+ }
+ ByteString bs = ByteString.copyFrom(bytes);
+ boolean isRoundTrippable = bs.isValidUtf8();
+ String s = new String(bytes, "UTF-8");
+ byte[] bytesReencoded = s.getBytes("UTF-8");
+ boolean bytesEqual = Arrays.equals(bytes, bytesReencoded);
+
+ if (bytesEqual != isRoundTrippable) {
+ outputFailure(byteChar, bytes, bytesReencoded);
+ }
+
+ // Check agreement with static Utf8 methods.
+ assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes));
+ assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes, 0, numBytes));
+
+ // Test partial sequences.
+ // Partition numBytes into three segments (not necessarily non-empty).
+ int i = rnd.nextInt(numBytes);
+ int j = rnd.nextInt(numBytes);
+ if (j < i) {
+ int tmp = i; i = j; j = tmp;
+ }
+ int state1 = Utf8.partialIsValidUtf8(Utf8.COMPLETE, bytes, 0, i);
+ int state2 = Utf8.partialIsValidUtf8(state1, bytes, i, j);
+ int state3 = Utf8.partialIsValidUtf8(state2, bytes, j, numBytes);
+ if (isRoundTrippable != (state3 == Utf8.COMPLETE)) {
+ System.out.printf("state=%04x %04x %04x i=%d j=%d%n",
+ state1, state2, state3, i, j);
+ outputFailure(byteChar, bytes, bytesReencoded);
+ }
+ assertEquals(isRoundTrippable, (state3 == Utf8.COMPLETE));
+
+ // Test ropes built out of small partial sequences
+ ByteString rope = RopeByteString.newInstanceForTest(
+ bs.substring(0, i),
+ RopeByteString.newInstanceForTest(
+ bs.substring(i, j),
+ bs.substring(j, numBytes)));
+ assertSame(RopeByteString.class, rope.getClass());
+
+ ByteString[] byteStrings = { bs, bs.substring(0, numBytes), rope };
+ for (ByteString x : byteStrings) {
+ assertEquals(isRoundTrippable,
+ x.isValidUtf8());
+ assertEquals(state3,
+ x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes));
+
+ assertEquals(state1,
+ x.partialIsValidUtf8(Utf8.COMPLETE, 0, i));
+ assertEquals(state1,
+ x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i));
+ assertEquals(state2,
+ x.partialIsValidUtf8(state1, i, j - i));
+ assertEquals(state2,
+ x.substring(i, j).partialIsValidUtf8(state1, 0, j - i));
+ assertEquals(state3,
+ x.partialIsValidUtf8(state2, j, numBytes - j));
+ assertEquals(state3,
+ x.substring(j, numBytes)
+ .partialIsValidUtf8(state2, 0, numBytes - j));
+ }
+
+ // ByteString reduplication should not affect its UTF-8 validity.
+ ByteString ropeADope =
+ RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
+ assertEquals(isRoundTrippable, ropeADope.isValidUtf8());
+
+ if (isRoundTrippable) {
+ countRoundTripped++;
+ }
+ count++;
+ if (byteChar != 0 && byteChar % 1000000L == 0) {
+ logger.info("Processed " + (byteChar / 1000000L) +
+ " million characters");
+ }
+ }
+ logger.info("Round tripped " + countRoundTripped + " of " + count);
+ assertEquals(expectedCount, countRoundTripped);
+ }
+
+ /**
+ * Variation of {@link #testBytes} that does less allocation using the
+ * low-level encoders/decoders directly. Checked in because it's useful for
+ * debugging when trying to process bytes faster, but since it doesn't use the
+ * actual String class, it's possible for incompatibilities to develop
+ * (although unlikely).
+ *
+ * @param numBytes the number of bytes in the byte array
+ * @param expectedCount the expected number of roundtrippable permutations
+ * @param start the starting bytes encoded as a long as big-endian
+ * @param lim the limit of bytes to process encoded as a long as big-endian,
+ * or -1 to mean the max limit for numBytes
+ */
+ void testBytesUsingByteBuffers(
+ int numBytes, long expectedCount, long start, long lim)
+ throws UnsupportedEncodingException {
+ CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ byte[] bytes = new byte[numBytes];
+ int maxChars = (int) (decoder.maxCharsPerByte() * numBytes) + 1;
+ char[] charsDecoded =
+ new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1];
+ int maxBytes = (int) (encoder.maxBytesPerChar() * maxChars) + 1;
+ byte[] bytesReencoded = new byte[maxBytes];
+
+ ByteBuffer bb = ByteBuffer.wrap(bytes);
+ CharBuffer cb = CharBuffer.wrap(charsDecoded);
+ ByteBuffer bbReencoded = ByteBuffer.wrap(bytesReencoded);
+ if (lim == -1) {
+ lim = 1L << (numBytes * 8);
+ }
+ long count = 0;
+ long countRoundTripped = 0;
+ for (long byteChar = start; byteChar < lim; byteChar++) {
+ bb.rewind();
+ bb.limit(bytes.length);
+ cb.rewind();
+ cb.limit(charsDecoded.length);
+ bbReencoded.rewind();
+ bbReencoded.limit(bytesReencoded.length);
+ encoder.reset();
+ decoder.reset();
+ long tmpByteChar = byteChar;
+ for (int i = 0; i < bytes.length; i++) {
+ bytes[bytes.length - i - 1] = (byte) tmpByteChar;
+ tmpByteChar = tmpByteChar >> 8;
+ }
+ boolean isRoundTrippable = ByteString.copyFrom(bytes).isValidUtf8();
+ CoderResult result = decoder.decode(bb, cb, true);
+ assertFalse(result.isError());
+ result = decoder.flush(cb);
+ assertFalse(result.isError());
+
+ int charLen = cb.position();
+ cb.rewind();
+ cb.limit(charLen);
+ result = encoder.encode(cb, bbReencoded, true);
+ assertFalse(result.isError());
+ result = encoder.flush(bbReencoded);
+ assertFalse(result.isError());
+
+ boolean bytesEqual = true;
+ int bytesLen = bbReencoded.position();
+ if (bytesLen != numBytes) {
+ bytesEqual = false;
+ } else {
+ for (int i = 0; i < numBytes; i++) {
+ if (bytes[i] != bytesReencoded[i]) {
+ bytesEqual = false;
+ break;
+ }
+ }
+ }
+ if (bytesEqual != isRoundTrippable) {
+ outputFailure(byteChar, bytes, bytesReencoded, bytesLen);
+ }
+
+ count++;
+ if (isRoundTrippable) {
+ countRoundTripped++;
+ }
+ if (byteChar != 0 && byteChar % 1000000 == 0) {
+ logger.info("Processed " + (byteChar / 1000000) +
+ " million characters");
+ }
+ }
+ logger.info("Round tripped " + countRoundTripped + " of " + count);
+ assertEquals(expectedCount, countRoundTripped);
+ }
+
+ private static void outputFailure(long byteChar, byte[] bytes, byte[] after) {
+ outputFailure(byteChar, bytes, after, after.length);
+ }
+
+ private static void outputFailure(long byteChar, byte[] bytes, byte[] after,
+ int len) {
+ fail("Failure: (" + Long.toHexString(byteChar) + ") " +
+ toHexString(bytes) + " => " + toHexString(after, len));
+ }
+
+ private static String toHexString(byte[] b) {
+ return toHexString(b, b.length);
+ }
+
+ private static String toHexString(byte[] b, int len) {
+ StringBuilder s = new StringBuilder();
+ s.append("\"");
+ for (int i = 0; i < len; i++) {
+ if (i > 0) {
+ s.append(" ");
+ }
+ s.append(String.format("%02x", b[i] & 0xFF));
+ }
+ s.append("\"");
+ return s.toString();
+ }
+
+}
diff --git a/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
new file mode 100644
index 00000000..211b5697
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
@@ -0,0 +1,271 @@
+// 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 static protobuf_unittest.UnittestProto.optionalInt32Extension;
+import static protobuf_unittest.UnittestProto.optionalInt64Extension;
+
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import java.io.IOException;
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link LazyFieldLite}.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyFieldLiteTest extends TestCase {
+
+ public void testGetValue() {
+ MessageLite message = TestUtil.getAllSet();
+ LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+ assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+ changeValue(lazyField);
+ assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+ }
+
+ public void testGetValueEx() throws Exception {
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+ assertEquals(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+ changeValue(lazyField);
+ assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+ }
+
+ public void testSetValue() {
+ MessageLite message = TestUtil.getAllSet();
+ LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+ changeValue(lazyField);
+ assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+ message = lazyField.getValue(TestAllTypes.getDefaultInstance());
+ changeValue(lazyField);
+ assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+ }
+
+ public void testSetValueEx() throws Exception {
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+ changeValue(lazyField);
+ assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+ MessageLite value = lazyField.getValue(TestAllExtensions.getDefaultInstance());
+ changeValue(lazyField);
+ assertEquals(value, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+ }
+
+ public void testGetSerializedSize() {
+ MessageLite message = TestUtil.getAllSet();
+ LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+ assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
+ changeValue(lazyField);
+ assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
+ }
+
+ public void testGetSerializedSizeEx() throws Exception {
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+ assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
+ changeValue(lazyField);
+ assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
+ }
+
+ public void testGetByteString() {
+ MessageLite message = TestUtil.getAllSet();
+ LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+ assertEquals(message.toByteString(), lazyField.toByteString());
+ changeValue(lazyField);
+ assertNotEqual(message.toByteString(), lazyField.toByteString());
+ }
+
+ public void testGetByteStringEx() throws Exception {
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+ assertEquals(message.toByteString(), lazyField.toByteString());
+ changeValue(lazyField);
+ assertNotEqual(message.toByteString(), lazyField.toByteString());
+ }
+
+ public void testMergeExtensions() throws Exception {
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ LazyFieldLite original = createLazyFieldLiteFromMessage(message);
+ LazyFieldLite merged = new LazyFieldLite();
+ merged.merge(original);
+ TestAllExtensions value = (TestAllExtensions) merged.getValue(
+ TestAllExtensions.getDefaultInstance());
+ assertEquals(message, value);
+ }
+
+ public void testEmptyLazyField() throws Exception {
+ LazyFieldLite field = new LazyFieldLite();
+ assertEquals(0, field.getSerializedSize());
+ assertEquals(ByteString.EMPTY, field.toByteString());
+ }
+
+ public void testInvalidProto() throws Exception {
+ // Silently fails and uses the default instance.
+ LazyFieldLite field = new LazyFieldLite(
+ TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+ assertEquals(
+ TestAllTypes.getDefaultInstance(), field.getValue(TestAllTypes.getDefaultInstance()));
+ assertEquals(0, field.getSerializedSize());
+ assertEquals(ByteString.EMPTY, field.toByteString());
+ }
+
+ public void testMergeBeforeParsing() throws Exception {
+ TestAllTypes message1 = TestAllTypes.newBuilder().setOptionalInt32(1).build();
+ LazyFieldLite field1 = createLazyFieldLiteFromMessage(message1);
+ TestAllTypes message2 = TestAllTypes.newBuilder().setOptionalInt64(2).build();
+ LazyFieldLite field2 = createLazyFieldLiteFromMessage(message2);
+
+ field1.merge(field2);
+ TestAllTypes expected =
+ TestAllTypes.newBuilder().setOptionalInt32(1).setOptionalInt64(2).build();
+ assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+ }
+
+ public void testMergeOneNotParsed() throws Exception {
+ // Test a few different paths that involve one message that was not parsed.
+ TestAllTypes message1 = TestAllTypes.newBuilder().setOptionalInt32(1).build();
+ TestAllTypes message2 = TestAllTypes.newBuilder().setOptionalInt64(2).build();
+ TestAllTypes expected =
+ TestAllTypes.newBuilder().setOptionalInt32(1).setOptionalInt64(2).build();
+
+ LazyFieldLite field1 = LazyFieldLite.fromValue(message1);
+ field1.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
+ LazyFieldLite field2 = createLazyFieldLiteFromMessage(message2);
+ field1.merge(field2);
+ assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+
+ // Now reverse which one is parsed first.
+ field1 = LazyFieldLite.fromValue(message1);
+ field2 = createLazyFieldLiteFromMessage(message2);
+ field2.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
+ field1.merge(field2);
+ assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+ }
+
+ public void testMergeInvalid() throws Exception {
+ // Test a few different paths that involve one message that was not parsed.
+ TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(1).build();
+ LazyFieldLite valid = LazyFieldLite.fromValue(message);
+ LazyFieldLite invalid = new LazyFieldLite(
+ TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+ invalid.merge(valid);
+
+ // We swallow the exception and just use the set field.
+ assertEquals(message, invalid.getValue(TestAllTypes.getDefaultInstance()));
+ }
+
+ public void testMergeKeepsExtensionsWhenPossible() throws Exception {
+ // In this test we attempt to only use the empty registry, which will strip out all extensions
+ // when serializing and then parsing. We verify that each code path will attempt to not
+ // serialize and parse a message that was set directly without going through the
+ // extensionRegistry.
+ TestAllExtensions messageWithExtensions =
+ TestAllExtensions.newBuilder().setExtension(optionalInt32Extension, 42).build();
+ TestAllExtensions emptyMessage = TestAllExtensions.newBuilder().build();
+
+ ExtensionRegistryLite emptyRegistry = ExtensionRegistryLite.getEmptyRegistry();
+
+ LazyFieldLite field = LazyFieldLite.fromValue(messageWithExtensions);
+ field.merge(createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage));
+ assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+
+ // Now reverse the order of the merging.
+ field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
+ field.merge(LazyFieldLite.fromValue(messageWithExtensions));
+ assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+
+ // Now try parsing the empty field first.
+ field = LazyFieldLite.fromValue(messageWithExtensions);
+ LazyFieldLite other = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
+ other.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
+ field.merge(other);
+ assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+
+ // And again reverse.
+ field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
+ field.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
+ other = LazyFieldLite.fromValue(messageWithExtensions);
+ field.merge(other);
+ assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+ }
+
+ public void testMergeMightLoseExtensions() throws Exception {
+ // Test that we don't know about the extensions when parsing.
+ TestAllExtensions message1 =
+ TestAllExtensions.newBuilder().setExtension(optionalInt32Extension, 1).build();
+ TestAllExtensions message2 =
+ TestAllExtensions.newBuilder().setExtension(optionalInt64Extension, 2L).build();
+
+ LazyFieldLite field = LazyFieldLite.fromValue(message1);
+ field.merge(LazyFieldLite.fromValue(message2));
+
+ // We lose the extensions from message 2 because we have to serialize it and then parse it
+ // again, using the empty registry this time.
+ TestAllExtensions value =
+ (TestAllExtensions) field.getValue(TestAllExtensions.getDefaultInstance());
+ assertTrue(value.hasExtension(optionalInt32Extension));
+ assertEquals(Integer.valueOf(1), value.getExtension(optionalInt32Extension));
+ assertFalse(value.hasExtension(optionalInt64Extension));
+
+ // The field is still there, it is just unknown.
+ assertTrue(value.getUnknownFields()
+ .hasField(optionalInt64Extension.getDescriptor().getNumber()));
+ }
+
+
+ // Help methods.
+
+ private LazyFieldLite createLazyFieldLiteFromMessage(MessageLite message) {
+ return createLazyFieldLiteFromMessage(TestUtil.getExtensionRegistry(), message);
+ }
+
+ private LazyFieldLite createLazyFieldLiteFromMessage(
+ ExtensionRegistryLite extensionRegistry, MessageLite message) {
+ ByteString bytes = message.toByteString();
+ return new LazyFieldLite(extensionRegistry, bytes);
+ }
+
+ private void changeValue(LazyFieldLite lazyField) {
+ TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder();
+ builder.addRepeatedBool(true);
+ MessageLite newMessage = builder.build();
+ lazyField.setValue(newMessage);
+ }
+
+ private void assertNotEqual(Object unexpected, Object actual) {
+ assertFalse(unexpected == actual
+ || (unexpected != null && unexpected.equals(actual)));
+ }
+
+}
diff --git a/java/src/test/java/com/google/protobuf/LazyFieldTest.java b/java/src/test/java/com/google/protobuf/LazyFieldTest.java
new file mode 100644
index 00000000..2b900065
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/LazyFieldTest.java
@@ -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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import java.io.IOException;
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link LazyField}.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyFieldTest extends TestCase {
+ public void testHashCode() {
+ MessageLite message = TestUtil.getAllSet();
+ LazyField lazyField =
+ createLazyFieldFromMessage(message);
+ assertEquals(message.hashCode(), lazyField.hashCode());
+ lazyField.getValue();
+ assertEquals(message.hashCode(), lazyField.hashCode());
+ changeValue(lazyField);
+ // make sure two messages have different hash code
+ assertNotEqual(message.hashCode(), lazyField.hashCode());
+ }
+
+ public void testHashCodeEx() throws Exception {
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ LazyField lazyField = createLazyFieldFromMessage(message);
+ assertEquals(message.hashCode(), lazyField.hashCode());
+ lazyField.getValue();
+ assertEquals(message.hashCode(), lazyField.hashCode());
+ changeValue(lazyField);
+ // make sure two messages have different hash code
+ assertNotEqual(message.hashCode(), lazyField.hashCode());
+ }
+
+ public void testGetValue() {
+ MessageLite message = TestUtil.getAllSet();
+ LazyField lazyField = createLazyFieldFromMessage(message);
+ assertEquals(message, lazyField.getValue());
+ changeValue(lazyField);
+ assertNotEqual(message, lazyField.getValue());
+ }
+
+ public void testGetValueEx() throws Exception {
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ LazyField lazyField = createLazyFieldFromMessage(message);
+ assertEquals(message, lazyField.getValue());
+ changeValue(lazyField);
+ assertNotEqual(message, lazyField.getValue());
+ }
+
+ public void testEqualsObject() {
+ MessageLite message = TestUtil.getAllSet();
+ LazyField lazyField = createLazyFieldFromMessage(message);
+ assertTrue(lazyField.equals(message));
+ changeValue(lazyField);
+ assertFalse(lazyField.equals(message));
+ assertFalse(message.equals(lazyField.getValue()));
+ }
+
+ public void testEqualsObjectEx() throws Exception {
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ LazyField lazyField = createLazyFieldFromMessage(message);
+ assertTrue(lazyField.equals(message));
+ changeValue(lazyField);
+ assertFalse(lazyField.equals(message));
+ assertFalse(message.equals(lazyField.getValue()));
+ }
+
+ // Help methods.
+
+ private LazyField createLazyFieldFromMessage(MessageLite message) {
+ ByteString bytes = message.toByteString();
+ return new LazyField(message.getDefaultInstanceForType(),
+ TestUtil.getExtensionRegistry(), bytes);
+ }
+
+ private void changeValue(LazyField lazyField) {
+ TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder();
+ builder.addRepeatedBool(true);
+ MessageLite newMessage = builder.build();
+ lazyField.setValue(newMessage);
+ }
+
+ private void assertNotEqual(Object unexpected, Object actual) {
+ assertFalse(unexpected == actual
+ || (unexpected != null && unexpected.equals(actual)));
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
new file mode 100644
index 00000000..afe0fffd
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
@@ -0,0 +1,307 @@
+// 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.LazyFieldsLite.LazyExtension;
+import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite;
+import protobuf_unittest.LazyFieldsLite.LazyMessageLite;
+import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+
+/**
+ * Unit test for messages with lazy fields.
+ *
+ * @author niwasaki@google.com (Naoki Iwasaki)
+ */
+public class LazyMessageLiteTest extends TestCase {
+
+ private Parser<LazyInnerMessageLite> originalLazyInnerMessageLiteParser;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testSetValues() {
+ LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
+ .setNum(3)
+ .build();
+ LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+ .setNum(2)
+ .setNested(nested)
+ .build();
+ LazyMessageLite outer = LazyMessageLite.newBuilder()
+ .setNum(1)
+ .setInner(inner)
+ .setOneofNum(123)
+ .setOneofInner(inner)
+ .build();
+
+ assertEquals(1, outer.getNum());
+ assertEquals(421, outer.getNumWithDefault());
+
+ assertEquals(2, outer.getInner().getNum());
+ assertEquals(42, outer.getInner().getNumWithDefault());
+
+ assertEquals(3, outer.getInner().getNested().getNum());
+ assertEquals(4, outer.getInner().getNested().getNumWithDefault());
+
+ assertFalse(outer.hasOneofNum());
+ assertTrue(outer.hasOneofInner());
+
+ assertEquals(2, outer.getOneofInner().getNum());
+ assertEquals(42, outer.getOneofInner().getNumWithDefault());
+ assertEquals(3, outer.getOneofInner().getNested().getNum());
+ assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
+ }
+
+ public void testSetRepeatedValues() {
+ LazyMessageLite outer = LazyMessageLite.newBuilder()
+ .setNum(1)
+ .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
+ .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
+ .build();
+
+ assertEquals(1, outer.getNum());
+ assertEquals(2, outer.getRepeatedInnerCount());
+ assertEquals(119, outer.getRepeatedInner(0).getNum());
+ assertEquals(122, outer.getRepeatedInner(1).getNum());
+ }
+
+ public void testAddAll() {
+ ArrayList<LazyInnerMessageLite> inners = new ArrayList<LazyInnerMessageLite>();
+ int count = 4;
+ for (int i = 0; i < count; i++) {
+ LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+ .setNum(i)
+ .build();
+ inners.add(inner);
+ }
+
+ LazyMessageLite outer = LazyMessageLite.newBuilder()
+ .addAllRepeatedInner(inners)
+ .build();
+ assertEquals(count, outer.getRepeatedInnerCount());
+ for (int i = 0; i < count; i++) {
+ assertEquals(i, outer.getRepeatedInner(i).getNum());
+ }
+ }
+
+ public void testGetDefaultValues() {
+ LazyMessageLite outer = LazyMessageLite.newBuilder()
+ .build();
+
+ assertEquals(0, outer.getNum());
+ assertEquals(421, outer.getNumWithDefault());
+
+ assertEquals(0, outer.getInner().getNum());
+ assertEquals(42, outer.getInner().getNumWithDefault());
+
+ assertEquals(0, outer.getInner().getNested().getNum());
+ assertEquals(4, outer.getInner().getNested().getNumWithDefault());
+
+ assertEquals(0, outer.getOneofNum());
+
+ assertEquals(0, outer.getOneofInner().getNum());
+ assertEquals(42, outer.getOneofInner().getNumWithDefault());
+ assertEquals(0, outer.getOneofInner().getNested().getNum());
+ assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
+ }
+
+ public void testClearValues() {
+ LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+ .setNum(115)
+ .build();
+
+ LazyMessageLite.Builder outerBuilder = LazyMessageLite.newBuilder();
+
+ assertEquals(0, outerBuilder.build().getNum());
+
+
+ // Set/Clear num
+ outerBuilder.setNum(100);
+
+ assertEquals(100, outerBuilder.build().getNum());
+ assertEquals(421, outerBuilder.build().getNumWithDefault());
+ assertFalse(outerBuilder.build().hasInner());
+
+ outerBuilder.clearNum();
+
+ assertEquals(0, outerBuilder.build().getNum());
+ assertEquals(421, outerBuilder.build().getNumWithDefault());
+ assertFalse(outerBuilder.build().hasInner());
+
+
+ // Set/Clear all
+ outerBuilder.setNum(100)
+ .setInner(inner)
+ .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
+ .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
+ .setOneofInner(LazyInnerMessageLite.newBuilder().setNum(123));
+
+ LazyMessageLite outer = outerBuilder.build();
+ assertEquals(100, outer.getNum());
+ assertEquals(421, outer.getNumWithDefault());
+ assertTrue(outer.hasInner());
+ assertEquals(115, outer.getInner().getNum());
+ assertEquals(2, outer.getRepeatedInnerCount());
+ assertEquals(119, outer.getRepeatedInner(0).getNum());
+ assertEquals(122, outer.getRepeatedInner(1).getNum());
+ assertTrue(outer.hasOneofInner());
+ assertEquals(123, outer.getOneofInner().getNum());
+
+ outerBuilder.clear();
+
+ outer = outerBuilder.build();
+
+ assertEquals(0, outer.getNum());
+ assertEquals(421, outer.getNumWithDefault());
+ assertFalse(outer.hasInner());
+ assertEquals(0, outer.getRepeatedInnerCount());
+ assertFalse(outer.hasOneofInner());
+ assertEquals(0, outer.getOneofInner().getNum());
+ }
+
+ public void testMergeValues() {
+ LazyMessageLite outerBase = LazyMessageLite.newBuilder()
+ .setNumWithDefault(122)
+ .build();
+
+ LazyInnerMessageLite innerMerging = LazyInnerMessageLite.newBuilder()
+ .setNum(115)
+ .build();
+ LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
+ .setNum(119)
+ .setInner(innerMerging)
+ .setOneofInner(innerMerging)
+ .build();
+
+ LazyMessageLite merged = LazyMessageLite
+ .newBuilder(outerBase)
+ .mergeFrom(outerMerging)
+ .build();
+ assertEquals(119, merged.getNum());
+ assertEquals(122, merged.getNumWithDefault());
+ assertEquals(115, merged.getInner().getNum());
+ assertEquals(42, merged.getInner().getNumWithDefault());
+ assertEquals(115, merged.getOneofInner().getNum());
+ assertEquals(42, merged.getOneofInner().getNumWithDefault());
+ }
+
+ public void testMergeDefaultValues() {
+ LazyInnerMessageLite innerBase = LazyInnerMessageLite.newBuilder()
+ .setNum(115)
+ .build();
+ LazyMessageLite outerBase = LazyMessageLite.newBuilder()
+ .setNum(119)
+ .setNumWithDefault(122)
+ .setInner(innerBase)
+ .setOneofInner(innerBase)
+ .build();
+
+ LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
+ .build();
+
+ LazyMessageLite merged = LazyMessageLite
+ .newBuilder(outerBase)
+ .mergeFrom(outerMerging)
+ .build();
+ // Merging default-instance shouldn't overwrite values in the base message.
+ assertEquals(119, merged.getNum());
+ assertEquals(122, merged.getNumWithDefault());
+ assertEquals(115, merged.getInner().getNum());
+ assertEquals(42, merged.getInner().getNumWithDefault());
+ assertEquals(115, merged.getOneofInner().getNum());
+ assertEquals(42, merged.getOneofInner().getNumWithDefault());
+ }
+
+ public void testSerialize() throws InvalidProtocolBufferException {
+ LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
+ .setNum(3)
+ .build();
+ LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+ .setNum(2)
+ .setNested(nested)
+ .build();
+ LazyMessageLite outer = LazyMessageLite.newBuilder()
+ .setNum(1)
+ .setInner(inner)
+ .setOneofInner(inner)
+ .build();
+
+ ByteString bytes = outer.toByteString();
+ assertEquals(bytes.size(), outer.getSerializedSize());
+
+ LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes);
+
+ assertEquals(1, deserialized.getNum());
+ assertEquals(421, deserialized.getNumWithDefault());
+
+ assertEquals(2, deserialized.getInner().getNum());
+ assertEquals(42, deserialized.getInner().getNumWithDefault());
+
+ assertEquals(3, deserialized.getInner().getNested().getNum());
+ assertEquals(4, deserialized.getInner().getNested().getNumWithDefault());
+
+ assertEquals(2, deserialized.getOneofInner().getNum());
+ assertEquals(42, deserialized.getOneofInner().getNumWithDefault());
+ assertEquals(3, deserialized.getOneofInner().getNested().getNum());
+ assertEquals(4, deserialized.getOneofInner().getNested().getNumWithDefault());
+
+ assertEquals(bytes, deserialized.toByteString());
+ }
+
+ public void testExtensions() throws Exception {
+ LazyInnerMessageLite.Builder innerBuilder = LazyInnerMessageLite.newBuilder();
+ innerBuilder.setExtension(
+ LazyExtension.extension, LazyExtension.newBuilder()
+ .setName("name").build());
+ assertTrue(innerBuilder.hasExtension(LazyExtension.extension));
+ assertEquals("name", innerBuilder.getExtension(LazyExtension.extension).getName());
+
+ LazyInnerMessageLite innerMessage = innerBuilder.build();
+ assertTrue(innerMessage.hasExtension(LazyExtension.extension));
+ assertEquals("name", innerMessage.getExtension(LazyExtension.extension).getName());
+
+ LazyMessageLite lite = LazyMessageLite.newBuilder()
+ .setInner(innerMessage).build();
+ assertTrue(lite.getInner().hasExtension(LazyExtension.extension));
+ assertEquals("name", lite.getInner().getExtension(LazyExtension.extension).getName());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
index 4dcdc74d..f3012b96 100644
--- a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
+++ b/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,6 +32,9 @@ package com.google.protobuf;
import junit.framework.TestCase;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Tests for {@link LazyStringArrayList}.
*
@@ -64,6 +67,14 @@ public class LazyStringArrayListTest extends TestCase {
list.remove(1);
assertSame(STRING_A, list.get(0));
assertSame(STRING_C, list.get(1));
+
+ List<ByteString> byteStringList = list.asByteStringList();
+ assertEquals(BYTE_STRING_A, byteStringList.get(0));
+ assertEquals(BYTE_STRING_C, byteStringList.get(1));
+
+ // Underlying list should be transformed.
+ assertSame(byteStringList.get(0), list.getByteString(0));
+ assertSame(byteStringList.get(1), list.getByteString(1));
}
public void testJustByteString() {
@@ -80,6 +91,10 @@ public class LazyStringArrayListTest extends TestCase {
list.remove(1);
assertSame(BYTE_STRING_A, list.getByteString(0));
assertSame(BYTE_STRING_C, list.getByteString(1));
+
+ List<ByteString> byteStringList = list.asByteStringList();
+ assertSame(BYTE_STRING_A, byteStringList.get(0));
+ assertSame(BYTE_STRING_C, byteStringList.get(1));
}
public void testConversionBackAndForth() {
@@ -115,4 +130,45 @@ public class LazyStringArrayListTest extends TestCase {
assertSame(aPrimeByteString, list.getByteString(0));
assertSame(bPrimeByteString, list.getByteString(1));
}
+
+ public void testCopyConstructorCopiesByReference() {
+ LazyStringArrayList list1 = new LazyStringArrayList();
+ list1.add(STRING_A);
+ list1.add(BYTE_STRING_B);
+ list1.add(BYTE_STRING_C);
+
+ LazyStringArrayList list2 = new LazyStringArrayList(list1);
+ assertEquals(3, list2.size());
+ assertSame(STRING_A, list2.get(0));
+ assertSame(BYTE_STRING_B, list2.getByteString(1));
+ assertSame(BYTE_STRING_C, list2.getByteString(2));
+ }
+
+ public void testListCopyConstructor() {
+ List<String> list1 = new ArrayList<String>();
+ list1.add(STRING_A);
+ list1.add(STRING_B);
+ list1.add(STRING_C);
+
+ LazyStringArrayList list2 = new LazyStringArrayList(list1);
+ assertEquals(3, list2.size());
+ assertSame(STRING_A, list2.get(0));
+ assertSame(STRING_B, list2.get(1));
+ assertSame(STRING_C, list2.get(2));
+ }
+
+ public void testAddAllCopiesByReferenceIfPossible() {
+ LazyStringArrayList list1 = new LazyStringArrayList();
+ list1.add(STRING_A);
+ list1.add(BYTE_STRING_B);
+ list1.add(BYTE_STRING_C);
+
+ LazyStringArrayList list2 = new LazyStringArrayList();
+ list2.addAll(list1);
+
+ assertEquals(3, list2.size());
+ assertSame(STRING_A, list2.get(0));
+ assertSame(BYTE_STRING_B, list2.getByteString(1));
+ assertSame(BYTE_STRING_C, list2.getByteString(2));
+ }
}
diff --git a/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java b/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
index e6870b51..acd18003 100644
--- a/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
+++ b/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -50,6 +50,19 @@ public class LazyStringEndToEndTest extends TestCase {
114, 4, -1, 0, -1, 0, -30, 2, 4, -1,
0, -1, 0, -30, 2, 4, -1, 0, -1, 0, });
+ private ByteString encodedTestAllTypes;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.encodedTestAllTypes = UnittestProto.TestAllTypes.newBuilder()
+ .setOptionalString("foo")
+ .addRepeatedString("bar")
+ .addRepeatedString("baz")
+ .build()
+ .toByteString();
+ }
+
/**
* Tests that an invalid UTF8 string will roundtrip through a parse
* and serialization.
@@ -112,4 +125,19 @@ public class LazyStringEndToEndTest extends TestCase {
assertSame(bPrime, proto.getRepeatedString(0));
assertSame(cPrime, proto.getRepeatedString(1));
}
+
+ public void testNoStringCachingIfOnlyBytesAccessed() throws Exception {
+ UnittestProto.TestAllTypes proto =
+ UnittestProto.TestAllTypes.parseFrom(encodedTestAllTypes);
+ ByteString optional = proto.getOptionalStringBytes();
+ assertSame(optional, proto.getOptionalStringBytes());
+ assertSame(optional, proto.toBuilder().getOptionalStringBytes());
+
+ ByteString repeated0 = proto.getRepeatedStringBytes(0);
+ ByteString repeated1 = proto.getRepeatedStringBytes(1);
+ assertSame(repeated0, proto.getRepeatedStringBytes(0));
+ assertSame(repeated1, proto.getRepeatedStringBytes(1));
+ assertSame(repeated0, proto.toBuilder().getRepeatedStringBytes(0));
+ assertSame(repeated1, proto.toBuilder().getRepeatedStringBytes(1));
+ }
}
diff --git a/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
new file mode 100644
index 00000000..035917c8
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
@@ -0,0 +1,108 @@
+// 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.Bar;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
+
+import junit.framework.TestCase;
+
+/**
+ * Test generate equal and hash methods for the lite runtime.
+ *
+ * @author pbogle@google.com Phil Bogle
+ */
+public class LiteEqualsAndHashTest extends TestCase {
+
+ public void testEquals() throws Exception {
+ // Since the generated equals and hashCode methods for lite messages are a
+ // mostly complete subset of those for regular messages, we can mostly assume
+ // that the generated methods are already thoroughly tested by the regular tests.
+
+ // This test mostly just verifies is that a proto with
+ // optimize_for = LITE_RUNTIME and java_generates_equals_and_hash_compiles
+ // correctly when linked only against the lite library.
+
+ // We do however do some basic testing to make sure that equals is actually
+ // overriden to test for value equality rather than simple object equality.
+
+ // Check that two identical objs are equal.
+ Foo foo1a = Foo.newBuilder()
+ .setValue(1)
+ .addBar(Bar.newBuilder().setName("foo1"))
+ .build();
+ Foo foo1b = Foo.newBuilder()
+ .setValue(1)
+ .addBar(Bar.newBuilder().setName("foo1"))
+ .build();
+ Foo foo2 = Foo.newBuilder()
+ .setValue(1)
+ .addBar(Bar.newBuilder().setName("foo2"))
+ .build();
+
+ // Check that equals is doing value rather than object equality.
+ assertEquals(foo1a, foo1b);
+ assertEquals(foo1a.hashCode(), foo1b.hashCode());
+
+ // Check that a diffeent object is not equal.
+ assertFalse(foo1a.equals(foo2));
+
+ // Check that two objects which have different types but the same field values are not
+ // considered to be equal.
+ Bar bar = Bar.newBuilder().setName("bar").build();
+ 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/LiteTest.java b/java/src/test/java/com/google/protobuf/LiteTest.java
index 4e1003d9..4d8037fc 100644
--- a/java/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/src/test/java/com/google/protobuf/LiteTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -129,8 +129,11 @@ public class LiteTest extends TestCase {
TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
.build();
ObjectOutputStream out = new ObjectOutputStream(baos);
- out.writeObject(expected);
- out.close();
+ try {
+ out.writeObject(expected);
+ } finally {
+ out.close();
+ }
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bais);
TestAllTypesLite actual = (TestAllTypesLite) in.readObject();
@@ -142,4 +145,17 @@ public class LiteTest extends TestCase {
assertEquals(expected.getOptionalNestedMessage().getBb(),
actual.getOptionalNestedMessage().getBb());
}
+
+ public void testClone() {
+ TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder()
+ .setOptionalInt32(123);
+ assertEquals(
+ expected.getOptionalInt32(), expected.clone().getOptionalInt32());
+
+ TestAllExtensionsLite.Builder expected2 = TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 123);
+ assertEquals(
+ expected2.getExtension(UnittestLite.optionalInt32ExtensionLite),
+ expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite));
+ }
}
diff --git a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
new file mode 100644
index 00000000..046832de
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -0,0 +1,432 @@
+// 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 junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Test {@link LiteralByteString} by setting up a reference string in {@link #setUp()}.
+ * This class is designed to be extended for testing extensions of {@link LiteralByteString}
+ * such as {@link BoundedByteString}, see {@link BoundedByteStringTest}.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class LiteralByteStringTest extends TestCase {
+ protected static final String UTF_8 = "UTF-8";
+
+ protected String classUnderTest;
+ protected byte[] referenceBytes;
+ protected ByteString stringUnderTest;
+ protected int expectedHashCode;
+
+ @Override
+ protected void setUp() throws Exception {
+ classUnderTest = "LiteralByteString";
+ referenceBytes = ByteStringTest.getTestBytes(1234, 11337766L);
+ stringUnderTest = ByteString.copyFrom(referenceBytes);
+ expectedHashCode = 331161852;
+ }
+
+ public void testExpectedType() {
+ String actualClassName = getActualClassName(stringUnderTest);
+ assertEquals(classUnderTest + " should match type exactly", classUnderTest, actualClassName);
+ }
+
+ protected String getActualClassName(Object object) {
+ String actualClassName = object.getClass().getName();
+ actualClassName = actualClassName.substring(actualClassName.lastIndexOf('.') + 1);
+ return actualClassName;
+ }
+
+ public void testByteAt() {
+ boolean stillEqual = true;
+ for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
+ stillEqual = (referenceBytes[i] == stringUnderTest.byteAt(i));
+ }
+ assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
+ }
+
+ public void testByteIterator() {
+ boolean stillEqual = true;
+ ByteString.ByteIterator iter = stringUnderTest.iterator();
+ for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
+ stillEqual = (iter.hasNext() && referenceBytes[i] == iter.nextByte());
+ }
+ assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
+ assertFalse(classUnderTest + " must have exhausted the itertor", iter.hasNext());
+
+ try {
+ iter.nextByte();
+ fail("Should have thrown an exception.");
+ } catch (NoSuchElementException e) {
+ // This is success
+ }
+ }
+
+ public void testByteIterable() {
+ boolean stillEqual = true;
+ int j = 0;
+ for (byte quantum : stringUnderTest) {
+ stillEqual = (referenceBytes[j] == quantum);
+ ++j;
+ }
+ assertTrue(classUnderTest + " must capture the right bytes as Bytes", stillEqual);
+ assertEquals(classUnderTest + " iterable character count", referenceBytes.length, j);
+ }
+
+ public void testSize() {
+ assertEquals(classUnderTest + " must have the expected size", referenceBytes.length,
+ stringUnderTest.size());
+ }
+
+ public void testGetTreeDepth() {
+ assertEquals(classUnderTest + " must have depth 0", 0, stringUnderTest.getTreeDepth());
+ }
+
+ public void testIsBalanced() {
+ assertTrue(classUnderTest + " is technically balanced", stringUnderTest.isBalanced());
+ }
+
+ public void testCopyTo_ByteArrayOffsetLength() {
+ int destinationOffset = 50;
+ int length = 100;
+ byte[] destination = new byte[destinationOffset + length];
+ int sourceOffset = 213;
+ stringUnderTest.copyTo(destination, sourceOffset, destinationOffset, length);
+ boolean stillEqual = true;
+ for (int i = 0; stillEqual && i < length; ++i) {
+ stillEqual = referenceBytes[i + sourceOffset] == destination[i + destinationOffset];
+ }
+ assertTrue(classUnderTest + ".copyTo(4 arg) must give the expected bytes", stillEqual);
+ }
+
+ public void testCopyTo_ByteArrayOffsetLengthErrors() {
+ int destinationOffset = 50;
+ int length = 100;
+ byte[] destination = new byte[destinationOffset + length];
+
+ try {
+ // Copy one too many bytes
+ stringUnderTest.copyTo(destination, stringUnderTest.size() + 1 - length,
+ destinationOffset, length);
+ fail("Should have thrown an exception when copying too many bytes of a "
+ + classUnderTest);
+ } catch (IndexOutOfBoundsException expected) {
+ // This is success
+ }
+
+ try {
+ // Copy with illegal negative sourceOffset
+ stringUnderTest.copyTo(destination, -1, destinationOffset, length);
+ fail("Should have thrown an exception when given a negative sourceOffset in "
+ + classUnderTest);
+ } catch (IndexOutOfBoundsException expected) {
+ // This is success
+ }
+
+ try {
+ // Copy with illegal negative destinationOffset
+ stringUnderTest.copyTo(destination, 0, -1, length);
+ fail("Should have thrown an exception when given a negative destinationOffset in "
+ + classUnderTest);
+ } catch (IndexOutOfBoundsException expected) {
+ // This is success
+ }
+
+ try {
+ // Copy with illegal negative size
+ stringUnderTest.copyTo(destination, 0, 0, -1);
+ fail("Should have thrown an exception when given a negative size in "
+ + classUnderTest);
+ } catch (IndexOutOfBoundsException expected) {
+ // This is success
+ }
+
+ try {
+ // Copy with illegal too-large sourceOffset
+ stringUnderTest.copyTo(destination, 2 * stringUnderTest.size(), 0, length);
+ fail("Should have thrown an exception when the destinationOffset is too large in "
+ + classUnderTest);
+ } catch (IndexOutOfBoundsException expected) {
+ // This is success
+ }
+
+ try {
+ // Copy with illegal too-large destinationOffset
+ stringUnderTest.copyTo(destination, 0, 2 * destination.length, length);
+ fail("Should have thrown an exception when the destinationOffset is too large in "
+ + classUnderTest);
+ } catch (IndexOutOfBoundsException expected) {
+ // This is success
+ }
+ }
+
+ public void testCopyTo_ByteBuffer() {
+ ByteBuffer myBuffer = ByteBuffer.allocate(referenceBytes.length);
+ stringUnderTest.copyTo(myBuffer);
+ assertTrue(classUnderTest + ".copyTo(ByteBuffer) must give back the same bytes",
+ Arrays.equals(referenceBytes, myBuffer.array()));
+ }
+
+ public void testAsReadOnlyByteBuffer() {
+ ByteBuffer byteBuffer = stringUnderTest.asReadOnlyByteBuffer();
+ byte[] roundTripBytes = new byte[referenceBytes.length];
+ assertTrue(byteBuffer.remaining() == referenceBytes.length);
+ assertTrue(byteBuffer.isReadOnly());
+ byteBuffer.get(roundTripBytes);
+ assertTrue(classUnderTest + ".asReadOnlyByteBuffer() must give back the same bytes",
+ Arrays.equals(referenceBytes, roundTripBytes));
+ }
+
+ public void testAsReadOnlyByteBufferList() {
+ List<ByteBuffer> byteBuffers = stringUnderTest.asReadOnlyByteBufferList();
+ int bytesSeen = 0;
+ byte[] roundTripBytes = new byte[referenceBytes.length];
+ for (ByteBuffer byteBuffer : byteBuffers) {
+ int thisLength = byteBuffer.remaining();
+ assertTrue(byteBuffer.isReadOnly());
+ assertTrue(bytesSeen + thisLength <= referenceBytes.length);
+ byteBuffer.get(roundTripBytes, bytesSeen, thisLength);
+ bytesSeen += thisLength;
+ }
+ assertTrue(bytesSeen == referenceBytes.length);
+ assertTrue(classUnderTest + ".asReadOnlyByteBufferTest() must give back the same bytes",
+ Arrays.equals(referenceBytes, roundTripBytes));
+ }
+
+ public void testToByteArray() {
+ byte[] roundTripBytes = stringUnderTest.toByteArray();
+ assertTrue(classUnderTest + ".toByteArray() must give back the same bytes",
+ Arrays.equals(referenceBytes, roundTripBytes));
+ }
+
+ public void testWriteTo() throws IOException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ stringUnderTest.writeTo(bos);
+ byte[] roundTripBytes = bos.toByteArray();
+ assertTrue(classUnderTest + ".writeTo() must give back the same bytes",
+ Arrays.equals(referenceBytes, roundTripBytes));
+ }
+
+ public void testWriteTo_mutating() throws IOException {
+ OutputStream os = new OutputStream() {
+ @Override
+ public void write(byte[] b, int off, int len) {
+ for (int x = 0; x < len; ++x) {
+ b[off + x] = (byte) 0;
+ }
+ }
+
+ @Override
+ public void write(int b) {
+ // Purposefully left blank.
+ }
+ };
+
+ stringUnderTest.writeTo(os);
+ byte[] newBytes = stringUnderTest.toByteArray();
+ assertTrue(classUnderTest + ".writeTo() must not grant access to underlying array",
+ Arrays.equals(referenceBytes, newBytes));
+ }
+
+ public void testNewOutput() throws IOException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ByteString.Output output = ByteString.newOutput();
+ stringUnderTest.writeTo(output);
+ assertEquals("Output Size returns correct result",
+ output.size(), stringUnderTest.size());
+ output.writeTo(bos);
+ assertTrue("Output.writeTo() must give back the same bytes",
+ Arrays.equals(referenceBytes, bos.toByteArray()));
+
+ // write the output stream to itself! This should cause it to double
+ output.writeTo(output);
+ assertEquals("Writing an output stream to itself is successful",
+ stringUnderTest.concat(stringUnderTest), output.toByteString());
+
+ output.reset();
+ assertEquals("Output.reset() resets the output", 0, output.size());
+ assertEquals("Output.reset() resets the output",
+ ByteString.EMPTY, output.toByteString());
+ }
+
+ public void testToString() throws UnsupportedEncodingException {
+ String testString = "I love unicode \u1234\u5678 characters";
+ LiteralByteString unicode = new LiteralByteString(testString.getBytes(UTF_8));
+ String roundTripString = unicode.toString(UTF_8);
+ assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
+ }
+
+ public void testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException{
+ assertSame(classUnderTest + " must be the same string references",
+ ByteString.EMPTY.toString(UTF_8), new LiteralByteString(new byte[]{}).toString(UTF_8));
+ }
+
+ public void testToString_raisesException() throws UnsupportedEncodingException{
+ try {
+ ByteString.EMPTY.toString("invalid");
+ fail("Should have thrown an exception.");
+ } catch (UnsupportedEncodingException expected) {
+ // This is success
+ }
+
+ try {
+ new LiteralByteString(referenceBytes).toString("invalid");
+ fail("Should have thrown an exception.");
+ } catch (UnsupportedEncodingException expected) {
+ // This is success
+ }
+ }
+
+ public void testEquals() {
+ assertEquals(classUnderTest + " must not equal null", false, stringUnderTest.equals(null));
+ assertEquals(classUnderTest + " must equal self", stringUnderTest, stringUnderTest);
+ assertFalse(classUnderTest + " must not equal the empty string",
+ stringUnderTest.equals(ByteString.EMPTY));
+ assertEquals(classUnderTest + " empty strings must be equal",
+ new LiteralByteString(new byte[]{}), stringUnderTest.substring(55, 55));
+ assertEquals(classUnderTest + " must equal another string with the same value",
+ stringUnderTest, new LiteralByteString(referenceBytes));
+
+ byte[] mungedBytes = new byte[referenceBytes.length];
+ System.arraycopy(referenceBytes, 0, mungedBytes, 0, referenceBytes.length);
+ mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF);
+ assertFalse(classUnderTest + " must not equal every string with the same length",
+ stringUnderTest.equals(new LiteralByteString(mungedBytes)));
+ }
+
+ public void testHashCode() {
+ int hash = stringUnderTest.hashCode();
+ assertEquals(classUnderTest + " must have expected hashCode", expectedHashCode, hash);
+ }
+
+ public void testPeekCachedHashCode() {
+ assertEquals(classUnderTest + ".peekCachedHashCode() should return zero at first", 0,
+ stringUnderTest.peekCachedHashCode());
+ stringUnderTest.hashCode();
+ assertEquals(classUnderTest + ".peekCachedHashCode should return zero at first",
+ expectedHashCode, stringUnderTest.peekCachedHashCode());
+ }
+
+ public void testPartialHash() {
+ // partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
+ // This test would fail if the expected hash were 1. It's not.
+ int hash = stringUnderTest.partialHash(stringUnderTest.size(), 0, stringUnderTest.size());
+ assertEquals(classUnderTest + ".partialHash() must yield expected hashCode",
+ expectedHashCode, hash);
+ }
+
+ public void testNewInput() throws IOException {
+ InputStream input = stringUnderTest.newInput();
+ assertEquals("InputStream.available() returns correct value",
+ stringUnderTest.size(), input.available());
+ boolean stillEqual = true;
+ for (byte referenceByte : referenceBytes) {
+ int expectedInt = (referenceByte & 0xFF);
+ stillEqual = (expectedInt == input.read());
+ }
+ assertEquals("InputStream.available() returns correct value",
+ 0, input.available());
+ assertTrue(classUnderTest + " must give the same bytes from the InputStream", stillEqual);
+ assertEquals(classUnderTest + " InputStream must now be exhausted", -1, input.read());
+ }
+
+ public void testNewInput_skip() throws IOException {
+ InputStream input = stringUnderTest.newInput();
+ int stringSize = stringUnderTest.size();
+ int nearEndIndex = stringSize * 2 / 3;
+ long skipped1 = input.skip(nearEndIndex);
+ assertEquals("InputStream.skip()", skipped1, nearEndIndex);
+ assertEquals("InputStream.available()",
+ stringSize - skipped1, input.available());
+ assertTrue("InputStream.mark() is available", input.markSupported());
+ input.mark(0);
+ assertEquals("InputStream.skip(), read()",
+ stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
+ assertEquals("InputStream.available()",
+ stringSize - skipped1 - 1, input.available());
+ long skipped2 = input.skip(stringSize);
+ assertEquals("InputStream.skip() incomplete",
+ skipped2, stringSize - skipped1 - 1);
+ assertEquals("InputStream.skip(), no more input", 0, input.available());
+ assertEquals("InputStream.skip(), no more input", -1, input.read());
+ input.reset();
+ assertEquals("InputStream.reset() succeded",
+ stringSize - skipped1, input.available());
+ assertEquals("InputStream.reset(), read()",
+ stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
+ }
+
+ public void testNewCodedInput() throws IOException {
+ CodedInputStream cis = stringUnderTest.newCodedInput();
+ byte[] roundTripBytes = cis.readRawBytes(referenceBytes.length);
+ assertTrue(classUnderTest + " must give the same bytes back from the CodedInputStream",
+ Arrays.equals(referenceBytes, roundTripBytes));
+ assertTrue(classUnderTest + " CodedInputStream must now be exhausted", cis.isAtEnd());
+ }
+
+ /**
+ * Make sure we keep things simple when concatenating with empty. See also
+ * {@link ByteStringTest#testConcat_empty()}.
+ */
+ public void testConcat_empty() {
+ assertSame(classUnderTest + " concatenated with empty must give " + classUnderTest,
+ stringUnderTest.concat(ByteString.EMPTY), stringUnderTest);
+ assertSame("empty concatenated with " + classUnderTest + " must give " + classUnderTest,
+ ByteString.EMPTY.concat(stringUnderTest), stringUnderTest);
+ }
+
+ public void testJavaSerialization() throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(out);
+ oos.writeObject(stringUnderTest);
+ oos.close();
+ byte[] pickled = out.toByteArray();
+ InputStream in = new ByteArrayInputStream(pickled);
+ ObjectInputStream ois = new ObjectInputStream(in);
+ Object o = ois.readObject();
+ assertTrue("Didn't get a ByteString back", o instanceof ByteString);
+ assertEquals("Should get an equal ByteString back", stringUnderTest, o);
+ }
+}
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..78cba1b4
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -0,0 +1,516 @@
+// 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.TestMap.MessageWithRequiredFields;
+import map_test.MapForProto2TestProto.TestRecursiveMap;
+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 <KeyType, ValueType>
+ 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<Message> entryList = new ArrayList<Message>();
+ 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 <KeyType, ValueType>
+ Map<KeyType, ValueType> mapForValues(
+ KeyType key1, ValueType value1, KeyType key2, ValueType value2) {
+ Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
+ 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());
+ }
+
+
+ public void testRequiredMessage() throws Exception {
+ TestMap.Builder builder = TestMap.newBuilder();
+ builder.getMutableRequiredMessageMap().put(0,
+ MessageWithRequiredFields.newBuilder().buildPartial());
+ TestMap message = builder.buildPartial();
+ assertFalse(message.isInitialized());
+
+ builder.getMutableRequiredMessageMap().put(0,
+ MessageWithRequiredFields.newBuilder().setValue(1).build());
+ message = builder.build();
+ assertTrue(message.isInitialized());
+ }
+
+ public void testRecursiveMap() throws Exception {
+ TestRecursiveMap.Builder builder = TestRecursiveMap.newBuilder();
+ builder.getMutableRecursiveMapField().put(
+ 1, TestRecursiveMap.newBuilder().setValue(2).build());
+ builder.getMutableRecursiveMapField().put(
+ 3, TestRecursiveMap.newBuilder().setValue(4).build());
+ ByteString data = builder.build().toByteString();
+
+ TestRecursiveMap message = TestRecursiveMap.parseFrom(data);
+ assertEquals(2, message.getRecursiveMapField().get(1).getValue());
+ assertEquals(4, message.getRecursiveMapField().get(3).getValue());
+ }
+}
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..b8e67b7c
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/MapTest.java
@@ -0,0 +1,614 @@
+// 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.
+
+ // Regression test for b/18549190: if a map is a subset of the other map,
+ // equals() should return false.
+ b2.getMutableInt32ToInt32Field().remove(1);
+ m2 = b2.build();
+ assertFalse(m1.equals(m2));
+ assertFalse(m2.equals(m1));
+ }
+
+ 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());
+ }
+
+ public void testNestedBuilderOnChangeEventPropagationReflection() {
+ FieldDescriptor intMapField = f("int32_to_int32_field");
+ // Create an outer message builder with nested builder.
+ TestOnChangeEventPropagation.Builder parentBuilder =
+ TestOnChangeEventPropagation.newBuilder();
+ TestMap.Builder testMapBuilder = parentBuilder.getOptionalMessageBuilder();
+
+ // Create a map entry message.
+ TestMap.Builder entryBuilder = TestMap.newBuilder();
+ entryBuilder.getMutableInt32ToInt32Field().put(1, 1);
+
+ // Put the entry into the nested builder.
+ testMapBuilder.addRepeatedField(
+ intMapField, entryBuilder.getRepeatedField(intMapField, 0));
+
+ // Should be able to observe the change.
+ TestOnChangeEventPropagation message = parentBuilder.build();
+ assertEquals(1, message.getOptionalMessage().getInt32ToInt32Field().size());
+
+ // Change the entry value.
+ entryBuilder.getMutableInt32ToInt32Field().put(1, 4);
+ testMapBuilder = parentBuilder.getOptionalMessageBuilder();
+ testMapBuilder.setRepeatedField(
+ intMapField, 0, entryBuilder.getRepeatedField(intMapField, 0));
+
+ // Should be able to observe the change.
+ message = parentBuilder.build();
+ assertEquals(4,
+ message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
+
+ // Clear the nested builder.
+ testMapBuilder = parentBuilder.getOptionalMessageBuilder();
+ testMapBuilder.clearField(intMapField);
+
+ // Should be able to observe the change.
+ message = parentBuilder.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 <KeyType, ValueType>
+ 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<Message> entryList = new ArrayList<Message>();
+ 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 <KeyType, ValueType>
+ Map<KeyType, ValueType> mapForValues(
+ KeyType key1, ValueType value1, KeyType key2, ValueType value2) {
+ Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
+ 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<Integer, Integer> data = new HashMap<Integer, Integer>();
+ data.put(0, 0);
+ data.put(1, 1);
+ data.put(2, 1000); // unknown value.
+
+ TestMap.Builder builder = TestMap.newBuilder();
+ for (Map.Entry<Integer, Integer> 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<Integer, Integer> entry : message.getInt32ToEnumFieldValue().entrySet()) {
+ assertEquals(data.get(entry.getKey()) + 1, entry.getValue().intValue());
+ }
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/MessageTest.java b/java/src/test/java/com/google/protobuf/MessageTest.java
index c2f47eb2..abcd3a1d 100644
--- a/java/src/test/java/com/google/protobuf/MessageTest.java
+++ b/java/src/test/java/com/google/protobuf/MessageTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -38,6 +38,8 @@ import protobuf_unittest.UnittestProto.ForeignMessage;
import junit.framework.TestCase;
+import java.util.List;
+
/**
* Misc. unit tests for message operations that apply to both generated
* and dynamic messages.
@@ -310,4 +312,42 @@ public class MessageTest extends TestCase {
assertEquals("Message missing required fields: a, b, c", e.getMessage());
}
}
+
+ /** Test reading unset repeated message from DynamicMessage. */
+ public void testDynamicRepeatedMessageNull() throws Exception {
+ Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+ DynamicMessage result =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
+ .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+ .build();
+
+ assertTrue(result.getField(result.getDescriptorForType()
+ .findFieldByName("repeated_foreign_message")) instanceof List<?>);
+ assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
+ .findFieldByName("repeated_foreign_message")), 0);
+ }
+
+ /** Test reading repeated message from DynamicMessage. */
+ public void testDynamicRepeatedMessageNotNull() throws Exception {
+
+ TestAllTypes REPEATED_NESTED =
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(1)
+ .setOptionalString("foo")
+ .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+ .addRepeatedString("bar")
+ .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
+ .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
+ .build();
+ Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+ DynamicMessage result =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
+ .mergeFrom(DynamicMessage.newBuilder(REPEATED_NESTED).build())
+ .build();
+
+ assertTrue(result.getField(result.getDescriptorForType()
+ .findFieldByName("repeated_foreign_message")) instanceof List<?>);
+ assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
+ .findFieldByName("repeated_foreign_message")), 2);
+ }
}
diff --git a/java/src/test/java/com/google/protobuf/NestedBuildersTest.java b/java/src/test/java/com/google/protobuf/NestedBuildersTest.java
index f5375801..23653126 100644
--- a/java/src/test/java/com/google/protobuf/NestedBuildersTest.java
+++ b/java/src/test/java/com/google/protobuf/NestedBuildersTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/test/java/com/google/protobuf/ParserTest.java b/java/src/test/java/com/google/protobuf/ParserTest.java
new file mode 100644
index 00000000..b11d8cb9
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/ParserTest.java
@@ -0,0 +1,381 @@
+// 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.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import com.google.protobuf.UnittestLite.TestParsingMergeLite;
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestParsingMerge;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Unit test for {@link Parser}.
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+public class ParserTest extends TestCase {
+ public void testGeneratedMessageParserSingleton() throws Exception {
+ for (int i = 0; i < 10; i++) {
+ assertEquals(TestAllTypes.PARSER,
+ TestUtil.getAllSet().getParserForType());
+ }
+ }
+
+ private void assertRoundTripEquals(MessageLite message,
+ ExtensionRegistryLite registry)
+ throws Exception {
+ final byte[] data = message.toByteArray();
+ final int offset = 20;
+ final int length = data.length;
+ final int padding = 30;
+ Parser<? extends MessageLite> parser = message.getParserForType();
+ assertMessageEquals(message, parser.parseFrom(data, registry));
+ assertMessageEquals(message, parser.parseFrom(
+ generatePaddingArray(data, offset, padding),
+ offset, length, registry));
+ assertMessageEquals(message, parser.parseFrom(
+ message.toByteString(), registry));
+ assertMessageEquals(message, parser.parseFrom(
+ new ByteArrayInputStream(data), registry));
+ assertMessageEquals(message, parser.parseFrom(
+ CodedInputStream.newInstance(data), registry));
+ }
+
+ @SuppressWarnings("unchecked")
+ private void assertRoundTripEquals(MessageLite message) throws Exception {
+ final byte[] data = message.toByteArray();
+ final int offset = 20;
+ final int length = data.length;
+ final int padding = 30;
+
+ Parser<MessageLite> parser =
+ (Parser<MessageLite>) message.getParserForType();
+ assertMessageEquals(message, parser.parseFrom(data));
+ assertMessageEquals(message, parser.parseFrom(
+ generatePaddingArray(data, offset, padding),
+ offset, length));
+ assertMessageEquals(message, parser.parseFrom(message.toByteString()));
+ assertMessageEquals(message, parser.parseFrom(
+ new ByteArrayInputStream(data)));
+ assertMessageEquals(message, parser.parseFrom(
+ CodedInputStream.newInstance(data)));
+ }
+
+ private void assertMessageEquals(
+ MessageLite expected, MessageLite actual)
+ throws Exception {
+ if (expected instanceof Message) {
+ assertEquals(expected, actual);
+ } else {
+ assertEquals(expected.toByteString(), actual.toByteString());
+ }
+ }
+
+ private byte[] generatePaddingArray(byte[] data, int offset, int padding) {
+ byte[] result = new byte[offset + data.length + padding];
+ System.arraycopy(data, 0, result, offset, data.length);
+ return result;
+ }
+
+ public void testNormalMessage() throws Exception {
+ assertRoundTripEquals(TestUtil.getAllSet());
+ }
+
+
+ public void testParsePartial() throws Exception {
+ assertParsePartial(TestRequired.PARSER,
+ TestRequired.newBuilder().setA(1).buildPartial());
+ }
+
+ private <T extends MessageLite> void assertParsePartial(
+ Parser<T> parser, T partialMessage) throws Exception {
+ final String errorString =
+ "Should throw exceptions when the parsed message isn't initialized.";
+
+ // parsePartialFrom should pass.
+ byte[] data = partialMessage.toByteArray();
+ assertEquals(partialMessage, parser.parsePartialFrom(data));
+ assertEquals(partialMessage, parser.parsePartialFrom(
+ partialMessage.toByteString()));
+ assertEquals(partialMessage, parser.parsePartialFrom(
+ new ByteArrayInputStream(data)));
+ assertEquals(partialMessage, parser.parsePartialFrom(
+ CodedInputStream.newInstance(data)));
+
+ // parseFrom(ByteArray)
+ try {
+ parser.parseFrom(partialMessage.toByteArray());
+ fail(errorString);
+ } catch (InvalidProtocolBufferException e) {
+ // pass.
+ }
+
+ // parseFrom(ByteString)
+ try {
+ parser.parseFrom(partialMessage.toByteString());
+ fail(errorString);
+ } catch (InvalidProtocolBufferException e) {
+ // pass.
+ }
+
+ // parseFrom(InputStream)
+ try {
+ parser.parseFrom(new ByteArrayInputStream(partialMessage.toByteArray()));
+ fail(errorString);
+ } catch (IOException e) {
+ // pass.
+ }
+
+ // parseFrom(CodedInputStream)
+ try {
+ parser.parseFrom(CodedInputStream.newInstance(
+ partialMessage.toByteArray()));
+ fail(errorString);
+ } catch (IOException e) {
+ // pass.
+ }
+ }
+
+ public void testParseExtensions() throws Exception {
+ assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
+ TestUtil.getExtensionRegistry());
+ assertRoundTripEquals(TestUtil.getAllLiteExtensionsSet(),
+ TestUtil.getExtensionRegistryLite());
+ }
+
+ public void testParsePacked() throws Exception {
+ assertRoundTripEquals(TestUtil.getPackedSet());
+ assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
+ TestUtil.getExtensionRegistry());
+ assertRoundTripEquals(TestUtil.getLitePackedExtensionsSet(),
+ TestUtil.getExtensionRegistryLite());
+ }
+
+ public void testParseDelimitedTo() throws Exception {
+ // Write normal Message.
+ TestAllTypes normalMessage = TestUtil.getAllSet();
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ normalMessage.writeDelimitedTo(output);
+
+ // Write MessageLite with packed extension fields.
+ TestPackedExtensionsLite packedMessage =
+ TestUtil.getLitePackedExtensionsSet();
+ packedMessage.writeDelimitedTo(output);
+
+ InputStream input = new ByteArrayInputStream(output.toByteArray());
+ assertMessageEquals(
+ normalMessage,
+ normalMessage.getParserForType().parseDelimitedFrom(input));
+ assertMessageEquals(
+ packedMessage,
+ packedMessage.getParserForType().parseDelimitedFrom(
+ input, TestUtil.getExtensionRegistryLite()));
+ }
+
+ public void testParseUnknownFields() throws Exception {
+ // All fields will be treated as unknown fields in emptyMessage.
+ TestEmptyMessage emptyMessage = TestEmptyMessage.PARSER.parseFrom(
+ TestUtil.getAllSet().toByteString());
+ assertEquals(
+ TestUtil.getAllSet().toByteString(),
+ emptyMessage.toByteString());
+ }
+
+
+ public void testOptimizeForSize() throws Exception {
+ TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
+ builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());
+ builder.setExtension(TestOptimizedForSize.testExtension, 56);
+ builder.setExtension(TestOptimizedForSize.testExtension2,
+ TestRequiredOptimizedForSize.newBuilder().setX(78).build());
+
+ TestOptimizedForSize message = builder.build();
+ ExtensionRegistry registry = ExtensionRegistry.newInstance();
+ UnittestOptimizeFor.registerAllExtensions(registry);
+
+ assertRoundTripEquals(message, registry);
+ }
+
+ /** Helper method for {@link #testParsingMerge()}.*/
+ private void assertMessageMerged(TestAllTypes allTypes)
+ throws Exception {
+ assertEquals(3, allTypes.getOptionalInt32());
+ assertEquals(2, allTypes.getOptionalInt64());
+ assertEquals("hello", allTypes.getOptionalString());
+ }
+
+ /** Helper method for {@link #testParsingMergeLite()}.*/
+ private void assertMessageMerged(TestAllTypesLite allTypes)
+ throws Exception {
+ assertEquals(3, allTypes.getOptionalInt32());
+ assertEquals(2, allTypes.getOptionalInt64());
+ assertEquals("hello", allTypes.getOptionalString());
+ }
+
+ public void testParsingMerge() throws Exception {
+ // Build messages.
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestAllTypes msg1 = builder.setOptionalInt32(1).build();
+ builder.clear();
+ TestAllTypes msg2 = builder.setOptionalInt64(2).build();
+ builder.clear();
+ TestAllTypes msg3 = builder.setOptionalInt32(3)
+ .setOptionalString("hello").build();
+
+ // Build groups.
+ TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 =
+ TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
+ .setField1(msg1).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 =
+ TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
+ .setField1(msg2).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 =
+ TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
+ .setField1(msg3).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 =
+ TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
+ .setField1(msg1).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 =
+ TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
+ .setField1(msg2).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 =
+ TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
+ .setField1(msg3).build();
+
+ // Assign and serialize RepeatedFieldsGenerator.
+ ByteString data = TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
+ .addField1(msg1).addField1(msg2).addField1(msg3)
+ .addField2(msg1).addField2(msg2).addField2(msg3)
+ .addField3(msg1).addField3(msg2).addField3(msg3)
+ .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
+ .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
+ .addExt1(msg1).addExt1(msg2).addExt1(msg3)
+ .addExt2(msg1).addExt2(msg2).addExt2(msg3)
+ .build().toByteString();
+
+ // Parse TestParsingMerge.
+ ExtensionRegistry registry = ExtensionRegistry.newInstance();
+ UnittestProto.registerAllExtensions(registry);
+ TestParsingMerge parsingMerge =
+ TestParsingMerge.PARSER.parseFrom(data, registry);
+
+ // Required and optional fields should be merged.
+ assertMessageMerged(parsingMerge.getRequiredAllTypes());
+ assertMessageMerged(parsingMerge.getOptionalAllTypes());
+ assertMessageMerged(
+ parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
+ assertMessageMerged(parsingMerge.getExtension(
+ TestParsingMerge.optionalExt));
+
+ // Repeated fields should not be merged.
+ assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
+ assertEquals(3, parsingMerge.getRepeatedGroupCount());
+ assertEquals(3, parsingMerge.getExtensionCount(
+ TestParsingMerge.repeatedExt));
+ }
+
+ public void testParsingMergeLite() throws Exception {
+ // Build messages.
+ TestAllTypesLite.Builder builder =
+ TestAllTypesLite.newBuilder();
+ TestAllTypesLite msg1 = builder.setOptionalInt32(1).build();
+ builder.clear();
+ TestAllTypesLite msg2 = builder.setOptionalInt64(2).build();
+ builder.clear();
+ TestAllTypesLite msg3 = builder.setOptionalInt32(3)
+ .setOptionalString("hello").build();
+
+ // Build groups.
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG1 =
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
+ .setField1(msg1).build();
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG2 =
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
+ .setField1(msg2).build();
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG3 =
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
+ .setField1(msg3).build();
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG1 =
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
+ .setField1(msg1).build();
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG2 =
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
+ .setField1(msg2).build();
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG3 =
+ TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
+ .setField1(msg3).build();
+
+ // Assign and serialize RepeatedFieldsGenerator.
+ ByteString data = TestParsingMergeLite.RepeatedFieldsGenerator.newBuilder()
+ .addField1(msg1).addField1(msg2).addField1(msg3)
+ .addField2(msg1).addField2(msg2).addField2(msg3)
+ .addField3(msg1).addField3(msg2).addField3(msg3)
+ .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
+ .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
+ .addExt1(msg1).addExt1(msg2).addExt1(msg3)
+ .addExt2(msg1).addExt2(msg2).addExt2(msg3)
+ .build().toByteString();
+
+ // Parse TestParsingMergeLite.
+ ExtensionRegistry registry = ExtensionRegistry.newInstance();
+ UnittestLite.registerAllExtensions(registry);
+ TestParsingMergeLite parsingMerge =
+ TestParsingMergeLite.PARSER.parseFrom(data, registry);
+
+ // Required and optional fields should be merged.
+ assertMessageMerged(parsingMerge.getRequiredAllTypes());
+ assertMessageMerged(parsingMerge.getOptionalAllTypes());
+ assertMessageMerged(
+ parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
+ assertMessageMerged(parsingMerge.getExtension(
+ TestParsingMergeLite.optionalExt));
+
+ // Repeated fields should not be merged.
+ assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
+ assertEquals(3, parsingMerge.getRepeatedGroupCount());
+ assertEquals(3, parsingMerge.getExtensionCount(
+ TestParsingMergeLite.repeatedExt));
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java b/java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
index cdcdcb25..49d52321 100644
--- a/java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
+++ b/java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java b/java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
new file mode 100644
index 00000000..212f8d68
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
@@ -0,0 +1,97 @@
+// 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.UnsupportedEncodingException;
+import java.util.Iterator;
+
+/**
+ * This class tests {@link RopeByteString#substring(int, int)} by inheriting the tests from
+ * {@link LiteralByteStringTest}. Only a couple of methods are overridden.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class RopeByteStringSubstringTest extends LiteralByteStringTest {
+
+ @Override
+ protected void setUp() throws Exception {
+ classUnderTest = "RopeByteString";
+ byte[] sourceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
+ Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(sourceBytes).iterator();
+ ByteString sourceString = iter.next();
+ while (iter.hasNext()) {
+ sourceString = sourceString.concat(iter.next());
+ }
+
+ int from = 1130;
+ int to = sourceBytes.length - 5555;
+ stringUnderTest = sourceString.substring(from, to);
+ referenceBytes = new byte[to - from];
+ System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
+ expectedHashCode = -1259260680;
+ }
+
+ @Override
+ public void testGetTreeDepth() {
+ assertEquals(classUnderTest + " must have the expected tree depth",
+ 3, stringUnderTest.getTreeDepth());
+ }
+
+ @Override
+ public void testToString() throws UnsupportedEncodingException {
+ String sourceString = "I love unicode \u1234\u5678 characters";
+ ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
+ int copies = 250;
+
+ // By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
+ StringBuilder builder = new StringBuilder(copies * sourceString.length());
+ ByteString unicode = ByteString.EMPTY;
+ for (int i = 0; i < copies; ++i) {
+ builder.append(sourceString);
+ unicode = RopeByteString.concatenate(unicode, sourceByteString);
+ }
+ String testString = builder.toString();
+
+ // Do the substring part
+ testString = testString.substring(2, testString.length() - 6);
+ unicode = unicode.substring(2, unicode.size() - 6);
+
+ assertEquals(classUnderTest + " from string must have the expected type",
+ classUnderTest, getActualClassName(unicode));
+ String roundTripString = unicode.toString(UTF_8);
+ assertEquals(classUnderTest + " unicode bytes must match",
+ testString, roundTripString);
+ ByteString flatString = ByteString.copyFromUtf8(testString);
+ assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
+ assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
+ flatString.hashCode(), unicode.hashCode());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/RopeByteStringTest.java b/java/src/test/java/com/google/protobuf/RopeByteStringTest.java
new file mode 100644
index 00000000..0f2344d6
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/RopeByteStringTest.java
@@ -0,0 +1,161 @@
+// 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Iterator;
+
+/**
+ * This class tests {@link RopeByteString} by inheriting the tests from
+ * {@link LiteralByteStringTest}. Only a couple of methods are overridden.
+ *
+ * <p>A full test of the result of {@link RopeByteString#substring(int, int)} is found in the
+ * separate class {@link RopeByteStringSubstringTest}.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class RopeByteStringTest extends LiteralByteStringTest {
+
+ @Override
+ protected void setUp() throws Exception {
+ classUnderTest = "RopeByteString";
+ referenceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
+ Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(referenceBytes).iterator();
+ stringUnderTest = iter.next();
+ while (iter.hasNext()) {
+ stringUnderTest = stringUnderTest.concat(iter.next());
+ }
+ expectedHashCode = -1214197238;
+ }
+
+ @Override
+ public void testGetTreeDepth() {
+ assertEquals(classUnderTest + " must have the expected tree depth",
+ 4, stringUnderTest.getTreeDepth());
+ }
+
+ public void testBalance() {
+ int numberOfPieces = 10000;
+ int pieceSize = 64;
+ byte[] testBytes = ByteStringTest.getTestBytes(numberOfPieces * pieceSize, 113377L);
+
+ // Build up a big ByteString from smaller pieces to force a rebalance
+ ByteString concatenated = ByteString.EMPTY;
+ for (int i = 0; i < numberOfPieces; ++i) {
+ concatenated = concatenated.concat(ByteString.copyFrom(testBytes, i * pieceSize, pieceSize));
+ }
+
+ assertEquals(classUnderTest + " from string must have the expected type",
+ classUnderTest, getActualClassName(concatenated));
+ assertTrue(classUnderTest + " underlying bytes must match after balancing",
+ Arrays.equals(testBytes, concatenated.toByteArray()));
+ ByteString testString = ByteString.copyFrom(testBytes);
+ assertTrue(classUnderTest + " balanced string must equal flat string",
+ concatenated.equals(testString));
+ assertTrue(classUnderTest + " flat string must equal balanced string",
+ testString.equals(concatenated));
+ assertEquals(classUnderTest + " balanced string must have same hash code as flat string",
+ testString.hashCode(), concatenated.hashCode());
+ }
+
+ @Override
+ public void testToString() throws UnsupportedEncodingException {
+ String sourceString = "I love unicode \u1234\u5678 characters";
+ ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
+ int copies = 250;
+
+ // By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
+ StringBuilder builder = new StringBuilder(copies * sourceString.length());
+ ByteString unicode = ByteString.EMPTY;
+ for (int i = 0; i < copies; ++i) {
+ builder.append(sourceString);
+ unicode = RopeByteString.concatenate(unicode, sourceByteString);
+ }
+ String testString = builder.toString();
+
+ assertEquals(classUnderTest + " from string must have the expected type",
+ classUnderTest, getActualClassName(unicode));
+ String roundTripString = unicode.toString(UTF_8);
+ assertEquals(classUnderTest + " unicode bytes must match",
+ testString, roundTripString);
+ ByteString flatString = ByteString.copyFromUtf8(testString);
+ assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
+ assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
+ flatString.hashCode(), unicode.hashCode());
+ }
+
+ @Override
+ public void testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException {
+ RopeByteString ropeByteString =
+ RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
+ assertSame(classUnderTest + " must be the same string references",
+ ByteString.EMPTY.toString(UTF_8), ropeByteString.toString(UTF_8));
+ }
+
+ public void testToString_raisesException() throws UnsupportedEncodingException{
+ try {
+ ByteString byteString =
+ RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
+ byteString.toString("invalid");
+ fail("Should have thrown an exception.");
+ } catch (UnsupportedEncodingException expected) {
+ // This is success
+ }
+
+ try {
+ ByteString byteString = RopeByteString.concatenate(ByteString.copyFromUtf8("foo"),
+ ByteString.copyFromUtf8("bar"));
+ byteString.toString("invalid");
+ fail("Should have thrown an exception.");
+ } catch (UnsupportedEncodingException expected) {
+ // This is success
+ }
+ }
+
+ public void testJavaSerialization() throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(out);
+ oos.writeObject(stringUnderTest);
+ oos.close();
+ byte[] pickled = out.toByteArray();
+ InputStream in = new ByteArrayInputStream(pickled);
+ ObjectInputStream ois = new ObjectInputStream(in);
+ Object o = ois.readObject();
+ assertTrue("Didn't get a ByteString back", o instanceof ByteString);
+ assertEquals("Should get an equal ByteString back", stringUnderTest, o);
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/ServiceTest.java b/java/src/test/java/com/google/protobuf/ServiceTest.java
index 4be84f5b..ff980d66 100644
--- a/java/src/test/java/com/google/protobuf/ServiceTest.java
+++ b/java/src/test/java/com/google/protobuf/ServiceTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java b/java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
index 5c2f7e75..58b80007 100644
--- a/java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
+++ b/java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/test/java/com/google/protobuf/SmallSortedMapTest.java b/java/src/test/java/com/google/protobuf/SmallSortedMapTest.java
index 8f77a036..366086d3 100644
--- a/java/src/test/java/com/google/protobuf/SmallSortedMapTest.java
+++ b/java/src/test/java/com/google/protobuf/SmallSortedMapTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java b/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java
index 6feec4e6..2c60fe0e 100644
--- a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java
+++ b/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,7 +35,7 @@ import junit.framework.TestCase;
/**
* Tests that proto2 api generation doesn't cause compile errors when
* compiling protocol buffers that have names that would otherwise conflict
- * if not fully qualified (like @Deprecated and @Override).
+ * if not fully qualified (like @Deprecated and @Override).
*
* @author jonp@google.com (Jon Perlow)
*/
@@ -45,5 +45,52 @@ public class TestBadIdentifiers extends TestCase {
// If this compiles, it means the generation was correct.
TestBadIdentifiersProto.Deprecated.newBuilder();
TestBadIdentifiersProto.Override.newBuilder();
- }
+ }
+
+ public void testGetDescriptor() {
+ Descriptors.FileDescriptor fileDescriptor =
+ TestBadIdentifiersProto.getDescriptor();
+ String descriptorField = TestBadIdentifiersProto.Descriptor
+ .getDefaultInstance().getDescriptor();
+ Descriptors.Descriptor protoDescriptor = TestBadIdentifiersProto.Descriptor
+ .getDefaultInstance().getDescriptorForType();
+ String nestedDescriptorField = TestBadIdentifiersProto.Descriptor
+ .NestedDescriptor.getDefaultInstance().getDescriptor();
+ Descriptors.Descriptor nestedProtoDescriptor = TestBadIdentifiersProto
+ .Descriptor.NestedDescriptor.getDefaultInstance()
+ .getDescriptorForType();
+ }
+
+ public void testConflictingFieldNames() throws Exception {
+ TestBadIdentifiersProto.TestConflictingFieldNames message =
+ TestBadIdentifiersProto.TestConflictingFieldNames.getDefaultInstance();
+ // Make sure generated accessors are properly named.
+ assertEquals(0, message.getInt32Field1Count());
+ assertEquals(0, message.getEnumField2Count());
+ assertEquals(0, message.getStringField3Count());
+ assertEquals(0, message.getBytesField4Count());
+ assertEquals(0, message.getMessageField5Count());
+
+ assertEquals(0, message.getInt32FieldCount11());
+ assertEquals(0, message.getEnumFieldCount12().getNumber());
+ assertEquals("", message.getStringFieldCount13());
+ assertEquals(ByteString.EMPTY, message.getBytesFieldCount14());
+ assertEquals(0, message.getMessageFieldCount15().getSerializedSize());
+
+ assertEquals(0, message.getInt32Field21Count());
+ assertEquals(0, message.getEnumField22Count());
+ assertEquals(0, message.getStringField23Count());
+ assertEquals(0, message.getBytesField24Count());
+ assertEquals(0, message.getMessageField25Count());
+
+ assertEquals(0, message.getInt32Field1List().size());
+ assertEquals(0, message.getInt32FieldList31());
+
+ assertEquals(0, message.getInt64FieldCount());
+ assertEquals(0L, message.getExtension(
+ TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount).longValue());
+ assertEquals(0L, message.getExtension(
+ TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
+
+ }
}
diff --git a/java/src/test/java/com/google/protobuf/TestUtil.java b/java/src/test/java/com/google/protobuf/TestUtil.java
index 9109f419..135a1174 100644
--- a/java/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/src/test/java/com/google/protobuf/TestUtil.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -56,6 +56,11 @@ import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
import static protobuf_unittest.UnittestProto.defaultStringPieceExtension;
import static protobuf_unittest.UnittestProto.defaultCordExtension;
+import static protobuf_unittest.UnittestProto.oneofUint32Extension;
+import static protobuf_unittest.UnittestProto.oneofNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.oneofStringExtension;
+import static protobuf_unittest.UnittestProto.oneofBytesExtension;
+
import static protobuf_unittest.UnittestProto.optionalInt32Extension;
import static protobuf_unittest.UnittestProto.optionalInt64Extension;
import static protobuf_unittest.UnittestProto.optionalUint32Extension;
@@ -72,14 +77,16 @@ import static protobuf_unittest.UnittestProto.optionalBoolExtension;
import static protobuf_unittest.UnittestProto.optionalStringExtension;
import static protobuf_unittest.UnittestProto.optionalBytesExtension;
import static protobuf_unittest.UnittestProto.optionalGroupExtension;
-import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalCordExtension;
+import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension;
import static protobuf_unittest.UnittestProto.optionalForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalImportEnumExtension;
import static protobuf_unittest.UnittestProto.optionalImportMessageExtension;
import static protobuf_unittest.UnittestProto.optionalNestedEnumExtension;
-import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension;
-import static protobuf_unittest.UnittestProto.optionalImportEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalPublicImportMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension;
import static protobuf_unittest.UnittestProto.optionalStringPieceExtension;
-import static protobuf_unittest.UnittestProto.optionalCordExtension;
import static protobuf_unittest.UnittestProto.repeatedInt32Extension;
import static protobuf_unittest.UnittestProto.repeatedInt64Extension;
@@ -100,6 +107,7 @@ import static protobuf_unittest.UnittestProto.repeatedGroupExtension;
import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension;
import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension;
import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedLazyMessageExtension;
import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension;
import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension;
import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension;
@@ -145,6 +153,11 @@ import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
+
import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
@@ -162,11 +175,13 @@ import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
@@ -189,6 +204,7 @@ import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
@@ -217,13 +233,15 @@ import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestUnpackedTypes;
import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.ForeignEnum;
-import com.google.protobuf.test.UnittestImport.ImportMessage;
import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage;
import com.google.protobuf.UnittestLite.TestAllTypesLite;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
@@ -231,8 +249,9 @@ import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder;
import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
import com.google.protobuf.UnittestLite.ForeignMessageLite;
import com.google.protobuf.UnittestLite.ForeignEnumLite;
-import com.google.protobuf.UnittestImportLite.ImportMessageLite;
import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestImportLite.ImportMessageLite;
+import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
import junit.framework.Assert;
@@ -242,7 +261,7 @@ import java.io.RandomAccessFile;
/**
* Contains methods for setting all fields of {@code TestAllTypes} to
- * some vaules as well as checking that all the fields are set to those values.
+ * some values as well as checking that all the fields are set to those values.
* These are useful for testing various protocol message features, e.g.
* set all fields of a message, serialize it, parse it, and check that all
* fields are set.
@@ -275,6 +294,16 @@ public final class TestUtil {
}
/**
+ * Get a {@code TestAllTypes.Builder} with all fields set as they would be by
+ * {@link #setAllFields(TestAllTypes.Builder)}.
+ */
+ public static TestAllTypes.Builder getAllSetBuilder() {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ setAllFields(builder);
+ return builder;
+ }
+
+ /**
* Get a {@code TestAllExtensions} with all fields set as they would be by
* {@link #setAllExtensions(TestAllExtensions.Builder)}.
*/
@@ -344,6 +373,10 @@ public final class TestUtil {
ForeignMessage.newBuilder().setC(119).build());
message.setOptionalImportMessage(
ImportMessage.newBuilder().setD(120).build());
+ message.setOptionalPublicImportMessage(
+ PublicImportMessage.newBuilder().setE(126).build());
+ message.setOptionalLazyMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(127).build());
message.setOptionalNestedEnum (TestAllTypes.NestedEnum.BAZ);
message.setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ);
@@ -378,6 +411,8 @@ public final class TestUtil {
ForeignMessage.newBuilder().setC(219).build());
message.addRepeatedImportMessage(
ImportMessage.newBuilder().setD(220).build());
+ message.addRepeatedLazyMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(227).build());
message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAR);
message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAR);
@@ -411,6 +446,8 @@ public final class TestUtil {
ForeignMessage.newBuilder().setC(319).build());
message.addRepeatedImportMessage(
ImportMessage.newBuilder().setD(320).build());
+ message.addRepeatedLazyMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(327).build());
message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAZ);
message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAZ);
@@ -443,6 +480,12 @@ public final class TestUtil {
message.setDefaultStringPiece("424");
message.setDefaultCord("425");
+
+ message.setOneofUint32(601);
+ message.setOneofNestedMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(602).build());
+ message.setOneofString("603");
+ message.setOneofBytes(toBytes("604"));
}
// -------------------------------------------------------------------
@@ -476,6 +519,8 @@ public final class TestUtil {
ForeignMessage.newBuilder().setC(519).build());
message.setRepeatedImportMessage(1,
ImportMessage.newBuilder().setD(520).build());
+ message.setRepeatedLazyMessage(1,
+ TestAllTypes.NestedMessage.newBuilder().setBb(527).build());
message.setRepeatedNestedEnum (1, TestAllTypes.NestedEnum.FOO);
message.setRepeatedForeignEnum(1, ForeignEnum.FOREIGN_FOO);
@@ -541,10 +586,12 @@ public final class TestUtil {
Assert.assertEquals("115", message.getOptionalString ());
Assert.assertEquals(toBytes("116"), message.getOptionalBytes());
- Assert.assertEquals(117, message.getOptionalGroup ().getA());
- Assert.assertEquals(118, message.getOptionalNestedMessage ().getBb());
- Assert.assertEquals(119, message.getOptionalForeignMessage().getC());
- Assert.assertEquals(120, message.getOptionalImportMessage ().getD());
+ Assert.assertEquals(117, message.getOptionalGroup ().getA());
+ Assert.assertEquals(118, message.getOptionalNestedMessage ().getBb());
+ Assert.assertEquals(119, message.getOptionalForeignMessage ().getC());
+ Assert.assertEquals(120, message.getOptionalImportMessage ().getD());
+ Assert.assertEquals(126, message.getOptionalPublicImportMessage().getE());
+ Assert.assertEquals(127, message.getOptionalLazyMessage ().getBb());
Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getOptionalNestedEnum());
Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getOptionalForeignEnum());
@@ -575,6 +622,7 @@ public final class TestUtil {
Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedLazyMessageCount ());
Assert.assertEquals(2, message.getRepeatedNestedEnumCount ());
Assert.assertEquals(2, message.getRepeatedForeignEnumCount ());
Assert.assertEquals(2, message.getRepeatedImportEnumCount ());
@@ -602,6 +650,7 @@ public final class TestUtil {
Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+ Assert.assertEquals(227, message.getRepeatedLazyMessage (0).getBb());
Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
@@ -630,6 +679,7 @@ public final class TestUtil {
Assert.assertEquals(318, message.getRepeatedNestedMessage (1).getBb());
Assert.assertEquals(319, message.getRepeatedForeignMessage(1).getC());
Assert.assertEquals(320, message.getRepeatedImportMessage (1).getD());
+ Assert.assertEquals(327, message.getRepeatedLazyMessage (1).getBb());
Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getRepeatedNestedEnum (1));
Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getRepeatedForeignEnum(1));
@@ -685,6 +735,13 @@ public final class TestUtil {
Assert.assertEquals("424", message.getDefaultStringPiece());
Assert.assertEquals("425", message.getDefaultCord());
+
+ Assert.assertFalse(message.hasOneofUint32());
+ Assert.assertFalse(message.hasOneofNestedMessage());
+ Assert.assertFalse(message.hasOneofString());
+ Assert.assertTrue(message.hasOneofBytes());
+
+ Assert.assertEquals(toBytes("604"), message.getOneofBytes());
}
// -------------------------------------------------------------------
@@ -741,15 +798,19 @@ public final class TestUtil {
Assert.assertEquals(ByteString.EMPTY, message.getOptionalBytes());
// Embedded messages should also be clear.
- Assert.assertFalse(message.getOptionalGroup ().hasA());
- Assert.assertFalse(message.getOptionalNestedMessage ().hasBb());
- Assert.assertFalse(message.getOptionalForeignMessage().hasC());
- Assert.assertFalse(message.getOptionalImportMessage ().hasD());
-
- Assert.assertEquals(0, message.getOptionalGroup ().getA());
- Assert.assertEquals(0, message.getOptionalNestedMessage ().getBb());
- Assert.assertEquals(0, message.getOptionalForeignMessage().getC());
- Assert.assertEquals(0, message.getOptionalImportMessage ().getD());
+ Assert.assertFalse(message.getOptionalGroup ().hasA());
+ Assert.assertFalse(message.getOptionalNestedMessage ().hasBb());
+ Assert.assertFalse(message.getOptionalForeignMessage ().hasC());
+ Assert.assertFalse(message.getOptionalImportMessage ().hasD());
+ Assert.assertFalse(message.getOptionalPublicImportMessage().hasE());
+ Assert.assertFalse(message.getOptionalLazyMessage ().hasBb());
+
+ Assert.assertEquals(0, message.getOptionalGroup ().getA());
+ Assert.assertEquals(0, message.getOptionalNestedMessage ().getBb());
+ Assert.assertEquals(0, message.getOptionalForeignMessage ().getC());
+ Assert.assertEquals(0, message.getOptionalImportMessage ().getD());
+ Assert.assertEquals(0, message.getOptionalPublicImportMessage().getE());
+ Assert.assertEquals(0, message.getOptionalLazyMessage ().getBb());
// Enums without defaults are set to the first value in the enum.
Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum ());
@@ -780,6 +841,7 @@ public final class TestUtil {
Assert.assertEquals(0, message.getRepeatedNestedMessageCount ());
Assert.assertEquals(0, message.getRepeatedForeignMessageCount());
Assert.assertEquals(0, message.getRepeatedImportMessageCount ());
+ Assert.assertEquals(0, message.getRepeatedLazyMessageCount ());
Assert.assertEquals(0, message.getRepeatedNestedEnumCount ());
Assert.assertEquals(0, message.getRepeatedForeignEnumCount ());
Assert.assertEquals(0, message.getRepeatedImportEnumCount ());
@@ -834,6 +896,11 @@ public final class TestUtil {
Assert.assertEquals("abc", message.getDefaultStringPiece());
Assert.assertEquals("123", message.getDefaultCord());
+
+ Assert.assertFalse(message.hasOneofUint32());
+ Assert.assertFalse(message.hasOneofNestedMessage());
+ Assert.assertFalse(message.hasOneofString());
+ Assert.assertFalse(message.hasOneofBytes());
}
// -------------------------------------------------------------------
@@ -868,6 +935,7 @@ public final class TestUtil {
Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedLazyMessageCount ());
Assert.assertEquals(2, message.getRepeatedNestedEnumCount ());
Assert.assertEquals(2, message.getRepeatedForeignEnumCount ());
Assert.assertEquals(2, message.getRepeatedImportEnumCount ());
@@ -895,6 +963,7 @@ public final class TestUtil {
Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+ Assert.assertEquals(227, message.getRepeatedLazyMessage (0).getBb());
Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
@@ -924,6 +993,7 @@ public final class TestUtil {
Assert.assertEquals(518, message.getRepeatedNestedMessage (1).getBb());
Assert.assertEquals(519, message.getRepeatedForeignMessage(1).getC());
Assert.assertEquals(520, message.getRepeatedImportMessage (1).getD());
+ Assert.assertEquals(527, message.getRepeatedLazyMessage (1).getBb());
Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getRepeatedNestedEnum (1));
Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getRepeatedForeignEnum(1));
@@ -1210,6 +1280,10 @@ public final class TestUtil {
ForeignMessage.newBuilder().setC(119).build());
message.setExtension(optionalImportMessageExtension,
ImportMessage.newBuilder().setD(120).build());
+ message.setExtension(optionalPublicImportMessageExtension,
+ PublicImportMessage.newBuilder().setE(126).build());
+ message.setExtension(optionalLazyMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(127).build());
message.setExtension(optionalNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
message.setExtension(optionalForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
@@ -1244,6 +1318,8 @@ public final class TestUtil {
ForeignMessage.newBuilder().setC(219).build());
message.addExtension(repeatedImportMessageExtension,
ImportMessage.newBuilder().setD(220).build());
+ message.addExtension(repeatedLazyMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(227).build());
message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAR);
message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAR);
@@ -1277,6 +1353,8 @@ public final class TestUtil {
ForeignMessage.newBuilder().setC(319).build());
message.addExtension(repeatedImportMessageExtension,
ImportMessage.newBuilder().setD(320).build());
+ message.addExtension(repeatedLazyMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(327).build());
message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
@@ -1309,6 +1387,12 @@ public final class TestUtil {
message.setExtension(defaultStringPieceExtension, "424");
message.setExtension(defaultCordExtension, "425");
+
+ message.setExtension(oneofUint32Extension, 601);
+ message.setExtension(oneofNestedMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(602).build());
+ message.setExtension(oneofStringExtension, "603");
+ message.setExtension(oneofBytesExtension, toBytes("604"));
}
// -------------------------------------------------------------------
@@ -1343,6 +1427,8 @@ public final class TestUtil {
ForeignMessage.newBuilder().setC(519).build());
message.setExtension(repeatedImportMessageExtension, 1,
ImportMessage.newBuilder().setD(520).build());
+ message.setExtension(repeatedLazyMessageExtension, 1,
+ TestAllTypes.NestedMessage.newBuilder().setBb(527).build());
message.setExtension(repeatedNestedEnumExtension , 1, TestAllTypes.NestedEnum.FOO);
message.setExtension(repeatedForeignEnumExtension, 1, ForeignEnum.FOREIGN_FOO);
@@ -1409,10 +1495,12 @@ public final class TestUtil {
assertEqualsExactType("115", message.getExtension(optionalStringExtension ));
assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtension));
- assertEqualsExactType(117, message.getExtension(optionalGroupExtension ).getA());
- assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtension ).getBb());
- assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtension).getC());
- assertEqualsExactType(120, message.getExtension(optionalImportMessageExtension ).getD());
+ assertEqualsExactType(117, message.getExtension(optionalGroupExtension ).getA());
+ assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtension ).getBb());
+ assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtension ).getC());
+ assertEqualsExactType(120, message.getExtension(optionalImportMessageExtension ).getD());
+ assertEqualsExactType(126, message.getExtension(optionalPublicImportMessageExtension).getE());
+ assertEqualsExactType(127, message.getExtension(optionalLazyMessageExtension ).getBb());
assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
message.getExtension(optionalNestedEnumExtension));
@@ -1446,6 +1534,7 @@ public final class TestUtil {
Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtension ));
Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension ));
Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension ));
Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension ));
@@ -1473,6 +1562,7 @@ public final class TestUtil {
assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
+ assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtension , 0).getBb());
assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
message.getExtension(repeatedNestedEnumExtension, 0));
@@ -1504,6 +1594,7 @@ public final class TestUtil {
assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtension, 1).getC());
assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtension , 1).getD());
+ assertEqualsExactType(327, message.getExtension(repeatedLazyMessageExtension , 1).getBb());
assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
message.getExtension(repeatedNestedEnumExtension, 1));
@@ -1565,6 +1656,10 @@ public final class TestUtil {
assertEqualsExactType("424", message.getExtension(defaultStringPieceExtension));
assertEqualsExactType("425", message.getExtension(defaultCordExtension));
+
+ Assert.assertTrue(message.hasExtension(oneofBytesExtension));
+
+ assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtension));
}
// -------------------------------------------------------------------
@@ -1664,6 +1759,7 @@ public final class TestUtil {
Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtension ));
Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtension));
Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedLazyMessageExtension ));
Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtension ));
Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtension ));
Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtension ));
@@ -1692,6 +1788,7 @@ public final class TestUtil {
Assert.assertEquals(0, message.getExtension(repeatedNestedMessageExtension ).size());
Assert.assertEquals(0, message.getExtension(repeatedForeignMessageExtension).size());
Assert.assertEquals(0, message.getExtension(repeatedImportMessageExtension ).size());
+ Assert.assertEquals(0, message.getExtension(repeatedLazyMessageExtension ).size());
Assert.assertEquals(0, message.getExtension(repeatedNestedEnumExtension ).size());
Assert.assertEquals(0, message.getExtension(repeatedForeignEnumExtension ).size());
Assert.assertEquals(0, message.getExtension(repeatedImportEnumExtension ).size());
@@ -1749,6 +1846,11 @@ public final class TestUtil {
assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtension));
assertEqualsExactType("123", message.getExtension(defaultCordExtension));
+
+ Assert.assertFalse(message.hasExtension(oneofUint32Extension));
+ Assert.assertFalse(message.hasExtension(oneofNestedMessageExtension));
+ Assert.assertFalse(message.hasExtension(oneofStringExtension));
+ Assert.assertFalse(message.hasExtension(oneofBytesExtension));
}
// -------------------------------------------------------------------
@@ -1783,6 +1885,7 @@ public final class TestUtil {
Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtension ));
Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension ));
Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension ));
Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension ));
@@ -1810,6 +1913,7 @@ public final class TestUtil {
assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
+ assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtension , 0).getBb());
assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
message.getExtension(repeatedNestedEnumExtension, 0));
@@ -1842,6 +1946,7 @@ public final class TestUtil {
assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtension, 1).getC());
assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtension , 1).getD());
+ assertEqualsExactType(527, message.getExtension(repeatedLazyMessageExtension , 1).getBb());
assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
message.getExtension(repeatedNestedEnumExtension, 1));
@@ -1965,6 +2070,10 @@ public final class TestUtil {
ForeignMessageLite.newBuilder().setC(119).build());
message.setExtension(optionalImportMessageExtensionLite,
ImportMessageLite.newBuilder().setD(120).build());
+ message.setExtension(optionalPublicImportMessageExtensionLite,
+ PublicImportMessageLite.newBuilder().setE(126).build());
+ message.setExtension(optionalLazyMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
@@ -1999,6 +2108,8 @@ public final class TestUtil {
ForeignMessageLite.newBuilder().setC(219).build());
message.addExtension(repeatedImportMessageExtensionLite,
ImportMessageLite.newBuilder().setD(220).build());
+ message.addExtension(repeatedLazyMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR);
message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
@@ -2032,6 +2143,8 @@ public final class TestUtil {
ForeignMessageLite.newBuilder().setC(319).build());
message.addExtension(repeatedImportMessageExtensionLite,
ImportMessageLite.newBuilder().setD(320).build());
+ message.addExtension(repeatedLazyMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
@@ -2064,6 +2177,12 @@ public final class TestUtil {
message.setExtension(defaultStringPieceExtensionLite, "424");
message.setExtension(defaultCordExtensionLite, "425");
+
+ message.setExtension(oneofUint32ExtensionLite, 601);
+ message.setExtension(oneofNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
+ message.setExtension(oneofStringExtensionLite, "603");
+ message.setExtension(oneofBytesExtensionLite, toBytes("604"));
}
// -------------------------------------------------------------------
@@ -2098,6 +2217,8 @@ public final class TestUtil {
ForeignMessageLite.newBuilder().setC(519).build());
message.setExtension(repeatedImportMessageExtensionLite, 1,
ImportMessageLite.newBuilder().setD(520).build());
+ message.setExtension(repeatedLazyMessageExtensionLite, 1,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(527).build());
message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO);
message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO);
@@ -2168,6 +2289,9 @@ public final class TestUtil {
assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtensionLite).getC());
assertEqualsExactType(120, message.getExtension(optionalImportMessageExtensionLite ).getD());
+ assertEqualsExactType(126, message.getExtension(
+ optionalPublicImportMessageExtensionLite).getE());
+ assertEqualsExactType(127, message.getExtension(optionalLazyMessageExtensionLite).getBb());
assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
message.getExtension(optionalNestedEnumExtensionLite));
@@ -2201,6 +2325,7 @@ public final class TestUtil {
Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtensionLite ));
Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite ));
Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite ));
Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite ));
@@ -2228,6 +2353,7 @@ public final class TestUtil {
assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
+ assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtensionLite ,0).getBb());
assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
message.getExtension(repeatedNestedEnumExtensionLite, 0));
@@ -2259,6 +2385,7 @@ public final class TestUtil {
assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
+ assertEqualsExactType(327, message.getExtension(repeatedLazyMessageExtensionLite ,1).getBb());
assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
message.getExtension(repeatedNestedEnumExtensionLite, 1));
@@ -2320,6 +2447,10 @@ public final class TestUtil {
assertEqualsExactType("424", message.getExtension(defaultStringPieceExtensionLite));
assertEqualsExactType("425", message.getExtension(defaultCordExtensionLite));
+
+ Assert.assertTrue(message.hasExtension(oneofBytesExtensionLite));
+
+ assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtensionLite));
}
// -------------------------------------------------------------------
@@ -2348,10 +2479,12 @@ public final class TestUtil {
Assert.assertFalse(message.hasExtension(optionalStringExtensionLite ));
Assert.assertFalse(message.hasExtension(optionalBytesExtensionLite ));
- Assert.assertFalse(message.hasExtension(optionalGroupExtensionLite ));
- Assert.assertFalse(message.hasExtension(optionalNestedMessageExtensionLite ));
- Assert.assertFalse(message.hasExtension(optionalForeignMessageExtensionLite));
- Assert.assertFalse(message.hasExtension(optionalImportMessageExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalGroupExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalNestedMessageExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalForeignMessageExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalImportMessageExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalPublicImportMessageExtensionLite));
+ Assert.assertFalse(message.hasExtension(optionalLazyMessageExtensionLite ));
Assert.assertFalse(message.hasExtension(optionalNestedEnumExtensionLite ));
Assert.assertFalse(message.hasExtension(optionalForeignEnumExtensionLite));
@@ -2378,15 +2511,20 @@ public final class TestUtil {
assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtensionLite));
// Embedded messages should also be clear.
- Assert.assertFalse(message.getExtension(optionalGroupExtensionLite ).hasA());
- Assert.assertFalse(message.getExtension(optionalNestedMessageExtensionLite ).hasBb());
- Assert.assertFalse(message.getExtension(optionalForeignMessageExtensionLite).hasC());
- Assert.assertFalse(message.getExtension(optionalImportMessageExtensionLite ).hasD());
+ Assert.assertFalse(message.getExtension(optionalGroupExtensionLite ).hasA());
+ Assert.assertFalse(message.getExtension(optionalNestedMessageExtensionLite ).hasBb());
+ Assert.assertFalse(message.getExtension(optionalForeignMessageExtensionLite ).hasC());
+ Assert.assertFalse(message.getExtension(optionalImportMessageExtensionLite ).hasD());
+ Assert.assertFalse(message.getExtension(optionalPublicImportMessageExtensionLite).hasE());
+ Assert.assertFalse(message.getExtension(optionalLazyMessageExtensionLite ).hasBb());
assertEqualsExactType(0, message.getExtension(optionalGroupExtensionLite ).getA());
assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtensionLite).getC());
assertEqualsExactType(0, message.getExtension(optionalImportMessageExtensionLite ).getD());
+ assertEqualsExactType(0, message.getExtension(
+ optionalPublicImportMessageExtensionLite).getE());
+ assertEqualsExactType(0, message.getExtension(optionalLazyMessageExtensionLite ).getBb());
// Enums without defaults are set to the first value in the enum.
assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
@@ -2420,6 +2558,7 @@ public final class TestUtil {
Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtensionLite));
Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedLazyMessageExtensionLite ));
Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtensionLite ));
Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtensionLite ));
Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtensionLite ));
@@ -2477,6 +2616,11 @@ public final class TestUtil {
assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtensionLite));
assertEqualsExactType("123", message.getExtension(defaultCordExtensionLite));
+
+ Assert.assertFalse(message.hasExtension(oneofUint32ExtensionLite));
+ Assert.assertFalse(message.hasExtension(oneofNestedMessageExtensionLite));
+ Assert.assertFalse(message.hasExtension(oneofStringExtensionLite));
+ Assert.assertFalse(message.hasExtension(oneofBytesExtensionLite));
}
// -------------------------------------------------------------------
@@ -2511,6 +2655,7 @@ public final class TestUtil {
Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtensionLite ));
Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite ));
Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite ));
Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite ));
@@ -2538,6 +2683,7 @@ public final class TestUtil {
assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
+ assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtensionLite ,0).getBb());
assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
message.getExtension(repeatedNestedEnumExtensionLite, 0));
@@ -2570,6 +2716,7 @@ public final class TestUtil {
assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
+ assertEqualsExactType(527, message.getExtension(repeatedLazyMessageExtensionLite ,1).getBb());
assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
message.getExtension(repeatedNestedEnumExtensionLite, 1));
@@ -2661,6 +2808,82 @@ public final class TestUtil {
message.getExtension(packedEnumExtensionLite, 1));
}
+ // ===================================================================
+ // oneof
+ public static void setOneof(TestOneof2.Builder message) {
+ message.setFooLazyMessage(
+ TestOneof2.NestedMessage.newBuilder().setQuxInt(100).build());
+ message.setBarString("101");
+ message.setBazInt(102);
+ message.setBazString("103");
+ }
+
+ public static void assertOneofSet(TestOneof2 message) {
+ Assert.assertTrue(message.hasFooLazyMessage ());
+ Assert.assertTrue(message.getFooLazyMessage().hasQuxInt());
+
+ Assert.assertTrue(message.hasBarString());
+ Assert.assertTrue(message.hasBazInt ());
+ Assert.assertTrue(message.hasBazString());
+
+ Assert.assertEquals(100 , message.getFooLazyMessage().getQuxInt());
+ Assert.assertEquals("101", message.getBarString ());
+ Assert.assertEquals(102 , message.getBazInt ());
+ Assert.assertEquals("103", message.getBazString ());
+ }
+
+ public static void assertAtMostOneFieldSetOneof(TestOneof2 message) {
+ int count = 0;
+ if (message.hasFooInt()) { ++count; }
+ if (message.hasFooString()) { ++count; }
+ if (message.hasFooCord()) { ++count; }
+ if (message.hasFooStringPiece()) { ++count; }
+ if (message.hasFooBytes()) { ++count; }
+ if (message.hasFooEnum()) { ++count; }
+ if (message.hasFooMessage()) { ++count; }
+ if (message.hasFooGroup()) { ++count; }
+ if (message.hasFooLazyMessage()) { ++count; }
+ Assert.assertTrue(count <= 1);
+
+ count = 0;
+ if (message.hasBarInt()) { ++count; }
+ if (message.hasBarString()) { ++count; }
+ if (message.hasBarCord()) { ++count; }
+ if (message.hasBarStringPiece()) { ++count; }
+ if (message.hasBarBytes()) { ++count; }
+ if (message.hasBarEnum()) { ++count; }
+ Assert.assertTrue(count <= 1);
+
+ switch (message.getFooCase()) {
+ case FOO_INT:
+ Assert.assertTrue(message.hasFooInt());
+ break;
+ case FOO_STRING:
+ Assert.assertTrue(message.hasFooString());
+ break;
+ case FOO_CORD:
+ Assert.assertTrue(message.hasFooCord());
+ break;
+ case FOO_BYTES:
+ Assert.assertTrue(message.hasFooBytes());
+ break;
+ case FOO_ENUM:
+ Assert.assertTrue(message.hasFooEnum());
+ break;
+ case FOO_MESSAGE:
+ Assert.assertTrue(message.hasFooMessage());
+ break;
+ case FOOGROUP:
+ Assert.assertTrue(message.hasFooGroup());
+ break;
+ case FOO_LAZY_MESSAGE:
+ Assert.assertTrue(message.hasFooLazyMessage());
+ break;
+ case FOO_NOT_SET:
+ break;
+ }
+ }
+
// =================================================================
/**
@@ -2674,18 +2897,21 @@ public final class TestUtil {
private final Descriptors.FileDescriptor file;
private final Descriptors.FileDescriptor importFile;
+ private final Descriptors.FileDescriptor publicImportFile;
private final Descriptors.Descriptor optionalGroup;
private final Descriptors.Descriptor repeatedGroup;
private final Descriptors.Descriptor nestedMessage;
private final Descriptors.Descriptor foreignMessage;
private final Descriptors.Descriptor importMessage;
+ private final Descriptors.Descriptor publicImportMessage;
private final Descriptors.FieldDescriptor groupA;
private final Descriptors.FieldDescriptor repeatedGroupA;
private final Descriptors.FieldDescriptor nestedB;
private final Descriptors.FieldDescriptor foreignC;
private final Descriptors.FieldDescriptor importD;
+ private final Descriptors.FieldDescriptor importE;
private final Descriptors.EnumDescriptor nestedEnum;
private final Descriptors.EnumDescriptor foreignEnum;
@@ -2722,6 +2948,7 @@ public final class TestUtil {
this.file = baseDescriptor.getFile();
Assert.assertEquals(1, file.getDependencies().size());
this.importFile = file.getDependencies().get(0);
+ this.publicImportFile = importFile.getDependencies().get(0);
Descriptors.Descriptor testAllTypes;
if (baseDescriptor.getName() == "TestAllTypes") {
@@ -2748,6 +2975,8 @@ public final class TestUtil {
this.nestedMessage = testAllTypes.findNestedTypeByName("NestedMessage");
this.foreignMessage = file.findMessageTypeByName("ForeignMessage");
this.importMessage = importFile.findMessageTypeByName("ImportMessage");
+ this.publicImportMessage = publicImportFile.findMessageTypeByName(
+ "PublicImportMessage");
this.nestedEnum = testAllTypes.findEnumTypeByName("NestedEnum");
this.foreignEnum = file.findEnumTypeByName("ForeignEnum");
@@ -2765,6 +2994,7 @@ public final class TestUtil {
this.nestedB = nestedMessage .findFieldByName("bb");
this.foreignC = foreignMessage.findFieldByName("c");
this.importD = importMessage .findFieldByName("d");
+ this.importE = publicImportMessage.findFieldByName("e");
this.nestedFoo = nestedEnum.findValueByName("FOO");
this.nestedBar = nestedEnum.findValueByName("BAR");
this.nestedBaz = nestedEnum.findValueByName("BAZ");
@@ -2783,6 +3013,7 @@ public final class TestUtil {
Assert.assertNotNull(nestedB );
Assert.assertNotNull(foreignC );
Assert.assertNotNull(importD );
+ Assert.assertNotNull(importE );
Assert.assertNotNull(nestedFoo );
Assert.assertNotNull(nestedBar );
Assert.assertNotNull(nestedBaz );
@@ -2819,8 +3050,8 @@ public final class TestUtil {
return parent.newBuilderForField(field);
} else {
ExtensionRegistry.ExtensionInfo extension =
- extensionRegistry.findExtensionByNumber(field.getContainingType(),
- field.getNumber());
+ extensionRegistry.findImmutableExtensionByNumber(
+ field.getContainingType(), field.getNumber());
Assert.assertNotNull(extension);
Assert.assertNotNull(extension.defaultInstance);
return extension.defaultInstance.newBuilderForType();
@@ -2863,6 +3094,12 @@ public final class TestUtil {
message.setField(f("optional_import_message"),
newBuilderForField(message, f("optional_import_message"))
.setField(importD, 120).build());
+ message.setField(f("optional_public_import_message"),
+ newBuilderForField(message, f("optional_public_import_message"))
+ .setField(importE, 126).build());
+ message.setField(f("optional_lazy_message"),
+ newBuilderForField(message, f("optional_lazy_message"))
+ .setField(nestedB, 127).build());
message.setField(f("optional_nested_enum" ), nestedBaz);
message.setField(f("optional_foreign_enum"), foreignBaz);
@@ -2901,6 +3138,9 @@ public final class TestUtil {
message.addRepeatedField(f("repeated_import_message"),
newBuilderForField(message, f("repeated_import_message"))
.setField(importD, 220).build());
+ message.addRepeatedField(f("repeated_lazy_message"),
+ newBuilderForField(message, f("repeated_lazy_message"))
+ .setField(nestedB, 227).build());
message.addRepeatedField(f("repeated_nested_enum" ), nestedBar);
message.addRepeatedField(f("repeated_foreign_enum"), foreignBar);
@@ -2938,6 +3178,9 @@ public final class TestUtil {
message.addRepeatedField(f("repeated_import_message"),
newBuilderForField(message, f("repeated_import_message"))
.setField(importD, 320).build());
+ message.addRepeatedField(f("repeated_lazy_message"),
+ newBuilderForField(message, f("repeated_lazy_message"))
+ .setField(nestedB, 327).build());
message.addRepeatedField(f("repeated_nested_enum" ), nestedBaz);
message.addRepeatedField(f("repeated_foreign_enum"), foreignBaz);
@@ -2970,6 +3213,13 @@ public final class TestUtil {
message.setField(f("default_string_piece" ), "424");
message.setField(f("default_cord" ), "425");
+
+ message.setField(f("oneof_uint32" ), 601);
+ message.setField(f("oneof_nested_message"),
+ newBuilderForField(message, f("oneof_nested_message"))
+ .setField(nestedB, 602).build());
+ message.setField(f("oneof_string" ), "603");
+ message.setField(f("oneof_bytes" ), toBytes("604"));
}
// -------------------------------------------------------------------
@@ -3008,6 +3258,9 @@ public final class TestUtil {
message.setRepeatedField(f("repeated_import_message"), 1,
newBuilderForField(message, f("repeated_import_message"))
.setField(importD, 520).build());
+ message.setRepeatedField(f("repeated_lazy_message"), 1,
+ newBuilderForField(message, f("repeated_lazy_message"))
+ .setField(nestedB, 527).build());
message.setRepeatedField(f("repeated_nested_enum" ), 1, nestedFoo);
message.setRepeatedField(f("repeated_foreign_enum"), 1, foreignFoo);
@@ -3092,6 +3345,12 @@ public final class TestUtil {
Assert.assertEquals(120,
((Message)message.getField(f("optional_import_message")))
.getField(importD));
+ Assert.assertEquals(126,
+ ((Message)message.getField(f("optional_public_import_message")))
+ .getField(importE));
+ Assert.assertEquals(127,
+ ((Message)message.getField(f("optional_lazy_message")))
+ .getField(nestedB));
Assert.assertEquals( nestedBaz, message.getField(f("optional_nested_enum" )));
Assert.assertEquals(foreignBaz, message.getField(f("optional_foreign_enum")));
@@ -3122,6 +3381,7 @@ public final class TestUtil {
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_lazy_message" )));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum" )));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum" )));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum" )));
@@ -3157,6 +3417,9 @@ public final class TestUtil {
Assert.assertEquals(220,
((Message)message.getRepeatedField(f("repeated_import_message"), 0))
.getField(importD));
+ Assert.assertEquals(227,
+ ((Message)message.getRepeatedField(f("repeated_lazy_message"), 0))
+ .getField(nestedB));
Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
@@ -3193,6 +3456,9 @@ public final class TestUtil {
Assert.assertEquals(320,
((Message)message.getRepeatedField(f("repeated_import_message"), 1))
.getField(importD));
+ Assert.assertEquals(327,
+ ((Message)message.getRepeatedField(f("repeated_lazy_message"), 1))
+ .getField(nestedB));
Assert.assertEquals( nestedBaz, message.getRepeatedField(f("repeated_nested_enum" ),1));
Assert.assertEquals(foreignBaz, message.getRepeatedField(f("repeated_foreign_enum"),1));
@@ -3248,6 +3514,24 @@ public final class TestUtil {
Assert.assertEquals("424", message.getField(f("default_string_piece")));
Assert.assertEquals("425", message.getField(f("default_cord")));
+
+ Assert.assertTrue(message.hasField(f("oneof_bytes")));
+ Assert.assertEquals(toBytes("604"), message.getField(f("oneof_bytes")));
+
+ if (extensionRegistry == null) {
+ Assert.assertFalse(message.hasField(f("oneof_uint32")));
+ Assert.assertFalse(message.hasField(f("oneof_nested_message")));
+ Assert.assertFalse(message.hasField(f("oneof_string")));
+ } else {
+ Assert.assertTrue(message.hasField(f("oneof_uint32")));
+ Assert.assertTrue(message.hasField(f("oneof_nested_message")));
+ Assert.assertTrue(message.hasField(f("oneof_string")));
+ Assert.assertEquals(601, message.getField(f("oneof_uint32")));
+ Assert.assertEquals(602,
+ ((MessageOrBuilder) message.getField(f("oneof_nested_message")))
+ .getField(nestedB));
+ Assert.assertEquals("603", message.getField(f("oneof_string")));
+ }
}
// -------------------------------------------------------------------
@@ -3316,6 +3600,12 @@ public final class TestUtil {
Assert.assertFalse(
((Message)message.getField(f("optional_import_message")))
.hasField(importD));
+ Assert.assertFalse(
+ ((Message)message.getField(f("optional_public_import_message")))
+ .hasField(importE));
+ Assert.assertFalse(
+ ((Message)message.getField(f("optional_lazy_message")))
+ .hasField(nestedB));
Assert.assertEquals(0,
((Message)message.getField(f("optionalgroup"))).getField(groupA));
@@ -3328,6 +3618,12 @@ public final class TestUtil {
Assert.assertEquals(0,
((Message)message.getField(f("optional_import_message")))
.getField(importD));
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optional_public_import_message")))
+ .getField(importE));
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optional_lazy_message")))
+ .getField(nestedB));
// Enums without defaults are set to the first value in the enum.
Assert.assertEquals( nestedFoo, message.getField(f("optional_nested_enum" )));
@@ -3358,6 +3654,7 @@ public final class TestUtil {
Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_message" )));
Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_message")));
Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_message" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_lazy_message" )));
Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_enum" )));
Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_enum" )));
Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_enum" )));
@@ -3412,6 +3709,15 @@ public final class TestUtil {
Assert.assertEquals("abc", message.getField(f("default_string_piece")));
Assert.assertEquals("123", message.getField(f("default_cord")));
+
+ Assert.assertFalse(message.hasField(f("oneof_uint32")));
+ Assert.assertFalse(message.hasField(f("oneof_nested_message")));
+ Assert.assertFalse(message.hasField(f("oneof_string")));
+ Assert.assertFalse(message.hasField(f("oneof_bytes")));
+
+ Assert.assertEquals(0, message.getField(f("oneof_uint32")));
+ Assert.assertEquals("", message.getField(f("oneof_string")));
+ Assert.assertEquals(toBytes(""), message.getField(f("oneof_bytes")));
}
@@ -3442,6 +3748,7 @@ public final class TestUtil {
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_lazy_message" )));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum" )));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum" )));
Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum" )));
@@ -3477,6 +3784,9 @@ public final class TestUtil {
Assert.assertEquals(220,
((Message)message.getRepeatedField(f("repeated_import_message"), 0))
.getField(importD));
+ Assert.assertEquals(227,
+ ((Message)message.getRepeatedField(f("repeated_lazy_message"), 0))
+ .getField(nestedB));
Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
@@ -3513,6 +3823,9 @@ public final class TestUtil {
Assert.assertEquals(520,
((Message)message.getRepeatedField(f("repeated_import_message"), 1))
.getField(importD));
+ Assert.assertEquals(527,
+ ((Message)message.getRepeatedField(f("repeated_lazy_message"), 1))
+ .getField(nestedB));
Assert.assertEquals( nestedFoo, message.getRepeatedField(f("repeated_nested_enum" ),1));
Assert.assertEquals(foreignFoo, message.getRepeatedField(f("repeated_foreign_enum"),1));
@@ -3766,7 +4079,7 @@ public final class TestUtil {
*/
public static ByteString getGoldenMessage() {
if (goldenMessage == null) {
- goldenMessage = readBytesFromFile("golden_message");
+ goldenMessage = readBytesFromFile("golden_message_oneof_implemented");
}
return goldenMessage;
}
diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java
index 47690d1f..eba06ca0 100644
--- a/java/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -31,6 +31,7 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
import protobuf_unittest.UnittestMset.TestMessageSet;
import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
@@ -39,6 +40,7 @@ import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestOneof2;
import junit.framework.TestCase;
@@ -64,14 +66,14 @@ public class TextFormatTest extends TestCase {
+ "and \\t tabs and \\001 slashes \\\\";
private static String allFieldsSetText = TestUtil.readTextFromFile(
- "text_format_unittest_data.txt");
+ "text_format_unittest_data_oneof_implemented.txt");
private static String allExtensionsSetText = TestUtil.readTextFromFile(
"text_format_unittest_extensions_data.txt");
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" +
@@ -99,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" +
@@ -109,6 +111,24 @@ public class TextFormatTest extends TestCase {
" str: \"foo\"\n" +
"}\n";
+ private String messageSetTextWithRepeatedExtension =
+ "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+ " i: 123\n" +
+ "}\n" +
+ "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+ " i: 456\n" +
+ "}\n";
+
+
+ private final TextFormat.Parser parserWithOverwriteForbidden =
+ TextFormat.Parser.newBuilder()
+ .setSingularOverwritePolicy(
+ SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
+ .build();
+
+ private final TextFormat.Parser defaultParser =
+ TextFormat.Parser.newBuilder().build();
+
/** Print TestAllTypes and compare with golden file. */
public void testPrintMessage() throws Exception {
String javaText = TextFormat.printToString(TestUtil.getAllSet());
@@ -121,6 +141,18 @@ public class TextFormatTest extends TestCase {
assertEquals(allFieldsSetText, javaText);
}
+ /** Print TestAllTypes as Builder and compare with golden file. */
+ public void testPrintMessageBuilder() throws Exception {
+ String javaText = TextFormat.printToString(TestUtil.getAllSetBuilder());
+
+ // Java likes to add a trailing ".0" to floats and doubles. C printf
+ // (with %g format) does not. Our golden files are used for both
+ // C++ and Java TextFormat classes, so we need to conform.
+ javaText = javaText.replace(".0\n", "\n");
+
+ assertEquals(allFieldsSetText, javaText);
+ }
+
/** Print TestAllExtensions and compare with golden file. */
public void testPrintExtensions() throws Exception {
String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet());
@@ -238,8 +270,8 @@ public class TextFormatTest extends TestCase {
.addRepeatedInt32 (1 << 31)
.addRepeatedUint32(1 << 31)
- .addRepeatedInt64 (1l << 63)
- .addRepeatedUint64(1l << 63)
+ .addRepeatedInt64 (1L << 63)
+ .addRepeatedUint64(1L << 63)
// Floats of various precisions and exponents.
.addRepeatedDouble(123)
@@ -359,6 +391,40 @@ public class TextFormatTest extends TestCase {
TestMessageSetExtension2.messageSetExtension));
assertEquals("foo", messageSet.getExtension(
TestMessageSetExtension2.messageSetExtension).getStr());
+
+ builder = TestMessageSet.newBuilder();
+ TextFormat.merge(messageSetTextWithRepeatedExtension, extensionRegistry,
+ builder);
+ messageSet = builder.build();
+ assertEquals(456, messageSet.getExtension(
+ TestMessageSetExtension1.messageSetExtension).getI());
+ }
+
+ public void testParseMessageSetWithOverwriteForbidden() throws Exception {
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+ extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+ extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+ TestMessageSet.Builder builder = TestMessageSet.newBuilder();
+ parserWithOverwriteForbidden.merge(
+ messageSetText, extensionRegistry, builder);
+ TestMessageSet messageSet = builder.build();
+ assertEquals(123, messageSet.getExtension(
+ TestMessageSetExtension1.messageSetExtension).getI());
+ assertEquals("foo", messageSet.getExtension(
+ TestMessageSetExtension2.messageSetExtension).getStr());
+
+ builder = TestMessageSet.newBuilder();
+ try {
+ parserWithOverwriteForbidden.merge(
+ messageSetTextWithRepeatedExtension, extensionRegistry, builder);
+ fail("expected parse exception");
+ } catch (TextFormat.ParseException e) {
+ assertEquals("6:1: Non-repeated field "
+ + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
+ + " cannot be overwritten.",
+ e.getMessage());
+ }
}
public void testParseNumericEnum() throws Exception {
@@ -395,12 +461,33 @@ public class TextFormatTest extends TestCase {
}
}
+
+ private void assertParseErrorWithOverwriteForbidden(String error,
+ String text) {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ try {
+ parserWithOverwriteForbidden.merge(
+ text, TestUtil.getExtensionRegistry(), builder);
+ fail("Expected parse exception.");
+ } catch (TextFormat.ParseException e) {
+ assertEquals(error, e.getMessage());
+ }
+ }
+
+ private TestAllTypes assertParseSuccessWithOverwriteForbidden(
+ String text) throws TextFormat.ParseException {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ parserWithOverwriteForbidden.merge(
+ text, TestUtil.getExtensionRegistry(), builder);
+ return builder.build();
+ }
+
public void testParseErrors() throws Exception {
assertParseError(
"1:16: Expected \":\".",
"optional_int32 123");
assertParseError(
- "1:23: Expected identifier.",
+ "1:23: Expected identifier. Found '?'",
"optional_nested_enum: ?");
assertParseError(
"1:18: Couldn't parse integer: Number must be positive: -1",
@@ -457,10 +544,10 @@ public class TextFormatTest extends TestCase {
// Delimiters must match.
assertParseError(
- "1:22: Expected identifier.",
+ "1:22: Expected identifier. Found '}'",
"OptionalGroup < a: 1 }");
assertParseError(
- "1:22: Expected identifier.",
+ "1:22: Expected identifier. Found '>'",
"OptionalGroup { a: 1 >");
}
@@ -468,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\\\'\"",
@@ -749,4 +836,170 @@ public class TextFormatTest extends TestCase {
+ " 0xabcdef1234567890",
TextFormat.shortDebugString(makeUnknownFieldSet()));
}
+
+ public void testPrintToUnicodeString() throws Exception {
+ assertEquals(
+ "optional_string: \"abc\u3042efg\"\n" +
+ "optional_bytes: \"\\343\\201\\202\"\n" +
+ "repeated_string: \"\u3093XYZ\"\n",
+ TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+ .setOptionalString("abc\u3042efg")
+ .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
+ .addRepeatedString("\u3093XYZ")
+ .build()));
+
+ // Double quotes and backslashes should be escaped
+ assertEquals(
+ "optional_string: \"a\\\\bc\\\"ef\\\"g\"\n",
+ TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+ .setOptionalString("a\\bc\"ef\"g")
+ .build()));
+
+ // Test escaping roundtrip
+ TestAllTypes message = TestAllTypes.newBuilder()
+ .setOptionalString("a\\bc\\\"ef\"g")
+ .build();
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(TextFormat.printToUnicodeString(message), builder);
+ assertEquals(message.getOptionalString(), builder.getOptionalString());
+ }
+
+ public void testPrintToUnicodeStringWithNewlines() throws Exception {
+ // No newlines at start and end
+ assertEquals("optional_string: \"test newlines\\n\\nin\\nstring\"\n",
+ TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+ .setOptionalString("test newlines\n\nin\nstring")
+ .build()));
+
+ // Newlines at start and end
+ assertEquals("optional_string: \"\\ntest\\nnewlines\\n\\nin\\nstring\\n\"\n",
+ TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+ .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
+ .build()));
+
+ // Strings with 0, 1 and 2 newlines.
+ assertEquals("optional_string: \"\"\n",
+ TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+ .setOptionalString("")
+ .build()));
+ assertEquals("optional_string: \"\\n\"\n",
+ TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+ .setOptionalString("\n")
+ .build()));
+ assertEquals("optional_string: \"\\n\\n\"\n",
+ TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+ .setOptionalString("\n\n")
+ .build()));
+
+ // Test escaping roundtrip
+ TestAllTypes message = TestAllTypes.newBuilder()
+ .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
+ .build();
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(TextFormat.printToUnicodeString(message), builder);
+ assertEquals(message.getOptionalString(), builder.getOptionalString());
+ }
+
+ public void testPrintToUnicodeString_unknown() {
+ assertEquals(
+ "1: \"\\343\\201\\202\"\n",
+ TextFormat.printToUnicodeString(UnknownFieldSet.newBuilder()
+ .addField(1,
+ UnknownFieldSet.Field.newBuilder()
+ .addLengthDelimited(bytes(0xe3, 0x81, 0x82)).build())
+ .build()));
+ }
+
+
+ public void testParseNonRepeatedFields() throws Exception {
+ assertParseSuccessWithOverwriteForbidden(
+ "repeated_int32: 1\n" +
+ "repeated_int32: 2\n");
+ assertParseSuccessWithOverwriteForbidden(
+ "RepeatedGroup { a: 1 }\n" +
+ "RepeatedGroup { a: 2 }\n");
+ assertParseSuccessWithOverwriteForbidden(
+ "repeated_nested_message { bb: 1 }\n" +
+ "repeated_nested_message { bb: 2 }\n");
+ assertParseErrorWithOverwriteForbidden(
+ "3:17: Non-repeated field " +
+ "\"protobuf_unittest.TestAllTypes.optional_int32\" " +
+ "cannot be overwritten.",
+ "optional_int32: 1\n" +
+ "optional_bool: true\n" +
+ "optional_int32: 1\n");
+ assertParseErrorWithOverwriteForbidden(
+ "2:17: Non-repeated field " +
+ "\"protobuf_unittest.TestAllTypes.optionalgroup\" " +
+ "cannot be overwritten.",
+ "OptionalGroup { a: 1 }\n" +
+ "OptionalGroup { }\n");
+ assertParseErrorWithOverwriteForbidden(
+ "2:33: Non-repeated field " +
+ "\"protobuf_unittest.TestAllTypes.optional_nested_message\" " +
+ "cannot be overwritten.",
+ "optional_nested_message { }\n" +
+ "optional_nested_message { bb: 3 }\n");
+ assertParseErrorWithOverwriteForbidden(
+ "2:16: Non-repeated field " +
+ "\"protobuf_unittest.TestAllTypes.default_int32\" " +
+ "cannot be overwritten.",
+ "default_int32: 41\n" + // the default value
+ "default_int32: 41\n");
+ assertParseErrorWithOverwriteForbidden(
+ "2:17: Non-repeated field " +
+ "\"protobuf_unittest.TestAllTypes.default_string\" " +
+ "cannot be overwritten.",
+ "default_string: \"zxcv\"\n" +
+ "default_string: \"asdf\"\n");
+ }
+
+ public void testParseShortRepeatedFormOfRepeatedFields() throws Exception {
+ assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR]");
+ assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n");
+ assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n");
+ assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n");
+ }
+
+ public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
+ assertParseErrorWithOverwriteForbidden(
+ "1:17: Couldn't parse integer: For input string: \"[\"",
+ "optional_int32: [1]\n");
+ }
+
+ // =======================================================================
+ // test oneof
+
+ public void testOneofTextFormat() throws Exception {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestUtil.setOneof(builder);
+ TestOneof2 message = builder.build();
+ TestOneof2.Builder dest = TestOneof2.newBuilder();
+ TextFormat.merge(TextFormat.printToUnicodeString(message), dest);
+ TestUtil.assertOneofSet(dest.build());
+ }
+
+ public void testOneofOverwriteForbidden() throws Exception {
+ String input = "foo_string: \"stringvalue\" foo_int: 123";
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ try {
+ parserWithOverwriteForbidden.merge(
+ input, TestUtil.getExtensionRegistry(), builder);
+ fail("Expected parse exception.");
+ } catch (TextFormat.ParseException e) {
+ assertEquals("1:36: Field \"protobuf_unittest.TestOneof2.foo_int\""
+ + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
+ + " another member of oneof \"foo\".", e.getMessage());
+ }
+ }
+
+ public void testOneofOverwriteAllowed() throws Exception {
+ String input = "foo_string: \"stringvalue\" foo_int: 123";
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ defaultParser.merge(input, TestUtil.getExtensionRegistry(), builder);
+ // Only the last value sticks.
+ TestOneof2 oneof = builder.build();
+ assertFalse(oneof.hasFooString());
+ assertTrue(oneof.hasFooInt());
+ }
}
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..cec3da1e
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
@@ -0,0 +1,316 @@
+// 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;
+
+/**
+ * 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() throws Exception {
+ try {
+ Foo.parseFrom("this is a malformed protocol buffer".getBytes("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/UnknownFieldSetTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
index ea088b32..93a5ee22 100644
--- a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -31,10 +31,13 @@
package com.google.protobuf;
import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
import junit.framework.TestCase;
@@ -204,6 +207,13 @@ public class UnknownFieldSetTest extends TestCase {
TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
assertEquals(0, message.getSerializedSize());
}
+
+ public void testClearField() throws Exception {
+ int fieldNumber = unknownFields.asMap().keySet().iterator().next();
+ UnknownFieldSet fields =
+ UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clearField(fieldNumber).build();
+ assertFalse(fields.hasField(fieldNumber));
+ }
public void testParseKnownAndUnknown() throws Exception {
// Test mixing known and unknown fields when parsing.
@@ -434,4 +444,210 @@ public class UnknownFieldSetTest extends TestCase {
assertEquals(copy, set);
assertEquals(set.hashCode(), copy.hashCode());
}
+
+ // =================================================================
+
+ public void testSerializeLite() throws Exception {
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+ assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize());
+ ByteString data = emptyMessageLite.toByteString();
+ TestAllTypes message = TestAllTypes.parseFrom(data);
+ TestUtil.assertAllFieldsSet(message);
+ assertEquals(allFieldsData, data);
+ }
+
+ public void testAllExtensionsLite() throws Exception {
+ TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
+ ByteString allExtensionsData = allExtensions.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.PARSER.parseFrom(allExtensionsData);
+ ByteString data = emptyMessageLite.toByteString();
+ TestAllExtensions message =
+ TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+ TestUtil.assertAllExtensionsSet(message);
+ assertEquals(allExtensionsData, data);
+ }
+
+ public void testAllPackedFieldsLite() throws Exception {
+ TestPackedTypes allPackedFields = TestUtil.getPackedSet();
+ ByteString allPackedData = allPackedFields.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData);
+ ByteString data = emptyMessageLite.toByteString();
+ TestPackedTypes message =
+ TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry());
+ TestUtil.assertPackedFieldsSet(message);
+ assertEquals(allPackedData, data);
+ }
+
+ public void testAllPackedExtensionsLite() throws Exception {
+ TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet();
+ ByteString allPackedExtensionsData = allPackedExtensions.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData);
+ ByteString data = emptyMessageLite.toByteString();
+ TestPackedExtensions message =
+ TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+ TestUtil.assertPackedExtensionsSet(message);
+ assertEquals(allPackedExtensionsData, data);
+ }
+
+ public void testCopyFromLite() throws Exception {
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+ UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+ UnittestLite.TestEmptyMessageLite.newBuilder()
+ .mergeFrom(emptyMessageLite).build();
+ assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString());
+ }
+
+ public void testMergeFromLite() throws Exception {
+ TestAllTypes message1 = TestAllTypes.newBuilder()
+ .setOptionalInt32(1)
+ .setOptionalString("foo")
+ .addRepeatedString("bar")
+ .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ)
+ .build();
+
+ TestAllTypes message2 = TestAllTypes.newBuilder()
+ .setOptionalInt64(2)
+ .setOptionalString("baz")
+ .addRepeatedString("qux")
+ .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ)
+ .build();
+
+ ByteString data1 = message1.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+ UnittestLite.TestEmptyMessageLite.parseFrom(data1);
+ ByteString data2 = message2.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+ UnittestLite.TestEmptyMessageLite.parseFrom(data2);
+
+ message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build();
+ emptyMessageLite1 = UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1)
+ .mergeFrom(emptyMessageLite2).build();
+
+ data1 = emptyMessageLite1.toByteString();
+ message2 = TestAllTypes.parseFrom(data1);
+
+ assertEquals(message1, message2);
+ }
+
+ public void testWrongTypeTreatedAsUnknownLite() throws Exception {
+ // Test that fields of the wrong wire type are treated like unknown fields
+ // when parsing.
+
+ ByteString bizarroData = getBizarroData();
+ TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+ ByteString data = emptyMessageLite.toByteString();
+ TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data);
+
+ assertEquals(allTypesMessage.toString(), allTypesMessage2.toString());
+ }
+
+ public void testUnknownExtensionsLite() throws Exception {
+ // Make sure fields are properly parsed to the UnknownFieldSet even when
+ // they are declared as extension numbers.
+
+ UnittestLite.TestEmptyMessageWithExtensionsLite message =
+ UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData);
+
+ assertEquals(allFieldsData, message.toByteString());
+ }
+
+ public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception {
+ // Test that fields of the wrong wire type are treated like unknown fields
+ // when parsing extensions.
+
+ ByteString bizarroData = getBizarroData();
+ TestAllExtensions allExtensionsMessage =
+ TestAllExtensions.parseFrom(bizarroData);
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+
+ // All fields should have been interpreted as unknown, so the byte strings
+ // should be the same.
+ assertEquals(emptyMessageLite.toByteString(),
+ allExtensionsMessage.toByteString());
+ }
+
+ public void testParseUnknownEnumValueLite() throws Exception {
+ Descriptors.FieldDescriptor singularField =
+ TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
+ Descriptors.FieldDescriptor repeatedField =
+ TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
+ assertNotNull(singularField);
+ assertNotNull(repeatedField);
+
+ ByteString data =
+ UnknownFieldSet.newBuilder()
+ .addField(singularField.getNumber(),
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
+ .addVarint(5) // not valid
+ .build())
+ .addField(repeatedField.getNumber(),
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
+ .addVarint(4) // not valid
+ .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
+ .addVarint(6) // not valid
+ .build())
+ .build()
+ .toByteString();
+
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(data);
+ data = emptyMessageLite.toByteString();
+
+ {
+ TestAllTypes message = TestAllTypes.parseFrom(data);
+ assertEquals(TestAllTypes.NestedEnum.BAR,
+ message.getOptionalNestedEnum());
+ assertEquals(
+ Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+ message.getRepeatedNestedEnumList());
+ assertEquals(Arrays.asList(5L),
+ message.getUnknownFields()
+ .getField(singularField.getNumber())
+ .getVarintList());
+ assertEquals(Arrays.asList(4L, 6L),
+ message.getUnknownFields()
+ .getField(repeatedField.getNumber())
+ .getVarintList());
+ }
+
+ {
+ TestAllExtensions message =
+ TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+ assertEquals(TestAllTypes.NestedEnum.BAR,
+ message.getExtension(UnittestProto.optionalNestedEnumExtension));
+ assertEquals(
+ Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+ message.getExtension(UnittestProto.repeatedNestedEnumExtension));
+ assertEquals(Arrays.asList(5L),
+ message.getUnknownFields()
+ .getField(singularField.getNumber())
+ .getVarintList());
+ assertEquals(Arrays.asList(4L, 6L),
+ message.getUnknownFields()
+ .getField(repeatedField.getNumber())
+ .getVarintList());
+ }
+ }
+
+ public void testClearLite() throws Exception {
+ UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+ UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+ UnittestLite.TestEmptyMessageLite.newBuilder()
+ .mergeFrom(emptyMessageLite1).clear().build();
+ assertEquals(0, emptyMessageLite2.getSerializedSize());
+ ByteString data = emptyMessageLite2.toByteString();
+ assertEquals(0, data.size());
+ }
+
}
diff --git a/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java b/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
index ed5d069e..b1c75fc3 100644
--- a/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
+++ b/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,6 +33,7 @@ package com.google.protobuf;
import junit.framework.TestCase;
import java.util.Iterator;
+import java.util.List;
import java.util.ListIterator;
/**
@@ -60,6 +61,11 @@ public class UnmodifiableLazyStringListTest extends TestCase {
assertEquals(BYTE_STRING_A, list.getByteString(0));
assertEquals(BYTE_STRING_B, list.getByteString(1));
assertEquals(BYTE_STRING_C, list.getByteString(2));
+
+ List<ByteString> byteStringList = list.asByteStringList();
+ assertSame(list.getByteString(0), byteStringList.get(0));
+ assertSame(list.getByteString(1), byteStringList.get(1));
+ assertSame(list.getByteString(2), byteStringList.get(2));
}
public void testModifyMethods() {
@@ -88,6 +94,35 @@ public class UnmodifiableLazyStringListTest extends TestCase {
} catch (UnsupportedOperationException e) {
// expected
}
+ assertEquals(3, list.size());
+
+ List<ByteString> byteStringList = list.asByteStringList();
+ try {
+ byteStringList.remove(0);
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ assertEquals(3, list.size());
+ assertEquals(3, byteStringList.size());
+
+ try {
+ byteStringList.add(BYTE_STRING_B);
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ assertEquals(3, list.size());
+ assertEquals(3, byteStringList.size());
+
+ try {
+ byteStringList.set(1, BYTE_STRING_B);
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ assertEquals(3, list.size());
+ assertEquals(3, byteStringList.size());
}
public void testIterator() {
@@ -108,6 +143,20 @@ public class UnmodifiableLazyStringListTest extends TestCase {
}
assertEquals(3, count);
+ List<ByteString> byteStringList = list.asByteStringList();
+ Iterator<ByteString> byteIter = byteStringList.iterator();
+ count = 0;
+ while (byteIter.hasNext()) {
+ byteIter.next();
+ count++;
+ try {
+ byteIter.remove();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ }
+ assertEquals(3, count);
}
public void testListIterator() {
@@ -140,6 +189,32 @@ public class UnmodifiableLazyStringListTest extends TestCase {
}
assertEquals(3, count);
+ List<ByteString> byteStringList = list.asByteStringList();
+ ListIterator<ByteString> byteIter = byteStringList.listIterator();
+ count = 0;
+ while (byteIter.hasNext()) {
+ byteIter.next();
+ count++;
+ try {
+ byteIter.remove();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ try {
+ byteIter.set(BYTE_STRING_A);
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ try {
+ byteIter.add(BYTE_STRING_A);
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ }
+ assertEquals(3, count);
}
private LazyStringArrayList createSampleList() {
diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java
index 5ea1dd6a..6858524e 100644
--- a/java/src/test/java/com/google/protobuf/WireFormatTest.java
+++ b/java/src/test/java/com/google/protobuf/WireFormatTest.java
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,11 +34,14 @@ import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.util.List;
import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestFieldOrderings;
+import protobuf_unittest.UnittestProto.TestOneof2;
+import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestMset.TestMessageSet;
@@ -217,8 +220,8 @@ public class WireFormatTest extends TestCase {
}
public void testExtensionsSerializedSize() throws Exception {
- assertEquals(TestUtil.getAllSet().getSerializedSize(),
- TestUtil.getAllExtensionsSet().getSerializedSize());
+ assertNotSame(TestUtil.getAllSet().getSerializedSize(),
+ TestUtil.getAllExtensionsSet().getSerializedSize());
}
public void testSerializeDelimited() throws Exception {
@@ -328,7 +331,17 @@ public class WireFormatTest extends TestCase {
private static final int TYPE_ID_2 =
TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
- public void testSerializeMessageSet() throws Exception {
+ public void testSerializeMessageSetEagerly() throws Exception {
+ testSerializeMessageSetWithFlag(true);
+ }
+
+ public void testSerializeMessageSetNotEagerly() throws Exception {
+ testSerializeMessageSetWithFlag(false);
+ }
+
+ private void testSerializeMessageSetWithFlag(boolean eagerParsing)
+ throws Exception {
+ ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
// Set up a TestMessageSet with two known messages and an unknown one.
TestMessageSet messageSet =
TestMessageSet.newBuilder()
@@ -372,7 +385,17 @@ public class WireFormatTest extends TestCase {
assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
}
- public void testParseMessageSet() throws Exception {
+ public void testParseMessageSetEagerly() throws Exception {
+ testParseMessageSetWithFlag(true);
+ }
+
+ public void testParseMessageSetNotEagerly()throws Exception {
+ testParseMessageSetWithFlag(false);
+ }
+
+ private void testParseMessageSetWithFlag(boolean eagerParsing)
+ throws Exception {
+ ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
@@ -424,4 +447,160 @@ public class WireFormatTest extends TestCase {
assertEquals(1, field.getLengthDelimitedList().size());
assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8());
}
+
+ public void testParseMessageSetExtensionEagerly() throws Exception {
+ testParseMessageSetExtensionWithFlag(true);
+ }
+
+ public void testParseMessageSetExtensionNotEagerly() throws Exception {
+ testParseMessageSetExtensionWithFlag(false);
+ }
+
+ private void testParseMessageSetExtensionWithFlag(boolean eagerParsing)
+ throws Exception {
+ ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+ extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+
+ // Set up a RawMessageSet with a known messages.
+ int TYPE_ID_1 =
+ TestMessageSetExtension1
+ .getDescriptor().getExtensions().get(0).getNumber();
+ RawMessageSet raw =
+ RawMessageSet.newBuilder()
+ .addItem(
+ RawMessageSet.Item.newBuilder()
+ .setTypeId(TYPE_ID_1)
+ .setMessage(
+ TestMessageSetExtension1.newBuilder()
+ .setI(123)
+ .build().toByteString())
+ .build())
+ .build();
+
+ ByteString data = raw.toByteString();
+
+ // Parse as a TestMessageSet and check the contents.
+ TestMessageSet messageSet =
+ TestMessageSet.parseFrom(data, extensionRegistry);
+ assertEquals(123, messageSet.getExtension(
+ TestMessageSetExtension1.messageSetExtension).getI());
+ }
+
+ public void testMergeLazyMessageSetExtensionEagerly() throws Exception {
+ testMergeLazyMessageSetExtensionWithFlag(true);
+ }
+
+ public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception {
+ testMergeLazyMessageSetExtensionWithFlag(false);
+ }
+
+ private void testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing)
+ throws Exception {
+ ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+ extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+
+ // Set up a RawMessageSet with a known messages.
+ int TYPE_ID_1 =
+ TestMessageSetExtension1
+ .getDescriptor().getExtensions().get(0).getNumber();
+ RawMessageSet raw =
+ RawMessageSet.newBuilder()
+ .addItem(
+ RawMessageSet.Item.newBuilder()
+ .setTypeId(TYPE_ID_1)
+ .setMessage(
+ TestMessageSetExtension1.newBuilder()
+ .setI(123)
+ .build().toByteString())
+ .build())
+ .build();
+
+ ByteString data = raw.toByteString();
+
+ // Parse as a TestMessageSet and store value into lazy field
+ TestMessageSet messageSet =
+ TestMessageSet.parseFrom(data, extensionRegistry);
+ // Merge lazy field check the contents.
+ messageSet =
+ messageSet.toBuilder().mergeFrom(data, extensionRegistry).build();
+ assertEquals(123, messageSet.getExtension(
+ TestMessageSetExtension1.messageSetExtension).getI());
+ }
+
+ public void testMergeMessageSetExtensionEagerly() throws Exception {
+ testMergeMessageSetExtensionWithFlag(true);
+ }
+
+ public void testMergeMessageSetExtensionNotEagerly() throws Exception {
+ testMergeMessageSetExtensionWithFlag(false);
+ }
+
+ private void testMergeMessageSetExtensionWithFlag(boolean eagerParsing)
+ throws Exception {
+ ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+ extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+
+ // Set up a RawMessageSet with a known messages.
+ int TYPE_ID_1 =
+ TestMessageSetExtension1
+ .getDescriptor().getExtensions().get(0).getNumber();
+ RawMessageSet raw =
+ RawMessageSet.newBuilder()
+ .addItem(
+ RawMessageSet.Item.newBuilder()
+ .setTypeId(TYPE_ID_1)
+ .setMessage(
+ TestMessageSetExtension1.newBuilder()
+ .setI(123)
+ .build().toByteString())
+ .build())
+ .build();
+
+ // Serialize RawMessageSet unnormally (message value before type id)
+ ByteString.CodedBuilder out = ByteString.newCodedBuilder(
+ raw.getSerializedSize());
+ CodedOutputStream output = out.getCodedOutput();
+ List<RawMessageSet.Item> items = raw.getItemList();
+ for (int i = 0; i < items.size(); i++) {
+ RawMessageSet.Item item = items.get(i);
+ output.writeTag(1, WireFormat.WIRETYPE_START_GROUP);
+ output.writeBytes(3, item.getMessage());
+ output.writeInt32(2, item.getTypeId());
+ output.writeTag(1, WireFormat.WIRETYPE_END_GROUP);
+ }
+ ByteString data = out.build();
+
+ // Merge bytes into TestMessageSet and check the contents.
+ TestMessageSet messageSet =
+ TestMessageSet.newBuilder().mergeFrom(data, extensionRegistry).build();
+ assertEquals(123, messageSet.getExtension(
+ TestMessageSetExtension1.messageSetExtension).getI());
+ }
+
+ // ================================================================
+ // oneof
+ public void testOneofWireFormat() throws Exception {
+ TestOneof2.Builder builder = TestOneof2.newBuilder();
+ TestUtil.setOneof(builder);
+ TestOneof2 message = builder.build();
+ ByteString rawBytes = message.toByteString();
+
+ assertEquals(rawBytes.size(), message.getSerializedSize());
+
+ TestOneof2 message2 = TestOneof2.parseFrom(rawBytes);
+ TestUtil.assertOneofSet(message2);
+ }
+
+ public void testOneofOnlyLastSet() throws Exception {
+ TestOneofBackwardsCompatible source = TestOneofBackwardsCompatible
+ .newBuilder().setFooInt(100).setFooString("101").build();
+
+ ByteString rawBytes = source.toByteString();
+ TestOneof2 message = TestOneof2.parseFrom(rawBytes);
+ assertFalse(message.hasFooInt());
+ assertTrue(message.hasFooString());
+ }
}
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
new file mode 100644
index 00000000..5580f72d
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto
@@ -0,0 +1,71 @@
+// 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: Naoki Iwasaki (niwasaki@google.com)
+//
+// A proto file with lazy fields
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+option optimize_for = LITE_RUNTIME;
+
+message LazyMessageLite {
+ optional int32 num = 1;
+ optional int32 num_with_default = 2 [default = 421];
+ optional LazyInnerMessageLite inner = 3 [lazy = true];
+ repeated LazyInnerMessageLite repeated_inner = 4 [lazy = true];
+
+ oneof oneof_field {
+ int32 oneof_num = 5;
+ LazyInnerMessageLite oneof_inner = 6 [lazy = true];
+ }
+}
+
+message LazyInnerMessageLite {
+ optional int32 num = 1;
+ optional int32 num_with_default = 2 [default = 42];
+ optional LazyNestedInnerMessageLite nested = 3 [lazy = true];
+
+ extensions 1000 to max;
+}
+
+message LazyExtension {
+ extend LazyInnerMessageLite {
+ optional LazyExtension extension = 1000;
+ }
+ optional string name = 1;
+}
+
+message LazyNestedInnerMessageLite {
+ optional int32 num = 1;
+ optional int32 num_with_default = 2 [default = 4];
+}
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
new file mode 100644
index 00000000..86837250
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto
@@ -0,0 +1,72 @@
+// 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: pbogle@google.com (Phil Bogle)
+
+syntax = "proto2";
+
+package protobuf_unittest.lite_equals_and_hash;
+
+// This proto definition is used to test that java_generate_equals_and_hash
+// works correctly with the LITE_RUNTIME.
+option java_generate_equals_and_hash = true;
+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;
+}
+
+message BarPrime {
+ optional string name = 1;
+}
+
+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..d5418f28
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto
@@ -0,0 +1,75 @@
+// 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, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, MessageValue> int32_to_message_field = 5;
+ map<string, int32> string_to_int32_field = 6;
+
+ message MessageWithRequiredFields {
+ required int32 value = 1;
+ }
+ map<int32, MessageWithRequiredFields> required_message_map = 11;
+}
+
+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, int32> int32_to_int32_field = 4;
+}
+
+// Test that the maps initialization code works correctly when the map field
+// references the containing message.
+message TestRecursiveMap {
+ optional int32 value = 1;
+ map<int32, TestRecursiveMap> recursive_map_field = 2;
+}
+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..a9be5166
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/map_for_proto2_test.proto
@@ -0,0 +1,74 @@
+// 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, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, MessageValue> int32_to_message_field = 5;
+ map<string, int32> string_to_int32_field = 6;
+
+ message MessageWithRequiredFields {
+ required int32 value = 1;
+ }
+ map<int32, MessageWithRequiredFields> required_message_map = 11;
+}
+
+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, int32> int32_to_int32_field = 4;
+}
+
+// Test that the maps initialization code works correctly when the map field
+// references the containing message.
+message TestRecursiveMap {
+ optional int32 value = 1;
+ map<int32, TestRecursiveMap> recursive_map_field = 2;
+}
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..bf692c22
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/map_test.proto
@@ -0,0 +1,64 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+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, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, MessageValue> int32_to_message_field = 5;
+ map<string, int32> 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 9a040145..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
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,18 +32,21 @@
//
// 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
option java_generic_services = true; // auto-added
import "google/protobuf/unittest.proto";
+import "google/protobuf/descriptor.proto";
package protobuf_unittest;
option java_multiple_files = true;
option java_outer_classname = "MultipleFilesTestProto";
+
message MessageWithNoOuter {
message NestedMessage {
optional int32 i = 1;
@@ -57,8 +60,12 @@ message MessageWithNoOuter {
optional EnumWithNoOuter foreign_enum = 4;
}
+extend google.protobuf.EnumValueOptions {
+ optional int32 enum_value_option = 7654321;
+}
+
enum EnumWithNoOuter {
- FOO = 1;
+ FOO = 1 [(enum_value_option) = 12345];
BAR = 2;
}
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 abffb9d2..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
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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 9fe5d560..704e649e 100644
--- a/java/src/test/java/com/google/protobuf/nested_extension.proto
+++ b/java/src/test/java/com/google/protobuf/nested_extension.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,11 +33,13 @@
// 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";
package protobuf_unittest;
+
message MyNestedExtension {
extend MessageToBeExtended {
optional MessageToBeExtended recursiveExtension = 2;
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 16ee46e5..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
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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 f61b419b..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
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,9 +32,11 @@
//
// A proto file with extensions.
+syntax = "proto2";
package protobuf_unittest;
+
message MessageToBeExtended {
extensions 1 to max;
}
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 3c82659b..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
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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
new file mode 100644
index 00000000..42083681
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/outer_class_name_test.proto
@@ -0,0 +1,40 @@
+// 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 protobuf_unittest;
+
+
+// This message's name is the same with the default outer class name of this
+// proto file. It's used to test if the compiler can avoid this conflict
+// correctly.
+message OuterClassNameTest {
+}
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
new file mode 100644
index 00000000..3e5956b0
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto
@@ -0,0 +1,44 @@
+// 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 protobuf_unittest;
+
+
+message TestMessage2 {
+ message NestedMessage {
+ // This message's name is the same with the default outer class name of this
+ // proto file. It's used to test if the compiler can avoid this conflict
+ // correctly.
+ message OuterClassNameTest2 {
+ }
+ }
+}
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
new file mode 100644
index 00000000..74a8ba3c
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/outer_class_name_test3.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";
+
+package protobuf_unittest;
+
+
+message TestMessage3 {
+ message NestedMessage {
+ // This enum's name is the same with the default outer class name of this
+ // proto file. It's used to test if the compiler can avoid this conflict
+ // correctly.
+ enum OuterClassNameTest3 {
+ DUMMY_VALUE = 1;
+ }
+ }
+}
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 499f099f..dc082615 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
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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
@@ -42,13 +43,44 @@ package io_protocol_tests;
option java_package = "com.google.protobuf";
option java_outer_classname = "TestBadIdentifiersProto";
+option java_generate_equals_and_hash = true;
+
message TestMessage {
+ optional string cached_size = 1;
+ optional string serialized_size = 2;
+ optional string class = 3;
+}
+
+message Descriptor {
+ option no_standard_descriptor_accessor = true;
+ optional string descriptor = 1;
+ message NestedDescriptor {
+ option no_standard_descriptor_accessor = true;
+ optional string descriptor = 1;
+ }
+ optional NestedDescriptor nested_descriptor = 2;
+ enum NestedEnum {
+ UNKNOWN = 0;
+ FOO = 1;
+ }
+}
+
+message Parser {
+ enum ParserEnum {
+ UNKNOWN = 0;
+ PARSER = 1;
+ }
+ optional ParserEnum parser = 1;
}
message Deprecated {
enum TestEnum {
+ UNKNOWN = 0;
FOO = 1;
+
+ // Test if @Deprecated annotation conflicts with Deprecated message name.
+ BAR = 2 [ deprecated = true ];
}
optional int32 field1 = 1 [deprecated=true];
@@ -62,9 +94,77 @@ message Override {
message Object {
optional int32 object = 1;
+ optional string string_object = 2;
+}
+
+message String {
+ optional string string = 1;
+}
+
+message Integer {
+ optional int32 integer = 1;
+}
+
+message Long {
+ optional int32 long = 1;
+}
+
+message Float {
+ optional float float = 1;
+}
+
+message Double {
+ optional double double = 1;
}
service TestConflictingMethodNames {
rpc Override(TestMessage) returns (TestMessage);
}
+message TestConflictingFieldNames {
+ enum TestEnum {
+ UNKNOWN = 0;
+ FOO = 1;
+ }
+ message TestMessage {
+ }
+ repeated int32 int32_field = 1;
+ repeated TestEnum enum_field = 2;
+ repeated string string_field = 3;
+ repeated bytes bytes_field = 4;
+ repeated TestMessage message_field = 5;
+
+ optional int32 int32_field_count = 11;
+ optional TestEnum enum_field_count = 12;
+ optional string string_field_count = 13;
+ optional bytes bytes_field_count = 14;
+ optional TestMessage message_field_count = 15;
+
+ repeated int32 Int32Field = 21;
+ repeated TestEnum EnumField = 22;
+ repeated string StringField = 23;
+ repeated bytes BytesField = 24;
+ repeated TestMessage MessageField = 25;
+
+ // This field conflicts with "int32_field" as they both generate
+ // the method getInt32FieldList().
+ required int32 int32_field_list = 31; // NO_PROTO3
+
+ extensions 1000 to max; // NO_PROTO3
+
+ repeated int64 int64_field = 41;
+ 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; // NO_PROTO3
+ optional int64 int64_field_list = 1002; // NO_PROTO3
+ } // NO_PROTO3
+}
+
+message TestMapField {
+ message MapField {}
+ message Pair {}
+ message Message {}
+
+ map<int32, int32> 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
new file mode 100644
index 00000000..119c1dcb
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/test_check_utf8.proto
@@ -0,0 +1,51 @@
+// 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: Jacob Butcher (jbaum@google.com)
+//
+// Test file option java_string_check_utf8.
+syntax = "proto2";
+
+package proto2_test_check_utf8;
+
+option java_outer_classname = "TestCheckUtf8";
+option java_string_check_utf8 = true;
+
+message StringWrapper {
+ required string req = 1;
+ optional string opt = 2;
+ repeated string rep = 3;
+}
+
+message BytesWrapper {
+ required bytes req = 1;
+ optional bytes opt = 2;
+ repeated bytes rep = 3;
+}
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
new file mode 100644
index 00000000..f06d76d6
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto
@@ -0,0 +1,52 @@
+// 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: Jacob Butcher (jbaum@google.com)
+//
+// Test file option java_string_check_utf8.
+syntax = "proto2";
+
+package proto2_test_check_utf8_size;
+
+option java_outer_classname = "TestCheckUtf8Size";
+option java_string_check_utf8 = true;
+option optimize_for = CODE_SIZE;
+
+message StringWrapperSize {
+ required string req = 1;
+ optional string opt = 2;
+ repeated string rep = 3;
+}
+
+message BytesWrapperSize {
+ required bytes req = 1;
+ optional bytes opt = 2;
+ repeated bytes rep = 3;
+}
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
new file mode 100644
index 00000000..f8efd455
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/test_custom_options.proto
@@ -0,0 +1,44 @@
+// 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: Feng Xiao (xiaofeng@google.com)
+//
+// Test that custom options defined in a proto file's dependencies are properly
+// initialized.
+syntax = "proto2";
+
+package protobuf_unittest;
+
+
+import "google/protobuf/unittest_custom_options.proto";
+
+message TestMessageWithCustomOptionsContainer {
+ optional TestMessageWithCustomOptions field = 1;
+}
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
new file mode 100644
index 00000000..645f57b4
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/test_extra_interfaces.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.
+
+// Author: Darick Tong (darick@google.com)
+syntax = "proto2";
+
+package protobuf_unittest;
+
+message Proto1 {
+ option experimental_java_message_interface =
+ "com.google.protobuf.ExtraInterfaces.HasBoolValue";
+
+ option experimental_java_interface_extends =
+ "com.google.protobuf.ExtraInterfaces.HasByteValue";
+
+ option experimental_java_message_interface =
+ "com.google.protobuf.ExtraInterfaces.HasStringValue<Proto1>";
+
+ option experimental_java_builder_interface =
+ "com.google.protobuf.ExtraInterfaces.HasStringValueBuilder"
+ "<Proto1, Builder>";
+
+ optional string string_value = 1;
+ optional bool bool_value = 2;
+ optional bytes byte_value = 3;
+ optional int32 int_value = 4;
+}
+
+message Proto2 {
+ option experimental_java_message_interface =
+ "com.google.protobuf.ExtraInterfaces.HasBoolValue";
+
+ optional bool bool_value = 1;
+}
diff --git a/javanano/README.md b/javanano/README.md
new file mode 100644
index 00000000..7d696aa7
--- /dev/null
+++ b/javanano/README.md
@@ -0,0 +1,375 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
+Copyright 2008 Google Inc.
+
+This directory contains the Java Protocol Buffers Nano runtime library.
+
+Installation - With Maven
+-------------------------
+
+The Protocol Buffers build is managed using Maven. If you would
+rather build without Maven, see below.
+
+1) Install Apache Maven if you don't have it:
+
+ http://maven.apache.org/
+
+2) Build the C++ code, or obtain a binary distribution of protoc. If
+ you install a binary distribution, make sure that it is the same
+ version as this package. If in doubt, run:
+
+ $ protoc --version
+
+ You will need to place the protoc executable in ../src. (If you
+ built it yourself, it should already be there.)
+
+3) Run the tests:
+
+ $ mvn test
+
+ If some tests fail, this library may not work correctly on your
+ system. Continue at your own risk.
+
+4) Install the library into your Maven repository:
+
+ $ mvn install
+
+5) If you do not use Maven to manage your own build, you can build a
+ .jar file to use:
+
+ $ mvn package
+
+ The .jar will be placed in the "target" directory.
+
+Installation - Without Maven
+----------------------------
+
+If you would rather not install Maven to build the library, you may
+follow these instructions instead. Note that these instructions skip
+running unit tests.
+
+1) Build the C++ code, or obtain a binary distribution of protoc. If
+ you install a binary distribution, make sure that it is the same
+ version as this package. If in doubt, run:
+
+ $ protoc --version
+
+ If you built the C++ code without installing, the compiler binary
+ should be located in ../src.
+
+2) Invoke protoc to build DescriptorProtos.java:
+
+ $ protoc --java_out=src/main/java -I../src \
+ ../src/google/protobuf/descriptor.proto
+
+3) Compile the code in src/main/java using whatever means you prefer.
+
+4) Install the classes wherever you prefer.
+
+Nano version
+------------
+
+JavaNano is a special code generator and runtime library designed specially for
+resource-restricted systems, like Android. It is very resource-friendly in both
+the amount of code and the runtime overhead. Here is an overview of JavaNano
+features compared with the official Java protobuf:
+
+- No descriptors or message builders.
+- All messages are mutable; fields are public Java fields.
+- For optional fields only, encapsulation behind setter/getter/hazzer/
+ clearer functions is opt-in, which provide proper 'has' state support.
+- For proto2, if not opted in, has state (field presence) is not available.
+ Serialization outputs all fields not equal to their defaults
+ (see important implications below).
+ The behavior is consistent with proto3 semantics.
+- Required fields (proto2 only) are always serialized.
+- Enum constants are integers; protection against invalid values only
+ when parsing from the wire.
+- Enum constants can be generated into container interfaces bearing
+ the enum's name (so the referencing code is in Java style).
+- CodedInputByteBufferNano can only take byte[] (not InputStream).
+- Similarly CodedOutputByteBufferNano can only write to byte[].
+- Repeated fields are in arrays, not ArrayList or Vector. Null array
+ elements are allowed and silently ignored.
+- Full support for serializing/deserializing repeated packed fields.
+- Support extensions (in proto2).
+- Unset messages/groups are null, not an immutable empty default
+ instance.
+- toByteArray(...) and mergeFrom(...) are now static functions of
+ MessageNano.
+- The 'bytes' type translates to the Java type byte[].
+
+The generated messages are not thread-safe for writes, but may be
+used simultaneously from multiple threads in a read-only manner.
+In other words, an appropriate synchronization mechanism (such as
+a ReadWriteLock) must be used to ensure that a message, its
+ancestors, and descendants are not accessed by any other threads
+while the message is being modified. Field reads, getter methods
+(but not getExtension(...)), toByteArray(...), writeTo(...),
+getCachedSize(), and getSerializedSize() are all considered read-only
+operations.
+
+IMPORTANT: If you have fields with defaults and opt out of accessors
+
+How fields with defaults are serialized has changed. Because we don't
+keep "has" state, any field equal to its default is assumed to be not
+set and therefore is not serialized. Consider the situation where we
+change the default value of a field. Senders compiled against an older
+version of the proto continue to match against the old default, and
+don't send values to the receiver even though the receiver assumes the
+new default value. Therefore, think carefully about the implications
+of changing the default value. Alternatively, turn on accessors and
+enjoy the benefit of the explicit has() checks.
+
+IMPORTANT: If you have "bytes" fields with non-empty defaults
+
+Because the byte buffer is now of mutable type byte[], the default
+static final cannot be exposed through a public field. Each time a
+message's constructor or clear() function is called, the default value
+(kept in a private byte[]) is cloned. This causes a small memory
+penalty. This is not a problem if the field has no default or is an
+empty default.
+
+Nano Generator options
+----------------------
+
+```
+java_package -> <file-name>|<package-name>
+java_outer_classname -> <file-name>|<package-name>
+java_multiple_files -> true or false
+java_nano_generate_has -> true or false [DEPRECATED]
+optional_field_style -> default or accessors
+enum_style -> c or java
+ignore_services -> true or false
+parcelable_messages -> true or false
+```
+
+**java_package=\<file-name\>|\<package-name\>** (no default)
+
+ This allows overriding the 'java_package' option value
+ for the given file from the command line. Use multiple
+ java_package options to override the option for multiple
+ files. The final Java package for each file is the value
+ of this command line option if present, or the value of
+ the same option defined in the file if present, or the
+ proto package if present, or the default Java package.
+
+**java_outer_classname=\<file-name\>|\<outer-classname\>** (no default)
+
+ This allows overriding the 'java_outer_classname' option
+ for the given file from the command line. Use multiple
+ java_outer_classname options to override the option for
+ multiple files. The final Java outer class name for each
+ file is the value of this command line option if present,
+ or the value of the same option defined in the file if
+ present, or the file name converted to CamelCase. This
+ outer class will nest all classes and integer constants
+ generated from file-scope messages and enums.
+
+**java_multiple_files={true,false}** (no default)
+
+ This allows overriding the 'java_multiple_files' option
+ in all source files and their imported files from the
+ command line. The final value of this option for each
+ file is the value defined in this command line option, or
+ the value of the same option defined in the file if
+ present, or false. This specifies whether to generate
+ package-level classes for the file-scope messages in the
+ same Java package as the outer class (instead of nested
+ classes in the outer class). File-scope enum constants
+ are still generated as integer constants in the outer
+ class. This affects the fully qualified references in the
+ Java code. NOTE: because the command line option
+ overrides the value for all files and their imported
+ files, using this option inconsistently may result in
+ incorrect references to the imported messages and enum
+ constants.
+
+**java_nano_generate_has={true,false}** (default: false)
+
+ DEPRECATED. Use optional_field_style=accessors.
+
+ If true, generates a public boolean variable has\<fieldname\>
+ accompanying each optional or required field (not present for
+ repeated fields, groups or messages). It is set to false initially
+ and upon clear(). If parseFrom(...) reads the field from the wire,
+ it is set to true. This is a way for clients to inspect the "has"
+ value upon parse. If it is set to true, writeTo(...) will ALWAYS
+ output that field (even if field value is equal to its
+ default).
+
+ IMPORTANT: This option costs an extra 4 bytes per primitive field in
+ the message. Think carefully about whether you really need this. In
+ many cases reading the default works and determining whether the
+ field was received over the wire is irrelevant.
+
+**optional_field_style={default,accessors,reftypes}** (default: default)
+
+ Defines the style of the generated code for fields.
+
+ * default
+
+ In the default style, optional fields translate into public mutable
+ Java fields, and the serialization process is as discussed in the
+ "IMPORTANT" section above.
+
+ * accessors
+
+ When set to 'accessors', each optional field is encapsulated behind
+ 4 accessors, namely get\<fieldname\>(), set\<fieldname\>(), has\<fieldname\>()
+ and clear\<fieldname\>() methods, with the standard semantics. The hazzer's
+ return value determines whether a field is serialized, so this style is
+ useful when you need to serialize a field with the default value, or check
+ if a field has been explicitly set to its default value from the wire.
+
+ In the 'accessors' style, required and nested message fields are still
+ translated to one public mutable Java field each, repeated fields are still
+ translated to arrays. No accessors are generated for them.
+
+ IMPORTANT: When using the 'accessors' style, ProGuard should always
+ be enabled with optimization (don't use -dontoptimize) and allowing
+ access modification (use -allowaccessmodification). This removes the
+ unused accessors and maybe inline the rest at the call sites,
+ reducing the final code size.
+ TODO(maxtroy): find ProGuard config that would work the best.
+
+ * reftypes
+
+ When set to 'reftypes', each proto field is generated as a public Java
+ field. For primitive types, these fields use the Java reference types
+ such as java.lang.Integer instead of primitive types such as int.
+
+ In the 'reftypes' style, fields are initialized to null (or empty
+ arrays for repeated fields), and their default values are not available.
+ They are serialized over the wire based on equality to null.
+
+ The 'reftypes' mode has some additional cost due to autoboxing and usage
+ of reference types. In practice, many boxed types are cached, and so don't
+ result in object creation. However, references do take slightly more memory
+ than primitives.
+
+ The 'reftypes' mode is useful when you want to be able to serialize fields
+ with default values, or check if a field has been explicitly set to the
+ default over the wire without paying the extra method cost of the
+ 'accessors' mode.
+
+ Note that if you attempt to write null to a required field in the reftypes
+ mode, serialization of the proto will cause a NullPointerException. This is
+ an intentional indicator that you must set required fields.
+
+ NOTE
+ optional_field_style=accessors or reftypes cannot be used together with
+ java_nano_generate_has=true. If you need the 'has' flag for any
+ required field (you have no reason to), you can only use
+ java_nano_generate_has=true.
+
+**enum_style={c,java}** (default: c)
+
+ Defines where to put the int constants generated from enum members.
+
+ * c
+
+ Use C-style, so the enum constants are available at the scope where
+ the enum is defined. A file-scope enum's members are referenced like
+ 'FileOuterClass.ENUM_VALUE'; a message-scope enum's members are
+ referenced as 'Message.ENUM_VALUE'. The enum name is unavailable.
+ This complies with the Micro code generator's behavior.
+
+ * java
+
+ Use Java-style, so the enum constants are available under the enum
+ name and referenced like 'EnumName.ENUM_VALUE' (they are still int
+ constants). The enum name becomes the name of a public interface, at
+ the scope where the enum is defined. If the enum is file-scope and
+ the java_multiple_files option is on, the interface will be defined
+ in its own file. To reduce code size, this interface should not be
+ implemented and ProGuard shrinking should be used, so after the Java
+ compiler inlines all referenced enum constants into the call sites,
+ the interface remains unused and can be removed by ProGuard.
+
+**ignore_services={true,false}** (default: false)
+
+ Skips services definitions.
+
+ Nano doesn't support services. By default, if a service is defined
+ it will generate a compilation error. If this flag is set to true,
+ services will be silently ignored, instead.
+
+**parcelable_messages={true,false}** (default: false)
+
+ Android-specific option to generate Parcelable messages.
+
+
+To use nano protobufs within the Android repo:
+----------------------------------------------
+
+- Set 'LOCAL_PROTOC_OPTIMIZE_TYPE := nano' in your local .mk file.
+ When building a Java library or an app (package) target, the build
+ system will add the Java nano runtime library to the
+ LOCAL_STATIC_JAVA_LIBRARIES variable, so you don't need to.
+- Set 'LOCAL_PROTO_JAVA_OUTPUT_PARAMS := ...' in your local .mk file
+ for any command-line options you need. Use commas to join multiple
+ options. In the nano flavor only, whitespace surrounding the option
+ names and values are ignored, so you can use backslash-newline or
+ '+=' to structure your make files nicely.
+- The options will be applied to *all* proto files in LOCAL_SRC_FILES
+ when you build a Java library or package. In case different options
+ are needed for different proto files, build separate Java libraries
+ and reference them in your main target. Note: you should make sure
+ that, for each separate target, all proto files imported from any
+ proto file in LOCAL_SRC_FILES are included in LOCAL_SRC_FILES. This
+ is because the generator has to assume that the imported files are
+ built using the same options, and will generate code that reference
+ the fields and enums from the imported files using the same code
+ style.
+- Hint: 'include $(CLEAR_VARS)' resets all LOCAL_ variables, including
+ the two above.
+
+To use nano protobufs outside of Android repo:
+----------------------------------------------
+
+- Link with the generated jar file
+ \<protobuf-root\>java/target/protobuf-java-2.3.0-nano.jar.
+- Invoke with --javanano_out, e.g.:
+```
+./protoc '--javanano_out=\
+ java_package=src/proto/simple-data.proto|my_package,\
+ java_outer_classname=src/proto/simple-data.proto|OuterName\
+ :.' src/proto/simple-data.proto
+```
+
+Contributing to nano:
+---------------------
+
+Please add/edit tests in NanoTest.java.
+
+Please run the following steps to test:
+
+- cd external/protobuf
+- ./configure
+- Run "make -j12 check" and verify all tests pass.
+- cd java
+- Run "mvn test" and verify all tests pass.
+- cd ../../..
+- . build/envsetup.sh
+- lunch 1
+- "make -j12 aprotoc libprotobuf-java-2.3.0-nano aprotoc-test-nano-params NanoAndroidTest" and
+ check for build errors.
+- Plug in an Android device or start an emulator.
+- adb install -r out/target/product/generic/data/app/NanoAndroidTest.apk
+- Run:
+ "adb shell am instrument -w com.google.protobuf.nano.test/android.test.InstrumentationTestRunner"
+ and verify all tests pass.
+- repo sync -c -j256
+- "make -j12" and check for build errors
+
+Usage
+-----
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+ https://developers.google.com/protocol-buffers/
diff --git a/javanano/pom.xml b/javanano/pom.xml
new file mode 100644
index 00000000..7a2be9df
--- /dev/null
+++ b/javanano/pom.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google</groupId>
+ <artifactId>google</artifactId>
+ <version>1</version>
+ </parent>
+ <groupId>com.google.protobuf.nano</groupId>
+ <artifactId>protobuf-javanano</artifactId>
+ <version>3.0.0-alpha-3-pre</version>
+ <packaging>bundle</packaging>
+ <name>Protocol Buffer JavaNano API</name>
+ <description>
+ Protocol Buffers are a way of encoding structured data in an efficient yet
+ extensible format.
+ </description>
+ <inceptionYear>2008</inceptionYear>
+ <url>https://developers.google.com/protocol-buffers/</url>
+ <licenses>
+ <license>
+ <name>New BSD license</name>
+ <url>http://www.opensource.org/licenses/bsd-license.php</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <url>https://github.com/google/protobuf</url>
+ <connection>
+ scm:git:https://github.com/google/protobuf.git
+ </connection>
+ </scm>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>2.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymockclassextension</artifactId>
+ <version>2.2.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-test-sources</id>
+ <phase>generate-test-sources</phase>
+ <configuration>
+ <tasks>
+ <mkdir dir="target/generated-test-sources" />
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_import_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_single_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/map_test.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=store_unknown_fields=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=java_nano_generate_has=true,generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_has_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=optional_field_style=accessors,generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=enum_style=java:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=
+ optional_field_style=accessors,
+ java_outer_classname=google/protobuf/nano/unittest_enum_validity_nano.proto|EnumValidityAccessors
+ :target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=optional_field_style=reftypes,generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto" />
+ </exec>
+ </tasks>
+ <testSourceRoot>target/generated-test-sources</testSourceRoot>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
+ <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
+ <Export-Package>com.google.protobuf;version=3.0.0-alpha-3-pre</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.2.1</version>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9.1</version>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>nexus-staging-maven-plugin</artifactId>
+ <version>1.6.3</version>
+ <extensions>true</extensions>
+ <configuration>
+ <serverId>sonatype-nexus-staging</serverId>
+ <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+ <autoReleaseAfterClose>false</autoReleaseAfterClose>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
new file mode 100644
index 00000000..b4f20fde
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
@@ -0,0 +1,681 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.io.IOException;
+
+/**
+ * Reads and decodes protocol message fields.
+ *
+ * This class contains two kinds of methods: methods that read specific
+ * protocol message constructs and field types (e.g. {@link #readTag()} and
+ * {@link #readInt32()}) and methods that read low-level values (e.g.
+ * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
+ * encoded protocol messages, you should use the former methods, but if you are
+ * reading some other format of your own design, use the latter.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class CodedInputByteBufferNano {
+ /**
+ * Create a new CodedInputStream wrapping the given byte array.
+ */
+ public static CodedInputByteBufferNano newInstance(final byte[] buf) {
+ return newInstance(buf, 0, buf.length);
+ }
+
+ /**
+ * Create a new CodedInputStream wrapping the given byte array slice.
+ */
+ public static CodedInputByteBufferNano newInstance(final byte[] buf, final int off,
+ final int len) {
+ return new CodedInputByteBufferNano(buf, off, len);
+ }
+
+ // -----------------------------------------------------------------
+
+ /**
+ * Attempt to read a field tag, returning zero if we have reached EOF.
+ * Protocol message parsers use this to read tags, since a protocol message
+ * may legally end wherever a tag occurs, and zero is not a valid tag number.
+ */
+ public int readTag() throws IOException {
+ if (isAtEnd()) {
+ lastTag = 0;
+ return 0;
+ }
+
+ lastTag = readRawVarint32();
+ if (lastTag == 0) {
+ // If we actually read zero, that's not a valid tag.
+ throw InvalidProtocolBufferNanoException.invalidTag();
+ }
+ return lastTag;
+ }
+
+ /**
+ * Verifies that the last call to readTag() returned the given tag value.
+ * This is used to verify that a nested group ended with the correct
+ * end tag.
+ *
+ * @throws InvalidProtocolBufferNanoException {@code value} does not match the
+ * last tag.
+ */
+ public void checkLastTagWas(final int value)
+ throws InvalidProtocolBufferNanoException {
+ if (lastTag != value) {
+ throw InvalidProtocolBufferNanoException.invalidEndTag();
+ }
+ }
+
+ /**
+ * Reads and discards a single field, given its tag value.
+ *
+ * @return {@code false} if the tag is an endgroup tag, in which case
+ * nothing is skipped. Otherwise, returns {@code true}.
+ */
+ public boolean skipField(final int tag) throws IOException {
+ switch (WireFormatNano.getTagWireType(tag)) {
+ case WireFormatNano.WIRETYPE_VARINT:
+ readInt32();
+ return true;
+ case WireFormatNano.WIRETYPE_FIXED64:
+ readRawLittleEndian64();
+ return true;
+ case WireFormatNano.WIRETYPE_LENGTH_DELIMITED:
+ skipRawBytes(readRawVarint32());
+ return true;
+ case WireFormatNano.WIRETYPE_START_GROUP:
+ skipMessage();
+ checkLastTagWas(
+ WireFormatNano.makeTag(WireFormatNano.getTagFieldNumber(tag),
+ WireFormatNano.WIRETYPE_END_GROUP));
+ return true;
+ case WireFormatNano.WIRETYPE_END_GROUP:
+ return false;
+ case WireFormatNano.WIRETYPE_FIXED32:
+ readRawLittleEndian32();
+ return true;
+ default:
+ throw InvalidProtocolBufferNanoException.invalidWireType();
+ }
+ }
+
+ /**
+ * Reads and discards an entire message. This will read either until EOF
+ * or until an endgroup tag, whichever comes first.
+ */
+ public void skipMessage() throws IOException {
+ while (true) {
+ final int tag = readTag();
+ if (tag == 0 || !skipField(tag)) {
+ return;
+ }
+ }
+ }
+
+ // -----------------------------------------------------------------
+
+ /** Read a {@code double} field value from the stream. */
+ public double readDouble() throws IOException {
+ return Double.longBitsToDouble(readRawLittleEndian64());
+ }
+
+ /** Read a {@code float} field value from the stream. */
+ public float readFloat() throws IOException {
+ return Float.intBitsToFloat(readRawLittleEndian32());
+ }
+
+ /** Read a {@code uint64} field value from the stream. */
+ public long readUInt64() throws IOException {
+ return readRawVarint64();
+ }
+
+ /** Read an {@code int64} field value from the stream. */
+ public long readInt64() throws IOException {
+ return readRawVarint64();
+ }
+
+ /** Read an {@code int32} field value from the stream. */
+ public int readInt32() throws IOException {
+ return readRawVarint32();
+ }
+
+ /** Read a {@code fixed64} field value from the stream. */
+ public long readFixed64() throws IOException {
+ return readRawLittleEndian64();
+ }
+
+ /** Read a {@code fixed32} field value from the stream. */
+ public int readFixed32() throws IOException {
+ return readRawLittleEndian32();
+ }
+
+ /** Read a {@code bool} field value from the stream. */
+ public boolean readBool() throws IOException {
+ return readRawVarint32() != 0;
+ }
+
+ /** Read a {@code string} field value from the stream. */
+ public String readString() throws IOException {
+ final int size = readRawVarint32();
+ if (size <= (bufferSize - bufferPos) && size > 0) {
+ // Fast path: We already have the bytes in a contiguous buffer, so
+ // just copy directly from it.
+ final String result = new String(buffer, bufferPos, size, "UTF-8");
+ bufferPos += size;
+ return result;
+ } else {
+ // Slow path: Build a byte array first then copy it.
+ return new String(readRawBytes(size), "UTF-8");
+ }
+ }
+
+ /** Read a {@code group} field value from the stream. */
+ public void readGroup(final MessageNano msg, final int fieldNumber)
+ throws IOException {
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
+ }
+ ++recursionDepth;
+ msg.mergeFrom(this);
+ checkLastTagWas(
+ WireFormatNano.makeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP));
+ --recursionDepth;
+ }
+
+ public void readMessage(final MessageNano msg)
+ throws IOException {
+ final int length = readRawVarint32();
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
+ }
+ final int oldLimit = pushLimit(length);
+ ++recursionDepth;
+ msg.mergeFrom(this);
+ checkLastTagWas(0);
+ --recursionDepth;
+ popLimit(oldLimit);
+ }
+
+ /** Read a {@code bytes} field value from the stream. */
+ public byte[] readBytes() throws IOException {
+ final int size = readRawVarint32();
+ if (size <= (bufferSize - bufferPos) && size > 0) {
+ // Fast path: We already have the bytes in a contiguous buffer, so
+ // just copy directly from it.
+ final byte[] result = new byte[size];
+ System.arraycopy(buffer, bufferPos, result, 0, size);
+ bufferPos += size;
+ return result;
+ } else {
+ // Slow path: Build a byte array first then copy it.
+ return readRawBytes(size);
+ }
+ }
+
+ /** Read a {@code uint32} field value from the stream. */
+ public int readUInt32() throws IOException {
+ return readRawVarint32();
+ }
+
+ /**
+ * Read an enum field value from the stream. Caller is responsible
+ * for converting the numeric value to an actual enum.
+ */
+ public int readEnum() throws IOException {
+ return readRawVarint32();
+ }
+
+ /** Read an {@code sfixed32} field value from the stream. */
+ public int readSFixed32() throws IOException {
+ return readRawLittleEndian32();
+ }
+
+ /** Read an {@code sfixed64} field value from the stream. */
+ public long readSFixed64() throws IOException {
+ return readRawLittleEndian64();
+ }
+
+ /** Read an {@code sint32} field value from the stream. */
+ public int readSInt32() throws IOException {
+ return decodeZigZag32(readRawVarint32());
+ }
+
+ /** Read an {@code sint64} field value from the stream. */
+ public long readSInt64() throws IOException {
+ return decodeZigZag64(readRawVarint64());
+ }
+
+ // =================================================================
+
+ /**
+ * Read a raw Varint from the stream. If larger than 32 bits, discard the
+ * upper bits.
+ */
+ public int readRawVarint32() throws IOException {
+ byte tmp = readRawByte();
+ if (tmp >= 0) {
+ return tmp;
+ }
+ int result = tmp & 0x7f;
+ if ((tmp = readRawByte()) >= 0) {
+ result |= tmp << 7;
+ } else {
+ result |= (tmp & 0x7f) << 7;
+ if ((tmp = readRawByte()) >= 0) {
+ result |= tmp << 14;
+ } else {
+ result |= (tmp & 0x7f) << 14;
+ if ((tmp = readRawByte()) >= 0) {
+ result |= tmp << 21;
+ } else {
+ result |= (tmp & 0x7f) << 21;
+ result |= (tmp = readRawByte()) << 28;
+ if (tmp < 0) {
+ // Discard upper 32 bits.
+ for (int i = 0; i < 5; i++) {
+ if (readRawByte() >= 0) {
+ return result;
+ }
+ }
+ throw InvalidProtocolBufferNanoException.malformedVarint();
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /** Read a raw Varint from the stream. */
+ public long readRawVarint64() throws IOException {
+ int shift = 0;
+ long result = 0;
+ while (shift < 64) {
+ final byte b = readRawByte();
+ result |= (long)(b & 0x7F) << shift;
+ if ((b & 0x80) == 0) {
+ return result;
+ }
+ shift += 7;
+ }
+ throw InvalidProtocolBufferNanoException.malformedVarint();
+ }
+
+ /** Read a 32-bit little-endian integer from the stream. */
+ public int readRawLittleEndian32() throws IOException {
+ final byte b1 = readRawByte();
+ final byte b2 = readRawByte();
+ final byte b3 = readRawByte();
+ final byte b4 = readRawByte();
+ return ((b1 & 0xff) ) |
+ ((b2 & 0xff) << 8) |
+ ((b3 & 0xff) << 16) |
+ ((b4 & 0xff) << 24);
+ }
+
+ /** Read a 64-bit little-endian integer from the stream. */
+ public long readRawLittleEndian64() throws IOException {
+ final byte b1 = readRawByte();
+ final byte b2 = readRawByte();
+ final byte b3 = readRawByte();
+ final byte b4 = readRawByte();
+ final byte b5 = readRawByte();
+ final byte b6 = readRawByte();
+ final byte b7 = readRawByte();
+ final byte b8 = readRawByte();
+ return (((long)b1 & 0xff) ) |
+ (((long)b2 & 0xff) << 8) |
+ (((long)b3 & 0xff) << 16) |
+ (((long)b4 & 0xff) << 24) |
+ (((long)b5 & 0xff) << 32) |
+ (((long)b6 & 0xff) << 40) |
+ (((long)b7 & 0xff) << 48) |
+ (((long)b8 & 0xff) << 56);
+ }
+
+ /**
+ * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n An unsigned 32-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ * @return A signed 32-bit integer.
+ */
+ public static int decodeZigZag32(final int n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+ /**
+ * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n An unsigned 64-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ * @return A signed 64-bit integer.
+ */
+ public static long decodeZigZag64(final long n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+ // -----------------------------------------------------------------
+
+ private final byte[] buffer;
+ private int bufferStart;
+ private int bufferSize;
+ private int bufferSizeAfterLimit;
+ private int bufferPos;
+ private int lastTag;
+
+ /** The absolute position of the end of the current message. */
+ private int currentLimit = Integer.MAX_VALUE;
+
+ /** See setRecursionLimit() */
+ private int recursionDepth;
+ private int recursionLimit = DEFAULT_RECURSION_LIMIT;
+
+ /** See setSizeLimit() */
+ private int sizeLimit = DEFAULT_SIZE_LIMIT;
+
+ private static final int DEFAULT_RECURSION_LIMIT = 64;
+ private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
+
+ private CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) {
+ this.buffer = buffer;
+ bufferStart = off;
+ bufferSize = off + len;
+ bufferPos = off;
+ }
+
+ /**
+ * Set the maximum message recursion depth. In order to prevent malicious
+ * messages from causing stack overflows, {@code CodedInputStream} limits
+ * how deeply messages may be nested. The default limit is 64.
+ *
+ * @return the old limit.
+ */
+ public int setRecursionLimit(final int limit) {
+ if (limit < 0) {
+ throw new IllegalArgumentException(
+ "Recursion limit cannot be negative: " + limit);
+ }
+ final int oldLimit = recursionLimit;
+ recursionLimit = limit;
+ return oldLimit;
+ }
+
+ /**
+ * Set the maximum message size. In order to prevent malicious
+ * messages from exhausting memory or causing integer overflows,
+ * {@code CodedInputStream} limits how large a message may be.
+ * The default limit is 64MB. You should set this limit as small
+ * as you can without harming your app's functionality. Note that
+ * size limits only apply when reading from an {@code InputStream}, not
+ * when constructed around a raw byte array.
+ * <p>
+ * If you want to read several messages from a single CodedInputStream, you
+ * could call {@link #resetSizeCounter()} after each one to avoid hitting the
+ * size limit.
+ *
+ * @return the old limit.
+ */
+ public int setSizeLimit(final int limit) {
+ if (limit < 0) {
+ throw new IllegalArgumentException(
+ "Size limit cannot be negative: " + limit);
+ }
+ final int oldLimit = sizeLimit;
+ sizeLimit = limit;
+ return oldLimit;
+ }
+
+ /**
+ * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
+ */
+ public void resetSizeCounter() {
+ }
+
+ /**
+ * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This
+ * is called when descending into a length-delimited embedded message.
+ *
+ * @return the old limit.
+ */
+ public int pushLimit(int byteLimit) throws InvalidProtocolBufferNanoException {
+ if (byteLimit < 0) {
+ throw InvalidProtocolBufferNanoException.negativeSize();
+ }
+ byteLimit += bufferPos;
+ final int oldLimit = currentLimit;
+ if (byteLimit > oldLimit) {
+ throw InvalidProtocolBufferNanoException.truncatedMessage();
+ }
+ currentLimit = byteLimit;
+
+ recomputeBufferSizeAfterLimit();
+
+ return oldLimit;
+ }
+
+ private void recomputeBufferSizeAfterLimit() {
+ bufferSize += bufferSizeAfterLimit;
+ final int bufferEnd = bufferSize;
+ if (bufferEnd > currentLimit) {
+ // Limit is in current buffer.
+ bufferSizeAfterLimit = bufferEnd - currentLimit;
+ bufferSize -= bufferSizeAfterLimit;
+ } else {
+ bufferSizeAfterLimit = 0;
+ }
+ }
+
+ /**
+ * Discards the current limit, returning to the previous limit.
+ *
+ * @param oldLimit The old limit, as returned by {@code pushLimit}.
+ */
+ public void popLimit(final int oldLimit) {
+ currentLimit = oldLimit;
+ recomputeBufferSizeAfterLimit();
+ }
+
+ /**
+ * Returns the number of bytes to be read before the current limit.
+ * If no limit is set, returns -1.
+ */
+ public int getBytesUntilLimit() {
+ if (currentLimit == Integer.MAX_VALUE) {
+ return -1;
+ }
+
+ final int currentAbsolutePosition = bufferPos;
+ return currentLimit - currentAbsolutePosition;
+ }
+
+ /**
+ * Returns true if the stream has reached the end of the input. This is the
+ * case if either the end of the underlying input source has been reached or
+ * if the stream has reached a limit created using {@link #pushLimit(int)}.
+ */
+ public boolean isAtEnd() {
+ return bufferPos == bufferSize;
+ }
+
+ /**
+ * Get current position in buffer relative to beginning offset.
+ */
+ public int getPosition() {
+ return bufferPos - bufferStart;
+ }
+
+ /**
+ * Retrieves a subset of data in the buffer. The returned array is not backed by the original
+ * buffer array.
+ *
+ * @param offset the position (relative to the buffer start position) to start at.
+ * @param length the number of bytes to retrieve.
+ */
+ public byte[] getData(int offset, int length) {
+ if (length == 0) {
+ return WireFormatNano.EMPTY_BYTES;
+ }
+ byte[] copy = new byte[length];
+ int start = bufferStart + offset;
+ System.arraycopy(buffer, start, copy, 0, length);
+ return copy;
+ }
+
+ /**
+ * Rewind to previous position. Cannot go forward.
+ */
+ public void rewindToPosition(int position) {
+ if (position > bufferPos - bufferStart) {
+ throw new IllegalArgumentException(
+ "Position " + position + " is beyond current " + (bufferPos - bufferStart));
+ }
+ if (position < 0) {
+ throw new IllegalArgumentException("Bad position " + position);
+ }
+ bufferPos = bufferStart + position;
+ }
+
+ /**
+ * Read one byte from the input.
+ *
+ * @throws InvalidProtocolBufferNanoException The end of the stream or the current
+ * limit was reached.
+ */
+ public byte readRawByte() throws IOException {
+ if (bufferPos == bufferSize) {
+ throw InvalidProtocolBufferNanoException.truncatedMessage();
+ }
+ return buffer[bufferPos++];
+ }
+
+ /**
+ * Read a fixed size of bytes from the input.
+ *
+ * @throws InvalidProtocolBufferNanoException The end of the stream or the current
+ * limit was reached.
+ */
+ public byte[] readRawBytes(final int size) throws IOException {
+ if (size < 0) {
+ throw InvalidProtocolBufferNanoException.negativeSize();
+ }
+
+ if (bufferPos + size > currentLimit) {
+ // Read to the end of the stream anyway.
+ skipRawBytes(currentLimit - bufferPos);
+ // Then fail.
+ throw InvalidProtocolBufferNanoException.truncatedMessage();
+ }
+
+ if (size <= bufferSize - bufferPos) {
+ // We have all the bytes we need already.
+ final byte[] bytes = new byte[size];
+ System.arraycopy(buffer, bufferPos, bytes, 0, size);
+ bufferPos += size;
+ return bytes;
+ } else {
+ throw InvalidProtocolBufferNanoException.truncatedMessage();
+ }
+ }
+
+ /**
+ * Reads and discards {@code size} bytes.
+ *
+ * @throws InvalidProtocolBufferNanoException The end of the stream or the current
+ * limit was reached.
+ */
+ public void skipRawBytes(final int size) throws IOException {
+ if (size < 0) {
+ throw InvalidProtocolBufferNanoException.negativeSize();
+ }
+
+ if (bufferPos + size > currentLimit) {
+ // Read to the end of the stream anyway.
+ skipRawBytes(currentLimit - bufferPos);
+ // Then fail.
+ throw InvalidProtocolBufferNanoException.truncatedMessage();
+ }
+
+ if (size <= bufferSize - bufferPos) {
+ // We have all the bytes we need already.
+ bufferPos += size;
+ } else {
+ throw InvalidProtocolBufferNanoException.truncatedMessage();
+ }
+ }
+
+ // Read a primitive type.
+ Object readPrimitiveField(int type) throws IOException {
+ switch (type) {
+ case InternalNano.TYPE_DOUBLE:
+ return readDouble();
+ case InternalNano.TYPE_FLOAT:
+ return readFloat();
+ case InternalNano.TYPE_INT64:
+ return readInt64();
+ case InternalNano.TYPE_UINT64:
+ return readUInt64();
+ case InternalNano.TYPE_INT32:
+ return readInt32();
+ case InternalNano.TYPE_FIXED64:
+ return readFixed64();
+ case InternalNano.TYPE_FIXED32:
+ return readFixed32();
+ case InternalNano.TYPE_BOOL:
+ return readBool();
+ case InternalNano.TYPE_STRING:
+ return readString();
+ case InternalNano.TYPE_BYTES:
+ return readBytes();
+ case InternalNano.TYPE_UINT32:
+ return readUInt32();
+ case InternalNano.TYPE_ENUM:
+ return readEnum();
+ case InternalNano.TYPE_SFIXED32:
+ return readSFixed32();
+ case InternalNano.TYPE_SFIXED64:
+ return readSFixed64();
+ case InternalNano.TYPE_SINT32:
+ return readSInt32();
+ case InternalNano.TYPE_SINT64:
+ return readSInt64();
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
new file mode 100644
index 00000000..2777f34c
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
@@ -0,0 +1,1003 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Encodes and writes protocol message fields.
+ *
+ * <p>This class contains two kinds of methods: methods that write specific
+ * protocol message constructs and field types (e.g. {@link #writeTag} and
+ * {@link #writeInt32}) and methods that write low-level values (e.g.
+ * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are
+ * writing encoded protocol messages, you should use the former methods, but if
+ * you are writing some other format of your own design, use the latter.
+ *
+ * <p>This class is totally unsynchronized.
+ *
+ * @author kneton@google.com Kenton Varda
+ */
+public final class CodedOutputByteBufferNano {
+ private final byte[] buffer;
+ private final int limit;
+ private int position;
+
+ private CodedOutputByteBufferNano(final byte[] buffer, final int offset,
+ final int length) {
+ this.buffer = buffer;
+ position = offset;
+ limit = offset + length;
+ }
+
+ /**
+ * Create a new {@code CodedOutputStream} that writes directly to the given
+ * byte array. If more bytes are written than fit in the array,
+ * {@link OutOfSpaceException} will be thrown. Writing directly to a flat
+ * array is faster than writing to an {@code OutputStream}.
+ */
+ public static CodedOutputByteBufferNano newInstance(final byte[] flatArray) {
+ return newInstance(flatArray, 0, flatArray.length);
+ }
+
+ /**
+ * Create a new {@code CodedOutputStream} that writes directly to the given
+ * byte array slice. If more bytes are written than fit in the slice,
+ * {@link OutOfSpaceException} will be thrown. Writing directly to a flat
+ * array is faster than writing to an {@code OutputStream}.
+ */
+ public static CodedOutputByteBufferNano newInstance(final byte[] flatArray,
+ final int offset,
+ final int length) {
+ return new CodedOutputByteBufferNano(flatArray, offset, length);
+ }
+
+ // -----------------------------------------------------------------
+
+ /** Write a {@code double} field, including tag, to the stream. */
+ public void writeDouble(final int fieldNumber, final double value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
+ writeDoubleNoTag(value);
+ }
+
+ /** Write a {@code float} field, including tag, to the stream. */
+ public void writeFloat(final int fieldNumber, final float value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
+ writeFloatNoTag(value);
+ }
+
+ /** Write a {@code uint64} field, including tag, to the stream. */
+ public void writeUInt64(final int fieldNumber, final long value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+ writeUInt64NoTag(value);
+ }
+
+ /** Write an {@code int64} field, including tag, to the stream. */
+ public void writeInt64(final int fieldNumber, final long value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+ writeInt64NoTag(value);
+ }
+
+ /** Write an {@code int32} field, including tag, to the stream. */
+ public void writeInt32(final int fieldNumber, final int value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+ writeInt32NoTag(value);
+ }
+
+ /** Write a {@code fixed64} field, including tag, to the stream. */
+ public void writeFixed64(final int fieldNumber, final long value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
+ writeFixed64NoTag(value);
+ }
+
+ /** Write a {@code fixed32} field, including tag, to the stream. */
+ public void writeFixed32(final int fieldNumber, final int value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
+ writeFixed32NoTag(value);
+ }
+
+ /** Write a {@code bool} field, including tag, to the stream. */
+ public void writeBool(final int fieldNumber, final boolean value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+ writeBoolNoTag(value);
+ }
+
+ /** Write a {@code string} field, including tag, to the stream. */
+ public void writeString(final int fieldNumber, final String value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+ writeStringNoTag(value);
+ }
+
+ /** Write a {@code group} field, including tag, to the stream. */
+ public void writeGroup(final int fieldNumber, final MessageNano value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_START_GROUP);
+ writeGroupNoTag(value);
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
+ }
+
+ /** Write an embedded message field, including tag, to the stream. */
+ public void writeMessage(final int fieldNumber, final MessageNano value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+ writeMessageNoTag(value);
+ }
+
+ /** Write a {@code bytes} field, including tag, to the stream. */
+ public void writeBytes(final int fieldNumber, final byte[] value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+ writeBytesNoTag(value);
+ }
+
+ /** Write a {@code uint32} field, including tag, to the stream. */
+ public void writeUInt32(final int fieldNumber, final int value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+ writeUInt32NoTag(value);
+ }
+
+ /**
+ * Write an enum field, including tag, to the stream. Caller is responsible
+ * for converting the enum value to its numeric value.
+ */
+ public void writeEnum(final int fieldNumber, final int value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+ writeEnumNoTag(value);
+ }
+
+ /** Write an {@code sfixed32} field, including tag, to the stream. */
+ public void writeSFixed32(final int fieldNumber, final int value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
+ writeSFixed32NoTag(value);
+ }
+
+ /** Write an {@code sfixed64} field, including tag, to the stream. */
+ public void writeSFixed64(final int fieldNumber, final long value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
+ writeSFixed64NoTag(value);
+ }
+
+ /** Write an {@code sint32} field, including tag, to the stream. */
+ public void writeSInt32(final int fieldNumber, final int value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+ writeSInt32NoTag(value);
+ }
+
+ /** Write an {@code sint64} field, including tag, to the stream. */
+ public void writeSInt64(final int fieldNumber, final long value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+ writeSInt64NoTag(value);
+ }
+
+ /**
+ * Write a MessageSet extension field to the stream. For historical reasons,
+ * the wire format differs from normal fields.
+ */
+// public void writeMessageSetExtension(final int fieldNumber,
+// final MessageMicro value)
+// throws IOException {
+// writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
+// writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
+// writeMessage(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+// writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
+// }
+
+ /**
+ * Write an unparsed MessageSet extension field to the stream. For
+ * historical reasons, the wire format differs from normal fields.
+ */
+// public void writeRawMessageSetExtension(final int fieldNumber,
+// final ByteStringMicro value)
+// throws IOException {
+// writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
+// writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
+// writeBytes(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+// writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
+// }
+
+ // -----------------------------------------------------------------
+
+ /** Write a {@code double} field to the stream. */
+ public void writeDoubleNoTag(final double value) throws IOException {
+ writeRawLittleEndian64(Double.doubleToLongBits(value));
+ }
+
+ /** Write a {@code float} field to the stream. */
+ public void writeFloatNoTag(final float value) throws IOException {
+ writeRawLittleEndian32(Float.floatToIntBits(value));
+ }
+
+ /** Write a {@code uint64} field to the stream. */
+ public void writeUInt64NoTag(final long value) throws IOException {
+ writeRawVarint64(value);
+ }
+
+ /** Write an {@code int64} field to the stream. */
+ public void writeInt64NoTag(final long value) throws IOException {
+ writeRawVarint64(value);
+ }
+
+ /** Write an {@code int32} field to the stream. */
+ public void writeInt32NoTag(final int value) throws IOException {
+ if (value >= 0) {
+ writeRawVarint32(value);
+ } else {
+ // Must sign-extend.
+ writeRawVarint64(value);
+ }
+ }
+
+ /** Write a {@code fixed64} field to the stream. */
+ public void writeFixed64NoTag(final long value) throws IOException {
+ writeRawLittleEndian64(value);
+ }
+
+ /** Write a {@code fixed32} field to the stream. */
+ public void writeFixed32NoTag(final int value) throws IOException {
+ writeRawLittleEndian32(value);
+ }
+
+ /** Write a {@code bool} field to the stream. */
+ public void writeBoolNoTag(final boolean value) throws IOException {
+ writeRawByte(value ? 1 : 0);
+ }
+
+ /** Write a {@code string} field to the stream. */
+ public void writeStringNoTag(final String value) throws IOException {
+ // Unfortunately there does not appear to be any way to tell Java to encode
+ // UTF-8 directly into our buffer, so we have to let it create its own byte
+ // array and then copy.
+ final byte[] bytes = value.getBytes("UTF-8");
+ writeRawVarint32(bytes.length);
+ writeRawBytes(bytes);
+ }
+
+ /** Write a {@code group} field to the stream. */
+ public void writeGroupNoTag(final MessageNano value) throws IOException {
+ value.writeTo(this);
+ }
+
+ /** Write an embedded message field to the stream. */
+ public void writeMessageNoTag(final MessageNano value) throws IOException {
+ writeRawVarint32(value.getCachedSize());
+ value.writeTo(this);
+ }
+
+ /** Write a {@code bytes} field to the stream. */
+ public void writeBytesNoTag(final byte[] value) throws IOException {
+ writeRawVarint32(value.length);
+ writeRawBytes(value);
+ }
+
+ /** Write a {@code uint32} field to the stream. */
+ public void writeUInt32NoTag(final int value) throws IOException {
+ writeRawVarint32(value);
+ }
+
+ /**
+ * Write an enum field to the stream. Caller is responsible
+ * for converting the enum value to its numeric value.
+ */
+ public void writeEnumNoTag(final int value) throws IOException {
+ writeRawVarint32(value);
+ }
+
+ /** Write an {@code sfixed32} field to the stream. */
+ public void writeSFixed32NoTag(final int value) throws IOException {
+ writeRawLittleEndian32(value);
+ }
+
+ /** Write an {@code sfixed64} field to the stream. */
+ public void writeSFixed64NoTag(final long value) throws IOException {
+ writeRawLittleEndian64(value);
+ }
+
+ /** Write an {@code sint32} field to the stream. */
+ public void writeSInt32NoTag(final int value) throws IOException {
+ writeRawVarint32(encodeZigZag32(value));
+ }
+
+ /** Write an {@code sint64} field to the stream. */
+ public void writeSInt64NoTag(final long value) throws IOException {
+ writeRawVarint64(encodeZigZag64(value));
+ }
+
+ // =================================================================
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code double} field, including tag.
+ */
+ public static int computeDoubleSize(final int fieldNumber,
+ final double value) {
+ return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code float} field, including tag.
+ */
+ public static int computeFloatSize(final int fieldNumber, final float value) {
+ return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint64} field, including tag.
+ */
+ public static int computeUInt64Size(final int fieldNumber, final long value) {
+ return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code int64} field, including tag.
+ */
+ public static int computeInt64Size(final int fieldNumber, final long value) {
+ return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code int32} field, including tag.
+ */
+ public static int computeInt32Size(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code fixed64} field, including tag.
+ */
+ public static int computeFixed64Size(final int fieldNumber,
+ final long value) {
+ return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code fixed32} field, including tag.
+ */
+ public static int computeFixed32Size(final int fieldNumber,
+ final int value) {
+ return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bool} field, including tag.
+ */
+ public static int computeBoolSize(final int fieldNumber,
+ final boolean value) {
+ return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code string} field, including tag.
+ */
+ public static int computeStringSize(final int fieldNumber,
+ final String value) {
+ return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field, including tag.
+ */
+ public static int computeGroupSize(final int fieldNumber,
+ final MessageNano value) {
+ return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * embedded message field, including tag.
+ */
+ public static int computeMessageSize(final int fieldNumber,
+ final MessageNano value) {
+ return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bytes} field, including tag.
+ */
+ public static int computeBytesSize(final int fieldNumber,
+ final byte[] value) {
+ return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint32} field, including tag.
+ */
+ public static int computeUInt32Size(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * enum field, including tag. Caller is responsible for converting the
+ * enum value to its numeric value.
+ */
+ public static int computeEnumSize(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed32} field, including tag.
+ */
+ public static int computeSFixed32Size(final int fieldNumber,
+ final int value) {
+ return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed64} field, including tag.
+ */
+ public static int computeSFixed64Size(final int fieldNumber,
+ final long value) {
+ return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint32} field, including tag.
+ */
+ public static int computeSInt32Size(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint64} field, including tag.
+ */
+ public static int computeSInt64Size(final int fieldNumber, final long value) {
+ return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * MessageSet extension to the stream. For historical reasons,
+ * the wire format differs from normal fields.
+ */
+// public static int computeMessageSetExtensionSize(
+// final int fieldNumber, final MessageMicro value) {
+// return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
+// computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
+// computeMessageSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+// }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * unparsed MessageSet extension field to the stream. For
+ * historical reasons, the wire format differs from normal fields.
+ */
+// public static int computeRawMessageSetExtensionSize(
+// final int fieldNumber, final ByteStringMicro value) {
+// return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
+// computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
+// computeBytesSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+// }
+
+ // -----------------------------------------------------------------
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code double} field, including tag.
+ */
+ public static int computeDoubleSizeNoTag(final double value) {
+ return LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code float} field, including tag.
+ */
+ public static int computeFloatSizeNoTag(final float value) {
+ return LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint64} field, including tag.
+ */
+ public static int computeUInt64SizeNoTag(final long value) {
+ return computeRawVarint64Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code int64} field, including tag.
+ */
+ public static int computeInt64SizeNoTag(final long value) {
+ return computeRawVarint64Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code int32} field, including tag.
+ */
+ public static int computeInt32SizeNoTag(final int value) {
+ if (value >= 0) {
+ return computeRawVarint32Size(value);
+ } else {
+ // Must sign-extend.
+ return 10;
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code fixed64} field.
+ */
+ public static int computeFixed64SizeNoTag(final long value) {
+ return LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code fixed32} field.
+ */
+ public static int computeFixed32SizeNoTag(final int value) {
+ return LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bool} field.
+ */
+ public static int computeBoolSizeNoTag(final boolean value) {
+ return 1;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code string} field.
+ */
+ public static int computeStringSizeNoTag(final String value) {
+ try {
+ final byte[] bytes = value.getBytes("UTF-8");
+ return computeRawVarint32Size(bytes.length) +
+ bytes.length;
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported.");
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field.
+ */
+ public static int computeGroupSizeNoTag(final MessageNano value) {
+ return value.getSerializedSize();
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an embedded
+ * message field.
+ */
+ public static int computeMessageSizeNoTag(final MessageNano value) {
+ final int size = value.getSerializedSize();
+ return computeRawVarint32Size(size) + size;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bytes} field.
+ */
+ public static int computeBytesSizeNoTag(final byte[] value) {
+ return computeRawVarint32Size(value.length) + value.length;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint32} field.
+ */
+ public static int computeUInt32SizeNoTag(final int value) {
+ return computeRawVarint32Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an enum field.
+ * Caller is responsible for converting the enum value to its numeric value.
+ */
+ public static int computeEnumSizeNoTag(final int value) {
+ return computeRawVarint32Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed32} field.
+ */
+ public static int computeSFixed32SizeNoTag(final int value) {
+ return LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed64} field.
+ */
+ public static int computeSFixed64SizeNoTag(final long value) {
+ return LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint32} field.
+ */
+ public static int computeSInt32SizeNoTag(final int value) {
+ return computeRawVarint32Size(encodeZigZag32(value));
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint64} field.
+ */
+ public static int computeSInt64SizeNoTag(final long value) {
+ return computeRawVarint64Size(encodeZigZag64(value));
+ }
+
+ // =================================================================
+
+ /**
+ * If writing to a flat array, return the space left in the array.
+ * Otherwise, throws {@code UnsupportedOperationException}.
+ */
+ public int spaceLeft() {
+ return limit - position;
+ }
+
+ /**
+ * Verifies that {@link #spaceLeft()} returns zero. It's common to create
+ * a byte array that is exactly big enough to hold a message, then write to
+ * it with a {@code CodedOutputStream}. Calling {@code checkNoSpaceLeft()}
+ * after writing verifies that the message was actually as big as expected,
+ * which can help catch bugs.
+ */
+ public void checkNoSpaceLeft() {
+ if (spaceLeft() != 0) {
+ throw new IllegalStateException(
+ "Did not write as much data as expected.");
+ }
+ }
+
+ /**
+ * If you create a CodedOutputStream around a simple flat array, you must
+ * not attempt to write more bytes than the array has space. Otherwise,
+ * this exception will be thrown.
+ */
+ public static class OutOfSpaceException extends IOException {
+ private static final long serialVersionUID = -6947486886997889499L;
+
+ OutOfSpaceException(int position, int limit) {
+ super("CodedOutputStream was writing to a flat byte array and ran " +
+ "out of space (pos " + position + " limit " + limit + ").");
+ }
+ }
+
+ /** Write a single byte. */
+ public void writeRawByte(final byte value) throws IOException {
+ if (position == limit) {
+ // We're writing to a single buffer.
+ throw new OutOfSpaceException(position, limit);
+ }
+
+ buffer[position++] = value;
+ }
+
+ /** Write a single byte, represented by an integer value. */
+ public void writeRawByte(final int value) throws IOException {
+ writeRawByte((byte) value);
+ }
+
+ /** Write an array of bytes. */
+ public void writeRawBytes(final byte[] value) throws IOException {
+ writeRawBytes(value, 0, value.length);
+ }
+
+ /** Write part of an array of bytes. */
+ public void writeRawBytes(final byte[] value, int offset, int length)
+ throws IOException {
+ if (limit - position >= length) {
+ // We have room in the current buffer.
+ System.arraycopy(value, offset, buffer, position, length);
+ position += length;
+ } else {
+ // We're writing to a single buffer.
+ throw new OutOfSpaceException(position, limit);
+ }
+ }
+
+ /** Encode and write a tag. */
+ public void writeTag(final int fieldNumber, final int wireType)
+ throws IOException {
+ writeRawVarint32(WireFormatNano.makeTag(fieldNumber, wireType));
+ }
+
+ /** Compute the number of bytes that would be needed to encode a tag. */
+ public static int computeTagSize(final int fieldNumber) {
+ return computeRawVarint32Size(WireFormatNano.makeTag(fieldNumber, 0));
+ }
+
+ /**
+ * Encode and write a varint. {@code value} is treated as
+ * unsigned, so it won't be sign-extended if negative.
+ */
+ public void writeRawVarint32(int value) throws IOException {
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ writeRawByte(value);
+ return;
+ } else {
+ writeRawByte((value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a varint.
+ * {@code value} is treated as unsigned, so it won't be sign-extended if
+ * negative.
+ */
+ public static int computeRawVarint32Size(final int value) {
+ if ((value & (0xffffffff << 7)) == 0) return 1;
+ if ((value & (0xffffffff << 14)) == 0) return 2;
+ if ((value & (0xffffffff << 21)) == 0) return 3;
+ if ((value & (0xffffffff << 28)) == 0) return 4;
+ return 5;
+ }
+
+ /** Encode and write a varint. */
+ public void writeRawVarint64(long value) throws IOException {
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ writeRawByte((int)value);
+ return;
+ } else {
+ writeRawByte(((int)value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ }
+
+ /** Compute the number of bytes that would be needed to encode a varint. */
+ public static int computeRawVarint64Size(final long value) {
+ if ((value & (0xffffffffffffffffL << 7)) == 0) return 1;
+ if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
+ if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
+ if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
+ if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
+ if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
+ if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
+ if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
+ if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
+ return 10;
+ }
+
+ /** Write a little-endian 32-bit integer. */
+ public void writeRawLittleEndian32(final int value) throws IOException {
+ writeRawByte((value ) & 0xFF);
+ writeRawByte((value >> 8) & 0xFF);
+ writeRawByte((value >> 16) & 0xFF);
+ writeRawByte((value >> 24) & 0xFF);
+ }
+
+ public static final int LITTLE_ENDIAN_32_SIZE = 4;
+
+ /** Write a little-endian 64-bit integer. */
+ public void writeRawLittleEndian64(final long value) throws IOException {
+ writeRawByte((int)(value ) & 0xFF);
+ writeRawByte((int)(value >> 8) & 0xFF);
+ writeRawByte((int)(value >> 16) & 0xFF);
+ writeRawByte((int)(value >> 24) & 0xFF);
+ writeRawByte((int)(value >> 32) & 0xFF);
+ writeRawByte((int)(value >> 40) & 0xFF);
+ writeRawByte((int)(value >> 48) & 0xFF);
+ writeRawByte((int)(value >> 56) & 0xFF);
+ }
+
+ public static final int LITTLE_ENDIAN_64_SIZE = 8;
+
+ /**
+ * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n A signed 32-bit integer.
+ * @return An unsigned 32-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ */
+ public static int encodeZigZag32(final int n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 31);
+ }
+
+ /**
+ * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n A signed 64-bit integer.
+ * @return An unsigned 64-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ */
+ public static long encodeZigZag64(final long n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 63);
+ }
+
+ static int computeFieldSize(int number, int type, Object object) {
+ switch (type) {
+ case InternalNano.TYPE_BOOL:
+ return computeBoolSize(number, (Boolean) object);
+ case InternalNano.TYPE_BYTES:
+ return computeBytesSize(number, (byte[]) object);
+ case InternalNano.TYPE_STRING:
+ return computeStringSize(number, (String) object);
+ case InternalNano.TYPE_FLOAT:
+ return computeFloatSize(number, (Float) object);
+ case InternalNano.TYPE_DOUBLE:
+ return computeDoubleSize(number, (Double) object);
+ case InternalNano.TYPE_ENUM:
+ return computeEnumSize(number, (Integer) object);
+ case InternalNano.TYPE_FIXED32:
+ return computeFixed32Size(number, (Integer) object);
+ case InternalNano.TYPE_INT32:
+ return computeInt32Size(number, (Integer) object);
+ case InternalNano.TYPE_UINT32:
+ return computeUInt32Size(number, (Integer) object);
+ case InternalNano.TYPE_SINT32:
+ return computeSInt32Size(number, (Integer) object);
+ case InternalNano.TYPE_SFIXED32:
+ return computeSFixed32Size(number, (Integer) object);
+ case InternalNano.TYPE_INT64:
+ return computeInt64Size(number, (Long) object);
+ case InternalNano.TYPE_UINT64:
+ return computeUInt64Size(number, (Long) object);
+ case InternalNano.TYPE_SINT64:
+ return computeSInt64Size(number, (Long) object);
+ case InternalNano.TYPE_FIXED64:
+ return computeFixed64Size(number, (Long) object);
+ case InternalNano.TYPE_SFIXED64:
+ return computeSFixed64Size(number, (Long) object);
+ case InternalNano.TYPE_MESSAGE:
+ return computeMessageSize(number, (MessageNano) object);
+ case InternalNano.TYPE_GROUP:
+ return computeGroupSize(number, (MessageNano) object);
+ default:
+ throw new IllegalArgumentException("Unknown type: " + type);
+ }
+ }
+
+ void writeField(int number, int type, Object value)
+ throws IOException {
+ switch (type) {
+ case InternalNano.TYPE_DOUBLE:
+ Double doubleValue = (Double) value;
+ writeDouble(number, doubleValue);
+ break;
+ case InternalNano.TYPE_FLOAT:
+ Float floatValue = (Float) value;
+ writeFloat(number, floatValue);
+ break;
+ case InternalNano.TYPE_INT64:
+ Long int64Value = (Long) value;
+ writeInt64(number, int64Value);
+ break;
+ case InternalNano.TYPE_UINT64:
+ Long uint64Value = (Long) value;
+ writeUInt64(number, uint64Value);
+ break;
+ case InternalNano.TYPE_INT32:
+ Integer int32Value = (Integer) value;
+ writeInt32(number, int32Value);
+ break;
+ case InternalNano.TYPE_FIXED64:
+ Long fixed64Value = (Long) value;
+ writeFixed64(number, fixed64Value);
+ break;
+ case InternalNano.TYPE_FIXED32:
+ Integer fixed32Value = (Integer) value;
+ writeFixed32(number, fixed32Value);
+ break;
+ case InternalNano.TYPE_BOOL:
+ Boolean boolValue = (Boolean) value;
+ writeBool(number, boolValue);
+ break;
+ case InternalNano.TYPE_STRING:
+ String stringValue = (String) value;
+ writeString(number, stringValue);
+ break;
+ case InternalNano.TYPE_BYTES:
+ byte[] bytesValue = (byte[]) value;
+ writeBytes(number, bytesValue);
+ break;
+ case InternalNano.TYPE_UINT32:
+ Integer uint32Value = (Integer) value;
+ writeUInt32(number, uint32Value);
+ break;
+ case InternalNano.TYPE_ENUM:
+ Integer enumValue = (Integer) value;
+ writeEnum(number, enumValue);
+ break;
+ case InternalNano.TYPE_SFIXED32:
+ Integer sfixed32Value = (Integer) value;
+ writeSFixed32(number, sfixed32Value);
+ break;
+ case InternalNano.TYPE_SFIXED64:
+ Long sfixed64Value = (Long) value;
+ writeSFixed64(number, sfixed64Value);
+ break;
+ case InternalNano.TYPE_SINT32:
+ Integer sint32Value = (Integer) value;
+ writeSInt32(number, sint32Value);
+ break;
+ case InternalNano.TYPE_SINT64:
+ Long sint64Value = (Long) value;
+ writeSInt64(number, sint64Value);
+ break;
+ case InternalNano.TYPE_MESSAGE:
+ MessageNano messageValue = (MessageNano) value;
+ writeMessage(number, messageValue);
+ break;
+ case InternalNano.TYPE_GROUP:
+ MessageNano groupValue = (MessageNano) value;
+ writeGroup(number, groupValue);
+ break;
+ default:
+ throw new IOException("Unknown type: " + type);
+ }
+ }
+
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
new file mode 100644
index 00000000..b979390d
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
@@ -0,0 +1,187 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.io.IOException;
+
+/**
+ * Base class of those Protocol Buffer messages that need to store unknown fields,
+ * such as extensions.
+ */
+public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>>
+ extends MessageNano {
+ /**
+ * A container for fields unknown to the message, including extensions. Extension fields can
+ * can be accessed through the {@link #getExtension} and {@link #setExtension} methods.
+ */
+ protected FieldArray unknownFieldData;
+
+ @Override
+ protected int computeSerializedSize() {
+ int size = 0;
+ if (unknownFieldData != null) {
+ for (int i = 0; i < unknownFieldData.size(); i++) {
+ FieldData field = unknownFieldData.dataAt(i);
+ size += field.computeSerializedSize();
+ }
+ }
+ return size;
+ }
+
+ @Override
+ public void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ if (unknownFieldData == null) {
+ return;
+ }
+ for (int i = 0; i < unknownFieldData.size(); i++) {
+ FieldData field = unknownFieldData.dataAt(i);
+ field.writeTo(output);
+ }
+ }
+
+ /**
+ * Checks if there is a value stored for the specified extension in this
+ * message.
+ */
+ public final boolean hasExtension(Extension<M, ?> extension) {
+ if (unknownFieldData == null) {
+ return false;
+ }
+ FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag));
+ return field != null;
+ }
+
+ /**
+ * Gets the value stored in the specified extension of this message.
+ */
+ public final <T> T getExtension(Extension<M, T> extension) {
+ if (unknownFieldData == null) {
+ return null;
+ }
+ FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag));
+ return field == null ? null : field.getValue(extension);
+ }
+
+ /**
+ * Sets the value of the specified extension of this message.
+ */
+ public final <T> M setExtension(Extension<M, T> extension, T value) {
+ int fieldNumber = WireFormatNano.getTagFieldNumber(extension.tag);
+ if (value == null) {
+ if (unknownFieldData != null) {
+ unknownFieldData.remove(fieldNumber);
+ if (unknownFieldData.isEmpty()) {
+ unknownFieldData = null;
+ }
+ }
+ } else {
+ FieldData field = null;
+ if (unknownFieldData == null) {
+ unknownFieldData = new FieldArray();
+ } else {
+ field = unknownFieldData.get(fieldNumber);
+ }
+ if (field == null) {
+ unknownFieldData.put(fieldNumber, new FieldData(extension, value));
+ } else {
+ field.setValue(extension, value);
+ }
+ }
+
+ @SuppressWarnings("unchecked") // Generated code should guarantee type safety
+ M typedThis = (M) this;
+ return typedThis;
+ }
+
+ /**
+ * Stores the binary data of an unknown field.
+ *
+ * <p>Generated messages will call this for unknown fields if the store_unknown_fields
+ * option is on.
+ *
+ * <p>Note that the tag might be a end-group tag (rather than the start of an unknown field) in
+ * which case we do not want to add an unknown field entry.
+ *
+ * @param input the input buffer.
+ * @param tag the tag of the field.
+
+ * @return {@literal true} unless the tag is an end-group tag.
+ */
+ protected final boolean storeUnknownField(CodedInputByteBufferNano input, int tag)
+ throws IOException {
+ int startPos = input.getPosition();
+ if (!input.skipField(tag)) {
+ return false; // This wasn't an unknown field, it's an end-group tag.
+ }
+ int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+ int endPos = input.getPosition();
+ byte[] bytes = input.getData(startPos, endPos - startPos);
+ UnknownFieldData unknownField = new UnknownFieldData(tag, bytes);
+
+ FieldData field = null;
+ if (unknownFieldData == null) {
+ unknownFieldData = new FieldArray();
+ } else {
+ field = unknownFieldData.get(fieldNumber);
+ }
+ if (field == null) {
+ field = new FieldData();
+ unknownFieldData.put(fieldNumber, field);
+ }
+ field.addUnknownField(unknownField);
+ return true;
+ }
+
+ /**
+ * Returns whether the stored unknown field data in this message is equivalent to that in the
+ * other message.
+ *
+ * @param other the other message.
+ * @return whether the two sets of unknown field data are equal.
+ */
+ protected final boolean unknownFieldDataEquals(M other) {
+ if (unknownFieldData == null || unknownFieldData.isEmpty()) {
+ return other.unknownFieldData == null || other.unknownFieldData.isEmpty();
+ } else {
+ return unknownFieldData.equals(other.unknownFieldData);
+ }
+ }
+
+ /**
+ * Computes the hashcode representing the unknown field data stored in this message.
+ *
+ * @return the hashcode for the unknown field data.
+ */
+ protected final int unknownFieldDataHashCode() {
+ return (unknownFieldData == null || unknownFieldData.isEmpty()
+ ? 0 : unknownFieldData.hashCode());
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/Extension.java b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
new file mode 100644
index 00000000..c29b030f
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
@@ -0,0 +1,687 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents an extension.
+ *
+ * @author bduff@google.com (Brian Duff)
+ * @author maxtroy@google.com (Max Cai)
+ * @param <M> the type of the extendable message this extension is for.
+ * @param <T> the Java type of the extension; see {@link #clazz}.
+ */
+public class Extension<M extends ExtendableMessageNano<M>, T> {
+
+ /*
+ * Because we typically only define message-typed extensions, the Extension class hierarchy is
+ * designed as follows, to allow a big amount of code in this file to be removed by ProGuard:
+ *
+ * Extension // ready to use for message/group typed extensions
+ * Δ
+ * |
+ * PrimitiveExtension // for primitive/enum typed extensions
+ */
+
+ public static final int TYPE_DOUBLE = InternalNano.TYPE_DOUBLE;
+ public static final int TYPE_FLOAT = InternalNano.TYPE_FLOAT;
+ public static final int TYPE_INT64 = InternalNano.TYPE_INT64;
+ public static final int TYPE_UINT64 = InternalNano.TYPE_UINT64;
+ public static final int TYPE_INT32 = InternalNano.TYPE_INT32;
+ public static final int TYPE_FIXED64 = InternalNano.TYPE_FIXED64;
+ public static final int TYPE_FIXED32 = InternalNano.TYPE_FIXED32;
+ public static final int TYPE_BOOL = InternalNano.TYPE_BOOL;
+ public static final int TYPE_STRING = InternalNano.TYPE_STRING;
+ public static final int TYPE_GROUP = InternalNano.TYPE_GROUP;
+ public static final int TYPE_MESSAGE = InternalNano.TYPE_MESSAGE;
+ public static final int TYPE_BYTES = InternalNano.TYPE_BYTES;
+ public static final int TYPE_UINT32 = InternalNano.TYPE_UINT32;
+ public static final int TYPE_ENUM = InternalNano.TYPE_ENUM;
+ public static final int TYPE_SFIXED32 = InternalNano.TYPE_SFIXED32;
+ public static final int TYPE_SFIXED64 = InternalNano.TYPE_SFIXED64;
+ public static final int TYPE_SINT32 = InternalNano.TYPE_SINT32;
+ public static final int TYPE_SINT64 = InternalNano.TYPE_SINT64;
+
+ /**
+ * Creates an {@code Extension} of the given message type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+ */
+ public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+ Extension<M, T> createMessageTyped(int type, Class<T> clazz, int tag) {
+ return new Extension<M, T>(type, clazz, tag, false);
+ }
+
+ /**
+ * Creates a repeated {@code Extension} of the given message type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+ */
+ public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+ Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, int tag) {
+ return new Extension<M, T[]>(type, clazz, tag, true);
+ }
+
+ /**
+ * Creates an {@code Extension} of the given primitive type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
+ * @param clazz the boxed Java type of this extension
+ */
+ public static <M extends ExtendableMessageNano<M>, T>
+ Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, int tag) {
+ return new PrimitiveExtension<M, T>(type, clazz, tag, false, 0, 0);
+ }
+
+ /**
+ * Creates a repeated {@code Extension} of the given primitive type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
+ * @param clazz the Java array type of this extension, with an unboxed component type
+ */
+ public static <M extends ExtendableMessageNano<M>, T>
+ Extension<M, T> createRepeatedPrimitiveTyped(
+ int type, Class<T> clazz, int tag, int nonPackedTag, int packedTag) {
+ return new PrimitiveExtension<M, T>(type, clazz, tag, true, nonPackedTag, packedTag);
+ }
+
+ /**
+ * Protocol Buffer type of this extension; one of the {@code TYPE_} constants.
+ */
+ protected final int type;
+
+ /**
+ * Java type of this extension. For a singular extension, this is the boxed Java type for the
+ * Protocol Buffer {@link #type}; for a repeated extension, this is an array type whose
+ * component type is the unboxed Java type for {@link #type}. For example, for a singular
+ * {@code int32}/{@link #TYPE_INT32} extension, this equals {@code Integer.class}; for a
+ * repeated {@code int32} extension, this equals {@code int[].class}.
+ */
+ protected final Class<T> clazz;
+
+ /**
+ * Tag number of this extension.
+ */
+ public final int tag;
+
+ /**
+ * Whether this extension is repeated.
+ */
+ protected final boolean repeated;
+
+ private Extension(int type, Class<T> clazz, int tag, boolean repeated) {
+ this.type = type;
+ this.clazz = clazz;
+ this.tag = tag;
+ this.repeated = repeated;
+ }
+
+ /**
+ * Returns the value of this extension stored in the given list of unknown fields, or
+ * {@code null} if no unknown fields matches this extension.
+ *
+ * @param unknownFields a list of {@link UnknownFieldData}. All of the elements must have a tag
+ * that matches this Extension's tag.
+ *
+ */
+ final T getValueFrom(List<UnknownFieldData> unknownFields) {
+ if (unknownFields == null) {
+ return null;
+ }
+ return repeated ? getRepeatedValueFrom(unknownFields) : getSingularValueFrom(unknownFields);
+ }
+
+ private T getRepeatedValueFrom(List<UnknownFieldData> unknownFields) {
+ // For repeated extensions, read all matching unknown fields in their original order.
+ List<Object> resultList = new ArrayList<Object>();
+ for (int i = 0; i < unknownFields.size(); i++) {
+ UnknownFieldData data = unknownFields.get(i);
+ if (data.bytes.length != 0) {
+ readDataInto(data, resultList);
+ }
+ }
+
+ int resultSize = resultList.size();
+ if (resultSize == 0) {
+ return null;
+ } else {
+ T result = clazz.cast(Array.newInstance(clazz.getComponentType(), resultSize));
+ for (int i = 0; i < resultSize; i++) {
+ Array.set(result, i, resultList.get(i));
+ }
+ return result;
+ }
+ }
+
+ private T getSingularValueFrom(List<UnknownFieldData> unknownFields) {
+ // For singular extensions, get the last piece of data stored under this extension.
+ if (unknownFields.isEmpty()) {
+ return null;
+ }
+ UnknownFieldData lastData = unknownFields.get(unknownFields.size() - 1);
+ return clazz.cast(readData(CodedInputByteBufferNano.newInstance(lastData.bytes)));
+ }
+
+ protected Object readData(CodedInputByteBufferNano input) {
+ // This implementation is for message/group extensions.
+ Class<?> messageType = repeated ? clazz.getComponentType() : clazz;
+ try {
+ switch (type) {
+ case TYPE_GROUP:
+ MessageNano group = (MessageNano) messageType.newInstance();
+ input.readGroup(group, WireFormatNano.getTagFieldNumber(tag));
+ return group;
+ case TYPE_MESSAGE:
+ MessageNano message = (MessageNano) messageType.newInstance();
+ input.readMessage(message);
+ return message;
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (InstantiationException e) {
+ throw new IllegalArgumentException(
+ "Error creating instance of class " + messageType, e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException(
+ "Error creating instance of class " + messageType, e);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ }
+
+ protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
+ // This implementation is for message/group extensions.
+ resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
+ }
+
+ void writeTo(Object value, CodedOutputByteBufferNano output) throws IOException {
+ if (repeated) {
+ writeRepeatedData(value, output);
+ } else {
+ writeSingularData(value, output);
+ }
+ }
+
+ protected void writeSingularData(Object value, CodedOutputByteBufferNano out) {
+ // This implementation is for message/group extensions.
+ try {
+ out.writeRawVarint32(tag);
+ switch (type) {
+ case TYPE_GROUP:
+ MessageNano groupValue = (MessageNano) value;
+ int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+ out.writeGroupNoTag(groupValue);
+ // The endgroup tag must be included in the data payload.
+ out.writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
+ break;
+ case TYPE_MESSAGE:
+ MessageNano messageValue = (MessageNano) value;
+ out.writeMessageNoTag(messageValue);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (IOException e) {
+ // Should not happen
+ throw new IllegalStateException(e);
+ }
+ }
+
+ protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
+ // This implementation is for non-packed extensions.
+ int arrayLength = Array.getLength(array);
+ for (int i = 0; i < arrayLength; i++) {
+ Object element = Array.get(array, i);
+ if (element != null) {
+ writeSingularData(element, output);
+ }
+ }
+ }
+
+ int computeSerializedSize(Object value) {
+ if (repeated) {
+ return computeRepeatedSerializedSize(value);
+ } else {
+ return computeSingularSerializedSize(value);
+ }
+ }
+
+ protected int computeRepeatedSerializedSize(Object array) {
+ // This implementation is for non-packed extensions.
+ int size = 0;
+ int arrayLength = Array.getLength(array);
+ for (int i = 0; i < arrayLength; i++) {
+ Object element = Array.get(array, i);
+ if (element != null) {
+ size += computeSingularSerializedSize(Array.get(array, i));
+ }
+ }
+ return size;
+ }
+
+ protected int computeSingularSerializedSize(Object value) {
+ // This implementation is for message/group extensions.
+ int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+ switch (type) {
+ case TYPE_GROUP:
+ MessageNano groupValue = (MessageNano) value;
+ return CodedOutputByteBufferNano.computeGroupSize(fieldNumber, groupValue);
+ case TYPE_MESSAGE:
+ MessageNano messageValue = (MessageNano) value;
+ return CodedOutputByteBufferNano.computeMessageSize(fieldNumber, messageValue);
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ }
+
+ /**
+ * Represents an extension of a primitive (including enum) type. If there is no primitive
+ * extensions, this subclass will be removable by ProGuard.
+ */
+ private static class PrimitiveExtension<M extends ExtendableMessageNano<M>, T>
+ extends Extension<M, T> {
+
+ /**
+ * Tag of a piece of non-packed data from the wire compatible with this extension.
+ */
+ private final int nonPackedTag;
+
+ /**
+ * Tag of a piece of packed data from the wire compatible with this extension.
+ * 0 if the type of this extension is not packable.
+ */
+ private final int packedTag;
+
+ public PrimitiveExtension(int type, Class<T> clazz, int tag, boolean repeated,
+ int nonPackedTag, int packedTag) {
+ super(type, clazz, tag, repeated);
+ this.nonPackedTag = nonPackedTag;
+ this.packedTag = packedTag;
+ }
+
+ @Override
+ protected Object readData(CodedInputByteBufferNano input) {
+ try {
+ return input.readPrimitiveField(type);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ }
+
+ @Override
+ protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
+ // This implementation is for primitive typed extensions,
+ // which can read both packed and non-packed data.
+ if (data.tag == nonPackedTag) {
+ resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
+ } else {
+ CodedInputByteBufferNano buffer =
+ CodedInputByteBufferNano.newInstance(data.bytes);
+ try {
+ buffer.pushLimit(buffer.readRawVarint32()); // length limit
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ while (!buffer.isAtEnd()) {
+ resultList.add(readData(buffer));
+ }
+ }
+ }
+
+ @Override
+ protected final void writeSingularData(Object value, CodedOutputByteBufferNano output) {
+ try {
+ output.writeRawVarint32(tag);
+ switch (type) {
+ case TYPE_DOUBLE:
+ Double doubleValue = (Double) value;
+ output.writeDoubleNoTag(doubleValue);
+ break;
+ case TYPE_FLOAT:
+ Float floatValue = (Float) value;
+ output.writeFloatNoTag(floatValue);
+ break;
+ case TYPE_INT64:
+ Long int64Value = (Long) value;
+ output.writeInt64NoTag(int64Value);
+ break;
+ case TYPE_UINT64:
+ Long uint64Value = (Long) value;
+ output.writeUInt64NoTag(uint64Value);
+ break;
+ case TYPE_INT32:
+ Integer int32Value = (Integer) value;
+ output.writeInt32NoTag(int32Value);
+ break;
+ case TYPE_FIXED64:
+ Long fixed64Value = (Long) value;
+ output.writeFixed64NoTag(fixed64Value);
+ break;
+ case TYPE_FIXED32:
+ Integer fixed32Value = (Integer) value;
+ output.writeFixed32NoTag(fixed32Value);
+ break;
+ case TYPE_BOOL:
+ Boolean boolValue = (Boolean) value;
+ output.writeBoolNoTag(boolValue);
+ break;
+ case TYPE_STRING:
+ String stringValue = (String) value;
+ output.writeStringNoTag(stringValue);
+ break;
+ case TYPE_BYTES:
+ byte[] bytesValue = (byte[]) value;
+ output.writeBytesNoTag(bytesValue);
+ break;
+ case TYPE_UINT32:
+ Integer uint32Value = (Integer) value;
+ output.writeUInt32NoTag(uint32Value);
+ break;
+ case TYPE_ENUM:
+ Integer enumValue = (Integer) value;
+ output.writeEnumNoTag(enumValue);
+ break;
+ case TYPE_SFIXED32:
+ Integer sfixed32Value = (Integer) value;
+ output.writeSFixed32NoTag(sfixed32Value);
+ break;
+ case TYPE_SFIXED64:
+ Long sfixed64Value = (Long) value;
+ output.writeSFixed64NoTag(sfixed64Value);
+ break;
+ case TYPE_SINT32:
+ Integer sint32Value = (Integer) value;
+ output.writeSInt32NoTag(sint32Value);
+ break;
+ case TYPE_SINT64:
+ Long sint64Value = (Long) value;
+ output.writeSInt64NoTag(sint64Value);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (IOException e) {
+ // Should not happen
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
+ if (tag == nonPackedTag) {
+ // Use base implementation for non-packed data
+ super.writeRepeatedData(array, output);
+ } else if (tag == packedTag) {
+ // Packed. Note that the array element type is guaranteed to be primitive, so there
+ // won't be any null elements, so no null check in this block.
+ int arrayLength = Array.getLength(array);
+ int dataSize = computePackedDataSize(array);
+
+ try {
+ output.writeRawVarint32(tag);
+ output.writeRawVarint32(dataSize);
+ switch (type) {
+ case TYPE_BOOL:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeBoolNoTag(Array.getBoolean(array, i));
+ }
+ break;
+ case TYPE_FIXED32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeFixed32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_SFIXED32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSFixed32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_FLOAT:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeFloatNoTag(Array.getFloat(array, i));
+ }
+ break;
+ case TYPE_FIXED64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeFixed64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_SFIXED64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSFixed64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_DOUBLE:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeDoubleNoTag(Array.getDouble(array, i));
+ }
+ break;
+ case TYPE_INT32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeInt32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_SINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSInt32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_UINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeUInt32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_INT64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeInt64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_SINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSInt64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_UINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeUInt64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_ENUM:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeEnumNoTag(Array.getInt(array, i));
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unpackable type " + type);
+ }
+ } catch (IOException e) {
+ // Should not happen.
+ throw new IllegalStateException(e);
+ }
+ } else {
+ throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
+ + ", unequal to both non-packed variant " + nonPackedTag
+ + " and packed variant " + packedTag);
+ }
+ }
+
+ private int computePackedDataSize(Object array) {
+ int dataSize = 0;
+ int arrayLength = Array.getLength(array);
+ switch (type) {
+ case TYPE_BOOL:
+ // Bools are stored as int32 but just as 0 or 1, so 1 byte each.
+ dataSize = arrayLength;
+ break;
+ case TYPE_FIXED32:
+ case TYPE_SFIXED32:
+ case TYPE_FLOAT:
+ dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_32_SIZE;
+ break;
+ case TYPE_FIXED64:
+ case TYPE_SFIXED64:
+ case TYPE_DOUBLE:
+ dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_64_SIZE;
+ break;
+ case TYPE_INT32:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeInt32SizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ case TYPE_SINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeSInt32SizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ case TYPE_UINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeUInt32SizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ case TYPE_INT64:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeInt64SizeNoTag(
+ Array.getLong(array, i));
+ }
+ break;
+ case TYPE_SINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeSInt64SizeNoTag(
+ Array.getLong(array, i));
+ }
+ break;
+ case TYPE_UINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeUInt64SizeNoTag(
+ Array.getLong(array, i));
+ }
+ break;
+ case TYPE_ENUM:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeEnumSizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected non-packable type " + type);
+ }
+ return dataSize;
+ }
+
+ @Override
+ protected int computeRepeatedSerializedSize(Object array) {
+ if (tag == nonPackedTag) {
+ // Use base implementation for non-packed data
+ return super.computeRepeatedSerializedSize(array);
+ } else if (tag == packedTag) {
+ // Packed.
+ int dataSize = computePackedDataSize(array);
+ int payloadSize =
+ dataSize + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
+ return payloadSize + CodedOutputByteBufferNano.computeRawVarint32Size(tag);
+ } else {
+ throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
+ + ", unequal to both non-packed variant " + nonPackedTag
+ + " and packed variant " + packedTag);
+ }
+ }
+
+ @Override
+ protected final int computeSingularSerializedSize(Object value) {
+ int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+ switch (type) {
+ case TYPE_DOUBLE:
+ Double doubleValue = (Double) value;
+ return CodedOutputByteBufferNano.computeDoubleSize(fieldNumber, doubleValue);
+ case TYPE_FLOAT:
+ Float floatValue = (Float) value;
+ return CodedOutputByteBufferNano.computeFloatSize(fieldNumber, floatValue);
+ case TYPE_INT64:
+ Long int64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeInt64Size(fieldNumber, int64Value);
+ case TYPE_UINT64:
+ Long uint64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeUInt64Size(fieldNumber, uint64Value);
+ case TYPE_INT32:
+ Integer int32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeInt32Size(fieldNumber, int32Value);
+ case TYPE_FIXED64:
+ Long fixed64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeFixed64Size(fieldNumber, fixed64Value);
+ case TYPE_FIXED32:
+ Integer fixed32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeFixed32Size(fieldNumber, fixed32Value);
+ case TYPE_BOOL:
+ Boolean boolValue = (Boolean) value;
+ return CodedOutputByteBufferNano.computeBoolSize(fieldNumber, boolValue);
+ case TYPE_STRING:
+ String stringValue = (String) value;
+ return CodedOutputByteBufferNano.computeStringSize(fieldNumber, stringValue);
+ case TYPE_BYTES:
+ byte[] bytesValue = (byte[]) value;
+ return CodedOutputByteBufferNano.computeBytesSize(fieldNumber, bytesValue);
+ case TYPE_UINT32:
+ Integer uint32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeUInt32Size(fieldNumber, uint32Value);
+ case TYPE_ENUM:
+ Integer enumValue = (Integer) value;
+ return CodedOutputByteBufferNano.computeEnumSize(fieldNumber, enumValue);
+ case TYPE_SFIXED32:
+ Integer sfixed32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeSFixed32Size(fieldNumber,
+ sfixed32Value);
+ case TYPE_SFIXED64:
+ Long sfixed64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeSFixed64Size(fieldNumber,
+ sfixed64Value);
+ case TYPE_SINT32:
+ Integer sint32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeSInt32Size(fieldNumber, sint32Value);
+ case TYPE_SINT64:
+ Long sint64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeSInt64Size(fieldNumber, sint64Value);
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ }
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
new file mode 100644
index 00000000..cdb66da2
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
@@ -0,0 +1,273 @@
+// 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.
+
+package com.google.protobuf.nano;
+
+
+/**
+ * A custom version of {@link android.util.SparseArray} with the minimal API
+ * for storing {@link FieldData} objects.
+ *
+ * Based on {@link android.support.v4.util.SpareArrayCompat}.
+ */
+class FieldArray {
+ private static final FieldData DELETED = new FieldData();
+ private boolean mGarbage = false;
+
+ private int[] mFieldNumbers;
+ private FieldData[] mData;
+ private int mSize;
+
+ /**
+ * Creates a new FieldArray containing no fields.
+ */
+ public FieldArray() {
+ this(10);
+ }
+
+ /**
+ * Creates a new FieldArray containing no mappings that will not
+ * require any additional memory allocation to store the specified
+ * number of mappings.
+ */
+ public FieldArray(int initialCapacity) {
+ initialCapacity = idealIntArraySize(initialCapacity);
+ mFieldNumbers = new int[initialCapacity];
+ mData = new FieldData[initialCapacity];
+ mSize = 0;
+ }
+
+ /**
+ * Gets the FieldData mapped from the specified fieldNumber, or <code>null</code>
+ * if no such mapping has been made.
+ */
+ public FieldData get(int fieldNumber) {
+ int i = binarySearch(fieldNumber);
+
+ if (i < 0 || mData[i] == DELETED) {
+ return null;
+ } else {
+ return mData[i];
+ }
+ }
+
+ /**
+ * Removes the data from the specified fieldNumber, if there was any.
+ */
+ public void remove(int fieldNumber) {
+ int i = binarySearch(fieldNumber);
+
+ if (i >= 0 && mData[i] != DELETED) {
+ mData[i] = DELETED;
+ mGarbage = true;
+ }
+ }
+
+ private void gc() {
+ int n = mSize;
+ int o = 0;
+ int[] keys = mFieldNumbers;
+ FieldData[] values = mData;
+
+ for (int i = 0; i < n; i++) {
+ FieldData val = values[i];
+
+ if (val != DELETED) {
+ if (i != o) {
+ keys[o] = keys[i];
+ values[o] = val;
+ values[i] = null;
+ }
+
+ o++;
+ }
+ }
+
+ mGarbage = false;
+ mSize = o;
+ }
+
+ /**
+ * Adds a mapping from the specified fieldNumber to the specified data,
+ * replacing the previous mapping if there was one.
+ */
+ public void put(int fieldNumber, FieldData data) {
+ int i = binarySearch(fieldNumber);
+
+ if (i >= 0) {
+ mData[i] = data;
+ } else {
+ i = ~i;
+
+ if (i < mSize && mData[i] == DELETED) {
+ mFieldNumbers[i] = fieldNumber;
+ mData[i] = data;
+ return;
+ }
+
+ if (mGarbage && mSize >= mFieldNumbers.length) {
+ gc();
+
+ // Search again because indices may have changed.
+ i = ~ binarySearch(fieldNumber);
+ }
+
+ if (mSize >= mFieldNumbers.length) {
+ int n = idealIntArraySize(mSize + 1);
+
+ int[] nkeys = new int[n];
+ FieldData[] nvalues = new FieldData[n];
+
+ System.arraycopy(mFieldNumbers, 0, nkeys, 0, mFieldNumbers.length);
+ System.arraycopy(mData, 0, nvalues, 0, mData.length);
+
+ mFieldNumbers = nkeys;
+ mData = nvalues;
+ }
+
+ if (mSize - i != 0) {
+ System.arraycopy(mFieldNumbers, i, mFieldNumbers, i + 1, mSize - i);
+ System.arraycopy(mData, i, mData, i + 1, mSize - i);
+ }
+
+ mFieldNumbers[i] = fieldNumber;
+ mData[i] = data;
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this FieldArray
+ * currently stores.
+ */
+ public int size() {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mSize;
+ }
+
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * FieldArray stores.
+ */
+ public FieldData dataAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mData[index];
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof FieldArray)) {
+ return false;
+ }
+
+ FieldArray other = (FieldArray) o;
+ if (size() != other.size()) { // size() will call gc() if necessary.
+ return false;
+ }
+ return arrayEquals(mFieldNumbers, other.mFieldNumbers, mSize) &&
+ arrayEquals(mData, other.mData, mSize);
+ }
+
+ @Override
+ public int hashCode() {
+ if (mGarbage) {
+ gc();
+ }
+ int result = 17;
+ for (int i = 0; i < mSize; i++) {
+ result = 31 * result + mFieldNumbers[i];
+ result = 31 * result + mData[i].hashCode();
+ }
+ return result;
+ }
+
+ private int idealIntArraySize(int need) {
+ return idealByteArraySize(need * 4) / 4;
+ }
+
+ private int idealByteArraySize(int need) {
+ for (int i = 4; i < 32; i++)
+ if (need <= (1 << i) - 12)
+ return (1 << i) - 12;
+
+ return need;
+ }
+
+ private int binarySearch(int value) {
+ int lo = 0;
+ int hi = mSize - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ int midVal = mFieldNumbers[mid];
+
+ if (midVal < value) {
+ lo = mid + 1;
+ } else if (midVal > value) {
+ hi = mid - 1;
+ } else {
+ return mid; // value found
+ }
+ }
+ return ~lo; // value not present
+ }
+
+ private boolean arrayEquals(int[] a, int[] b, int size) {
+ for (int i = 0; i < size; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean arrayEquals(FieldData[] a, FieldData[] b, int size) {
+ for (int i = 0; i < size; i++) {
+ if (!a[i].equals(b[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldData.java b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
new file mode 100644
index 00000000..21ead88b
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
@@ -0,0 +1,190 @@
+// 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Stores unknown fields. These might be extensions or fields that the generated API doesn't
+ * know about yet.
+ */
+class FieldData {
+ private Extension<?, ?> cachedExtension;
+ private Object value;
+ /** The serialised values for this object. Will be cleared if getValue is called */
+ private List<UnknownFieldData> unknownFieldData;
+
+ <T> FieldData(Extension<?, T> extension, T newValue) {
+ cachedExtension = extension;
+ value = newValue;
+ }
+
+ FieldData() {
+ unknownFieldData = new ArrayList<UnknownFieldData>();
+ }
+
+ void addUnknownField(UnknownFieldData unknownField) {
+ unknownFieldData.add(unknownField);
+ }
+
+ UnknownFieldData getUnknownField(int index) {
+ if (unknownFieldData == null) {
+ return null;
+ }
+ if (index < unknownFieldData.size()) {
+ return unknownFieldData.get(index);
+ }
+ return null;
+ }
+
+ int getUnknownFieldSize() {
+ if (unknownFieldData == null) {
+ return 0;
+ }
+ return unknownFieldData.size();
+ }
+
+ <T> T getValue(Extension<?, T> extension) {
+ if (value != null){
+ if (cachedExtension != extension) { // Extension objects are singletons.
+ throw new IllegalStateException(
+ "Tried to getExtension with a differernt Extension.");
+ }
+ } else {
+ cachedExtension = extension;
+ value = extension.getValueFrom(unknownFieldData);
+ unknownFieldData = null;
+ }
+ return (T) value;
+ }
+
+ <T> void setValue(Extension<?, T> extension, T newValue) {
+ cachedExtension = extension;
+ value = newValue;
+ unknownFieldData = null;
+ }
+
+ int computeSerializedSize() {
+ int size = 0;
+ if (value != null) {
+ size = cachedExtension.computeSerializedSize(value);
+ } else {
+ for (UnknownFieldData unknownField : unknownFieldData) {
+ size += unknownField.computeSerializedSize();
+ }
+ }
+ return size;
+ }
+
+ void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ if (value != null) {
+ cachedExtension.writeTo(value, output);
+ } else {
+ for (UnknownFieldData unknownField : unknownFieldData) {
+ unknownField.writeTo(output);
+ }
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof FieldData)) {
+ return false;
+ }
+
+ FieldData other = (FieldData) o;
+ if (value != null && other.value != null) {
+ // If both objects have deserialized values, compare those.
+ // Since unknown fields are only compared if messages have generated equals methods
+ // we know this will be a meaningful comparison (not identity) for all values.
+ if (cachedExtension != other.cachedExtension) { // Extension objects are singletons.
+ return false;
+ }
+ if (!cachedExtension.clazz.isArray()) {
+ // Can't test (!cachedExtension.repeated) due to 'bytes' -> 'byte[]'
+ return value.equals(other.value);
+ }
+ if (value instanceof byte[]) {
+ return Arrays.equals((byte[]) value, (byte[]) other.value);
+ } else if (value instanceof int[]) {
+ return Arrays.equals((int[]) value, (int[]) other.value);
+ } else if (value instanceof long[]) {
+ return Arrays.equals((long[]) value, (long[]) other.value);
+ } else if (value instanceof float[]) {
+ return Arrays.equals((float[]) value, (float[]) other.value);
+ } else if (value instanceof double[]) {
+ return Arrays.equals((double[]) value, (double[]) other.value);
+ } else if (value instanceof boolean[]) {
+ return Arrays.equals((boolean[]) value, (boolean[]) other.value);
+ } else {
+ return Arrays.deepEquals((Object[]) value, (Object[]) other.value);
+ }
+ }
+ if (unknownFieldData != null && other.unknownFieldData != null) {
+ // If both objects have byte arrays compare those directly.
+ return unknownFieldData.equals(other.unknownFieldData);
+ }
+ try {
+ // As a last resort, serialize and compare the resulting byte arrays.
+ return Arrays.equals(toByteArray(), other.toByteArray());
+ } catch (IOException e) {
+ // Should not happen.
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ try {
+ // The only way to generate a consistent hash is to use the serialized form.
+ result = 31 * result + Arrays.hashCode(toByteArray());
+ } catch (IOException e) {
+ // Should not happen.
+ throw new IllegalStateException(e);
+ }
+ return result;
+ }
+
+ private byte[] toByteArray() throws IOException {
+ byte[] result = new byte[computeSerializedSize()];
+ CodedOutputByteBufferNano output = CodedOutputByteBufferNano.newInstance(result);
+ writeTo(output);
+ return result;
+ }
+
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
new file mode 100644
index 00000000..4a08bb58
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
@@ -0,0 +1,555 @@
+// 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.nano;
+
+import com.google.protobuf.nano.MapFactories.MapFactory;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * The classes contained within are used internally by the Protocol Buffer
+ * library and generated message implementations. They are public only because
+ * those generated messages do not reside in the {@code protobuf} package.
+ * Others should not use this class directly.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public final class InternalNano {
+
+ public static final int TYPE_DOUBLE = 1;
+ public static final int TYPE_FLOAT = 2;
+ public static final int TYPE_INT64 = 3;
+ public static final int TYPE_UINT64 = 4;
+ public static final int TYPE_INT32 = 5;
+ public static final int TYPE_FIXED64 = 6;
+ public static final int TYPE_FIXED32 = 7;
+ public static final int TYPE_BOOL = 8;
+ public static final int TYPE_STRING = 9;
+ public static final int TYPE_GROUP = 10;
+ public static final int TYPE_MESSAGE = 11;
+ public static final int TYPE_BYTES = 12;
+ public static final int TYPE_UINT32 = 13;
+ public static final int TYPE_ENUM = 14;
+ public static final int TYPE_SFIXED32 = 15;
+ public static final int TYPE_SFIXED64 = 16;
+ public static final int TYPE_SINT32 = 17;
+ public static final int TYPE_SINT64 = 18;
+
+
+ private InternalNano() {}
+
+ /**
+ * An object to provide synchronization when lazily initializing static fields
+ * of {@link MessageNano} subclasses.
+ * <p>
+ * To enable earlier versions of ProGuard to inline short methods from a
+ * generated MessageNano subclass to the call sites, that class must not have
+ * a class initializer, which will be created if there is any static variable
+ * initializers. To lazily initialize the static variables in a thread-safe
+ * manner, the initialization code will synchronize on this object.
+ */
+ public static final Object LAZY_INIT_LOCK = new Object();
+
+ /**
+ * Helper called by generated code to construct default values for string
+ * fields.
+ * <p>
+ * The protocol compiler does not actually contain a UTF-8 decoder -- it
+ * just pushes UTF-8-encoded text around without touching it. The one place
+ * where this presents a problem is when generating Java string literals.
+ * Unicode characters in the string literal would normally need to be encoded
+ * using a Unicode escape sequence, which would require decoding them.
+ * To get around this, protoc instead embeds the UTF-8 bytes into the
+ * generated code and leaves it to the runtime library to decode them.
+ * <p>
+ * It gets worse, though. If protoc just generated a byte array, like:
+ * new byte[] {0x12, 0x34, 0x56, 0x78}
+ * Java actually generates *code* which allocates an array and then fills
+ * in each value. This is much less efficient than just embedding the bytes
+ * directly into the bytecode. To get around this, we need another
+ * work-around. String literals are embedded directly, so protoc actually
+ * generates a string literal corresponding to the bytes. The easiest way
+ * to do this is to use the ISO-8859-1 character set, which corresponds to
+ * the first 256 characters of the Unicode range. Protoc can then use
+ * good old CEscape to generate the string.
+ * <p>
+ * So we have a string literal which represents a set of bytes which
+ * represents another string. This function -- stringDefaultValue --
+ * converts from the generated string to the string we actually want. The
+ * generated code calls this automatically.
+ */
+ public static String stringDefaultValue(String bytes) {
+ try {
+ return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // This should never happen since all JVMs are required to implement
+ // both of the above character sets.
+ throw new IllegalStateException(
+ "Java VM does not support a standard character set.", e);
+ }
+ }
+
+ /**
+ * Helper called by generated code to construct default values for bytes
+ * fields.
+ * <p>
+ * This is a lot like {@link #stringDefaultValue}, but for bytes fields.
+ * In this case we only need the second of the two hacks -- allowing us to
+ * embed raw bytes as a string literal with ISO-8859-1 encoding.
+ */
+ public static byte[] bytesDefaultValue(String bytes) {
+ try {
+ return bytes.getBytes("ISO-8859-1");
+ } catch (UnsupportedEncodingException e) {
+ // This should never happen since all JVMs are required to implement
+ // ISO-8859-1.
+ throw new IllegalStateException(
+ "Java VM does not support a standard character set.", e);
+ }
+ }
+
+ /**
+ * Helper function to convert a string into UTF-8 while turning the
+ * UnsupportedEncodingException to a RuntimeException.
+ */
+ public static byte[] copyFromUtf8(final String text) {
+ try {
+ return text.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported?");
+ }
+ }
+
+ /**
+ * Checks repeated int field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(int[] field1, int[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated long field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(long[] field1, long[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated float field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(float[] field1, float[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated double field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(double[] field1, double[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated boolean field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(boolean[] field1, boolean[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated bytes field equality. Only non-null elements are tested.
+ * Returns true if the two fields have the same sequence of non-null
+ * elements. Null-value fields and fields of any length with only null
+ * elements are considered equal.
+ */
+ public static boolean equals(byte[][] field1, byte[][] field2) {
+ int index1 = 0;
+ int length1 = field1 == null ? 0 : field1.length;
+ int index2 = 0;
+ int length2 = field2 == null ? 0 : field2.length;
+ while (true) {
+ while (index1 < length1 && field1[index1] == null) {
+ index1++;
+ }
+ while (index2 < length2 && field2[index2] == null) {
+ index2++;
+ }
+ boolean atEndOf1 = index1 >= length1;
+ boolean atEndOf2 = index2 >= length2;
+ if (atEndOf1 && atEndOf2) {
+ // no more non-null elements to test in both arrays
+ return true;
+ } else if (atEndOf1 != atEndOf2) {
+ // one of the arrays have extra non-null elements
+ return false;
+ } else if (!Arrays.equals(field1[index1], field2[index2])) {
+ // element mismatch
+ return false;
+ }
+ index1++;
+ index2++;
+ }
+ }
+
+ /**
+ * Checks repeated string/message field equality. Only non-null elements are
+ * tested. Returns true if the two fields have the same sequence of non-null
+ * elements. Null-value fields and fields of any length with only null
+ * elements are considered equal.
+ */
+ public static boolean equals(Object[] field1, Object[] field2) {
+ int index1 = 0;
+ int length1 = field1 == null ? 0 : field1.length;
+ int index2 = 0;
+ int length2 = field2 == null ? 0 : field2.length;
+ while (true) {
+ while (index1 < length1 && field1[index1] == null) {
+ index1++;
+ }
+ while (index2 < length2 && field2[index2] == null) {
+ index2++;
+ }
+ boolean atEndOf1 = index1 >= length1;
+ boolean atEndOf2 = index2 >= length2;
+ if (atEndOf1 && atEndOf2) {
+ // no more non-null elements to test in both arrays
+ return true;
+ } else if (atEndOf1 != atEndOf2) {
+ // one of the arrays have extra non-null elements
+ return false;
+ } else if (!field1[index1].equals(field2[index2])) {
+ // element mismatch
+ return false;
+ }
+ index1++;
+ index2++;
+ }
+ }
+
+ /**
+ * Computes the hash code of a repeated int field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(int[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated long field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(long[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated float field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(float[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated double field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(double[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated boolean field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(boolean[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated bytes field. Only the sequence of all
+ * non-null elements are used in the computation. Null-value fields and fields
+ * of any length with only null elements have the same hash code.
+ */
+ public static int hashCode(byte[][] field) {
+ int result = 0;
+ for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
+ byte[] element = field[i];
+ if (element != null) {
+ result = 31 * result + Arrays.hashCode(element);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Computes the hash code of a repeated string/message field. Only the
+ * sequence of all non-null elements are used in the computation. Null-value
+ * fields and fields of any length with only null elements have the same hash
+ * code.
+ */
+ public static int hashCode(Object[] field) {
+ int result = 0;
+ for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
+ Object element = field[i];
+ if (element != null) {
+ result = 31 * result + element.hashCode();
+ }
+ }
+ return result;
+ }
+ private static Object primitiveDefaultValue(int type) {
+ switch (type) {
+ case TYPE_BOOL:
+ return Boolean.FALSE;
+ case TYPE_BYTES:
+ return WireFormatNano.EMPTY_BYTES;
+ case TYPE_STRING:
+ return "";
+ case TYPE_FLOAT:
+ return Float.valueOf(0);
+ case TYPE_DOUBLE:
+ return Double.valueOf(0);
+ case TYPE_ENUM:
+ case TYPE_FIXED32:
+ case TYPE_INT32:
+ case TYPE_UINT32:
+ case TYPE_SINT32:
+ case TYPE_SFIXED32:
+ return Integer.valueOf(0);
+ case TYPE_INT64:
+ case TYPE_UINT64:
+ case TYPE_SINT64:
+ case TYPE_FIXED64:
+ case TYPE_SFIXED64:
+ return Long.valueOf(0L);
+ case TYPE_MESSAGE:
+ case TYPE_GROUP:
+ default:
+ throw new IllegalArgumentException(
+ "Type: " + type + " is not a primitive type.");
+ }
+ }
+
+ /**
+ * Merges the map entry into the map field. Note this is only supposed to
+ * be called by generated messages.
+ *
+ * @param map the map field; may be null, in which case a map will be
+ * instantiated using the {@link MapFactories.MapFactory}
+ * @param input the input byte buffer
+ * @param keyType key type, as defined in InternalNano.TYPE_*
+ * @param valueType value type, as defined in InternalNano.TYPE_*
+ * @param value an new instance of the value, if the value is a TYPE_MESSAGE;
+ * otherwise this parameter can be null and will be ignored.
+ * @param keyTag wire tag for the key
+ * @param valueTag wire tag for the value
+ * @return the map field
+ * @throws IOException
+ */
+ @SuppressWarnings("unchecked")
+ public static final <K, V> Map<K, V> mergeMapEntry(
+ CodedInputByteBufferNano input,
+ Map<K, V> map,
+ MapFactory mapFactory,
+ int keyType,
+ int valueType,
+ V value,
+ int keyTag,
+ int valueTag) throws IOException {
+ map = mapFactory.forMap(map);
+ final int length = input.readRawVarint32();
+ final int oldLimit = input.pushLimit(length);
+ K key = null;
+ while (true) {
+ int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+ if (tag == keyTag) {
+ key = (K) input.readPrimitiveField(keyType);
+ } else if (tag == valueTag) {
+ if (valueType == TYPE_MESSAGE) {
+ input.readMessage((MessageNano) value);
+ } else {
+ value = (V) input.readPrimitiveField(valueType);
+ }
+ } else {
+ if (!input.skipField(tag)) {
+ break;
+ }
+ }
+ }
+ input.checkLastTagWas(0);
+ input.popLimit(oldLimit);
+
+ if (key == null) {
+ // key can only be primitive types.
+ key = (K) primitiveDefaultValue(keyType);
+ }
+
+ if (value == null) {
+ // message type value will be initialized by code-gen.
+ value = (V) primitiveDefaultValue(valueType);
+ }
+
+ map.put(key, value);
+ return map;
+ }
+
+ public static <K, V> void serializeMapField(
+ CodedOutputByteBufferNano output,
+ Map<K, V> map, int number, int keyType, int valueType)
+ throws IOException {
+ for (Entry<K, V> entry: map.entrySet()) {
+ K key = entry.getKey();
+ V value = entry.getValue();
+ if (key == null || value == null) {
+ throw new IllegalStateException(
+ "keys and values in maps cannot be null");
+ }
+ int entrySize =
+ CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) +
+ CodedOutputByteBufferNano.computeFieldSize(2, valueType, value);
+ output.writeTag(number, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(entrySize);
+ output.writeField(1, keyType, key);
+ output.writeField(2, valueType, value);
+ }
+ }
+
+ public static <K, V> int computeMapFieldSize(
+ Map<K, V> map, int number, int keyType, int valueType) {
+ int size = 0;
+ int tagSize = CodedOutputByteBufferNano.computeTagSize(number);
+ for (Entry<K, V> entry: map.entrySet()) {
+ K key = entry.getKey();
+ V value = entry.getValue();
+ if (key == null || value == null) {
+ throw new IllegalStateException(
+ "keys and values in maps cannot be null");
+ }
+ int entrySize =
+ CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) +
+ CodedOutputByteBufferNano.computeFieldSize(2, valueType, value);
+ size += tagSize + entrySize
+ + CodedOutputByteBufferNano.computeRawVarint32Size(entrySize);
+ }
+ return size;
+ }
+
+ /**
+ * Checks whether two {@link Map} are equal. We don't use the default equals
+ * method of {@link Map} because it compares by identity not by content for
+ * byte arrays.
+ */
+ public static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null) {
+ return b.size() == 0;
+ }
+ if (b == null) {
+ return a.size() == 0;
+ }
+ if (a.size() != b.size()) {
+ return false;
+ }
+ for (Entry<K, V> entry : a.entrySet()) {
+ if (!b.containsKey(entry.getKey())) {
+ return false;
+ }
+ if (!equalsMapValue(entry.getValue(), b.get(entry.getKey()))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean equalsMapValue(Object a, Object b) {
+ if (a == null || b == null) {
+ throw new IllegalStateException(
+ "keys and values in maps cannot be null");
+ }
+ if (a instanceof byte[] && b instanceof byte[]) {
+ return Arrays.equals((byte[]) a, (byte[]) b);
+ }
+ return a.equals(b);
+ }
+
+ public static <K, V> int hashCode(Map<K, V> map) {
+ if (map == null) {
+ return 0;
+ }
+ int result = 0;
+ for (Entry<K, V> entry : map.entrySet()) {
+ result += hashCodeForMap(entry.getKey())
+ ^ hashCodeForMap(entry.getValue());
+ }
+ return result;
+ }
+
+ private static int hashCodeForMap(Object o) {
+ if (o instanceof byte[]) {
+ return Arrays.hashCode((byte[]) o);
+ }
+ return o.hashCode();
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java b/javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java
new file mode 100644
index 00000000..3864d38a
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java
@@ -0,0 +1,93 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a protocol message being parsed is invalid in some way,
+ * e.g. it contains a malformed varint or a negative byte length.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class InvalidProtocolBufferNanoException extends IOException {
+ private static final long serialVersionUID = -1616151763072450476L;
+
+ public InvalidProtocolBufferNanoException(final String description) {
+ super(description);
+ }
+
+ static InvalidProtocolBufferNanoException truncatedMessage() {
+ return new InvalidProtocolBufferNanoException(
+ "While parsing a protocol message, the input ended unexpectedly " +
+ "in the middle of a field. This could mean either than the " +
+ "input has been truncated or that an embedded message " +
+ "misreported its own length.");
+ }
+
+ static InvalidProtocolBufferNanoException negativeSize() {
+ return new InvalidProtocolBufferNanoException(
+ "CodedInputStream encountered an embedded string or message " +
+ "which claimed to have negative size.");
+ }
+
+ static InvalidProtocolBufferNanoException malformedVarint() {
+ return new InvalidProtocolBufferNanoException(
+ "CodedInputStream encountered a malformed varint.");
+ }
+
+ static InvalidProtocolBufferNanoException invalidTag() {
+ return new InvalidProtocolBufferNanoException(
+ "Protocol message contained an invalid tag (zero).");
+ }
+
+ static InvalidProtocolBufferNanoException invalidEndTag() {
+ return new InvalidProtocolBufferNanoException(
+ "Protocol message end-group tag did not match expected tag.");
+ }
+
+ static InvalidProtocolBufferNanoException invalidWireType() {
+ return new InvalidProtocolBufferNanoException(
+ "Protocol message tag had invalid wire type.");
+ }
+
+ static InvalidProtocolBufferNanoException recursionLimitExceeded() {
+ return new InvalidProtocolBufferNanoException(
+ "Protocol message had too many levels of nesting. May be malicious. " +
+ "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
+ }
+
+ static InvalidProtocolBufferNanoException sizeLimitExceeded() {
+ return new InvalidProtocolBufferNanoException(
+ "Protocol message was too large. May be malicious. " +
+ "Use CodedInputStream.setSizeLimit() to increase the size limit.");
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MapFactories.java b/javanano/src/main/java/com/google/protobuf/nano/MapFactories.java
new file mode 100644
index 00000000..98fa4877
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/MapFactories.java
@@ -0,0 +1,67 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility class for maps support.
+ */
+public final class MapFactories {
+ public static interface MapFactory {
+ <K, V> Map<K, V> forMap(Map<K, V> oldMap);
+ }
+
+ // NOTE(liujisi): The factory setter is temporarily marked as package private.
+ // The way to provide customized implementations of maps for different
+ // platforms are still under discussion. Mark it as private to avoid exposing
+ // the API in proto3 alpha release.
+ /* public */ static void setMapFactory(MapFactory newMapFactory) {
+ mapFactory = newMapFactory;
+ }
+
+ public static MapFactory getMapFactory() {
+ return mapFactory;
+ }
+
+ private static class DefaultMapFactory implements MapFactory {
+ public <K, V> Map<K, V> forMap(Map<K, V> oldMap) {
+ if (oldMap == null) {
+ return new HashMap<K, V>();
+ }
+ return oldMap;
+ }
+ }
+ private static volatile MapFactory mapFactory = new DefaultMapFactory();
+
+ private MapFactories() {}
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
new file mode 100644
index 00000000..81e58571
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
@@ -0,0 +1,190 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ *
+ * @author wink@google.com Wink Saville
+ */
+public abstract class MessageNano {
+ protected volatile int cachedSize = -1;
+
+ /**
+ * Get the number of bytes required to encode this message.
+ * Returns the cached size or calls getSerializedSize which
+ * sets the cached size. This is used internally when serializing
+ * so the size is only computed once. If a member is modified
+ * then this could be stale call getSerializedSize if in doubt.
+ */
+ public int getCachedSize() {
+ if (cachedSize < 0) {
+ // getSerializedSize sets cachedSize
+ getSerializedSize();
+ }
+ return cachedSize;
+ }
+
+ /**
+ * Computes the number of bytes required to encode this message.
+ * The size is cached and the cached result can be retrieved
+ * using getCachedSize().
+ */
+ public int getSerializedSize() {
+ int size = computeSerializedSize();
+ cachedSize = size;
+ return size;
+ }
+
+ /**
+ * Computes the number of bytes required to encode this message. This does not update the
+ * cached size.
+ */
+ protected int computeSerializedSize() {
+ // This is overridden if the generated message has serialized fields.
+ return 0;
+ }
+
+ /**
+ * Serializes the message and writes it to {@code output}.
+ *
+ * @param output the output to receive the serialized form.
+ * @throws IOException if an error occurred writing to {@code output}.
+ */
+ public void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ // Does nothing by default. Overridden by subclasses which have data to write.
+ }
+
+ /**
+ * Parse {@code input} as a message of this type and merge it with the
+ * message being built.
+ */
+ public abstract MessageNano mergeFrom(CodedInputByteBufferNano input) throws IOException;
+
+ /**
+ * Serialize to a byte array.
+ * @return byte array with the serialized data.
+ */
+ public static final byte[] toByteArray(MessageNano msg) {
+ final byte[] result = new byte[msg.getSerializedSize()];
+ toByteArray(msg, result, 0, result.length);
+ return result;
+ }
+
+ /**
+ * Serialize to a byte array starting at offset through length. The
+ * method getSerializedSize must have been called prior to calling
+ * this method so the proper length is know. If an attempt to
+ * write more than length bytes OutOfSpaceException will be thrown
+ * and if length bytes are not written then IllegalStateException
+ * is thrown.
+ */
+ public static final void toByteArray(MessageNano msg, byte[] data, int offset, int length) {
+ try {
+ final CodedOutputByteBufferNano output =
+ CodedOutputByteBufferNano.newInstance(data, offset, length);
+ msg.writeTo(output);
+ output.checkNoSpaceLeft();
+ } catch (IOException e) {
+ throw new RuntimeException("Serializing to a byte array threw an IOException "
+ + "(should never happen).", e);
+ }
+ }
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built.
+ */
+ public static final <T extends MessageNano> T mergeFrom(T msg, final byte[] data)
+ throws InvalidProtocolBufferNanoException {
+ return mergeFrom(msg, data, 0, data.length);
+ }
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built.
+ */
+ public static final <T extends MessageNano> T mergeFrom(T msg, final byte[] data,
+ final int off, final int len) throws InvalidProtocolBufferNanoException {
+ try {
+ final CodedInputByteBufferNano input =
+ CodedInputByteBufferNano.newInstance(data, off, len);
+ msg.mergeFrom(input);
+ input.checkLastTagWas(0);
+ return msg;
+ } catch (InvalidProtocolBufferNanoException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException("Reading from a byte array threw an IOException (should "
+ + "never happen).");
+ }
+ }
+
+ /**
+ * Compares two {@code MessageNano}s and returns true if the message's are the same class and
+ * have serialized form equality (i.e. all of the field values are the same).
+ */
+ public static final boolean messageNanoEquals(MessageNano a, MessageNano b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ if (a.getClass() != b.getClass()) {
+ return false;
+ }
+ final int serializedSize = a.getSerializedSize();
+ if (b.getSerializedSize() != serializedSize) {
+ return false;
+ }
+ final byte[] aByteArray = new byte[serializedSize];
+ final byte[] bByteArray = new byte[serializedSize];
+ toByteArray(a, aByteArray, 0, serializedSize);
+ toByteArray(b, bByteArray, 0, serializedSize);
+ return Arrays.equals(aByteArray, bByteArray);
+ }
+
+ /**
+ * Returns a string that is (mostly) compatible with ProtoBuffer's TextFormat. Note that groups
+ * (which are deprecated) are not serialized with the correct field name.
+ *
+ * <p>This is implemented using reflection, so it is not especially fast nor is it guaranteed
+ * to find all fields if you have method removal turned on for proguard.
+ */
+ @Override
+ public String toString() {
+ return MessageNanoPrinter.print(this);
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
new file mode 100644
index 00000000..c4b2ad3d
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
@@ -0,0 +1,271 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+
+/**
+ * Static helper methods for printing nano protos.
+ *
+ * @author flynn@google.com Andrew Flynn
+ */
+public final class MessageNanoPrinter {
+ // Do not allow instantiation
+ private MessageNanoPrinter() {}
+
+ private static final String INDENT = " ";
+ private static final int MAX_STRING_LEN = 200;
+
+ /**
+ * Returns an text representation of a MessageNano suitable for debugging. The returned string
+ * is mostly compatible with Protocol Buffer's TextFormat (as provided by non-nano protocol
+ * buffers) -- groups (which are deprecated) are output with an underscore name (e.g. foo_bar
+ * instead of FooBar) and will thus not parse.
+ *
+ * <p>Employs Java reflection on the given object and recursively prints primitive fields,
+ * groups, and messages.</p>
+ */
+ public static <T extends MessageNano> String print(T message) {
+ if (message == null) {
+ return "";
+ }
+
+ StringBuffer buf = new StringBuffer();
+ try {
+ print(null, message, new StringBuffer(), buf);
+ } catch (IllegalAccessException e) {
+ return "Error printing proto: " + e.getMessage();
+ } catch (InvocationTargetException e) {
+ return "Error printing proto: " + e.getMessage();
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Function that will print the given message/field into the StringBuffer.
+ * Meant to be called recursively.
+ *
+ * @param identifier the identifier to use, or {@code null} if this is the root message to
+ * print.
+ * @param object the value to print. May in fact be a primitive value or byte array and not a
+ * message.
+ * @param indentBuf the indentation each line should begin with.
+ * @param buf the output buffer.
+ */
+ private static void print(String identifier, Object object,
+ StringBuffer indentBuf, StringBuffer buf) throws IllegalAccessException,
+ InvocationTargetException {
+ if (object == null) {
+ // This can happen if...
+ // - we're about to print a message, String, or byte[], but it not present;
+ // - we're about to print a primitive, but "reftype" optional style is enabled, and
+ // the field is unset.
+ // In both cases the appropriate behavior is to output nothing.
+ } else if (object instanceof MessageNano) { // Nano proto message
+ int origIndentBufLength = indentBuf.length();
+ if (identifier != null) {
+ buf.append(indentBuf).append(deCamelCaseify(identifier)).append(" <\n");
+ indentBuf.append(INDENT);
+ }
+ Class<?> clazz = object.getClass();
+
+ // Proto fields follow one of two formats:
+ //
+ // 1) Public, non-static variables that do not begin or end with '_'
+ // Find and print these using declared public fields
+ for (Field field : clazz.getFields()) {
+ int modifiers = field.getModifiers();
+ String fieldName = field.getName();
+
+ if ((modifiers & Modifier.PUBLIC) == Modifier.PUBLIC
+ && (modifiers & Modifier.STATIC) != Modifier.STATIC
+ && !fieldName.startsWith("_")
+ && !fieldName.endsWith("_")) {
+ Class<?> fieldType = field.getType();
+ Object value = field.get(object);
+
+ if (fieldType.isArray()) {
+ Class<?> arrayType = fieldType.getComponentType();
+
+ // bytes is special since it's not repeated, but is represented by an array
+ if (arrayType == byte.class) {
+ print(fieldName, value, indentBuf, buf);
+ } else {
+ int len = value == null ? 0 : Array.getLength(value);
+ for (int i = 0; i < len; i++) {
+ Object elem = Array.get(value, i);
+ print(fieldName, elem, indentBuf, buf);
+ }
+ }
+ } else {
+ print(fieldName, value, indentBuf, buf);
+ }
+ }
+ }
+
+ // 2) Fields that are accessed via getter methods (when accessors
+ // mode is turned on)
+ // Find and print these using getter methods.
+ for (Method method : clazz.getMethods()) {
+ String name = method.getName();
+ // Check for the setter accessor method since getters and hazzers both have
+ // non-proto-field name collisions (hashCode() and getSerializedSize())
+ if (name.startsWith("set")) {
+ String subfieldName = name.substring(3);
+
+ Method hazzer = null;
+ try {
+ hazzer = clazz.getMethod("has" + subfieldName);
+ } catch (NoSuchMethodException e) {
+ continue;
+ }
+ // If hazzer does't exist or returns false, no need to continue
+ if (!(Boolean) hazzer.invoke(object)) {
+ continue;
+ }
+
+ Method getter = null;
+ try {
+ getter = clazz.getMethod("get" + subfieldName);
+ } catch (NoSuchMethodException e) {
+ continue;
+ }
+
+ print(subfieldName, getter.invoke(object), indentBuf, buf);
+ }
+ }
+ if (identifier != null) {
+ indentBuf.setLength(origIndentBufLength);
+ buf.append(indentBuf).append(">\n");
+ }
+ } else if (object instanceof Map) {
+ Map<?,?> map = (Map<?,?>) object;
+ identifier = deCamelCaseify(identifier);
+
+ for (Map.Entry<?,?> entry : map.entrySet()) {
+ buf.append(indentBuf).append(identifier).append(" <\n");
+ int origIndentBufLength = indentBuf.length();
+ indentBuf.append(INDENT);
+ print("key", entry.getKey(), indentBuf, buf);
+ print("value", entry.getValue(), indentBuf, buf);
+ indentBuf.setLength(origIndentBufLength);
+ buf.append(indentBuf).append(">\n");
+ }
+ } else {
+ // Non-null primitive value
+ identifier = deCamelCaseify(identifier);
+ buf.append(indentBuf).append(identifier).append(": ");
+ if (object instanceof String) {
+ String stringMessage = sanitizeString((String) object);
+ buf.append("\"").append(stringMessage).append("\"");
+ } else if (object instanceof byte[]) {
+ appendQuotedBytes((byte[]) object, buf);
+ } else {
+ buf.append(object);
+ }
+ buf.append("\n");
+ }
+ }
+
+ /**
+ * Converts an identifier of the format "FieldName" into "field_name".
+ */
+ private static String deCamelCaseify(String identifier) {
+ StringBuffer out = new StringBuffer();
+ for (int i = 0; i < identifier.length(); i++) {
+ char currentChar = identifier.charAt(i);
+ if (i == 0) {
+ out.append(Character.toLowerCase(currentChar));
+ } else if (Character.isUpperCase(currentChar)) {
+ out.append('_').append(Character.toLowerCase(currentChar));
+ } else {
+ out.append(currentChar);
+ }
+ }
+ return out.toString();
+ }
+
+ /**
+ * Shortens and escapes the given string.
+ */
+ private static String sanitizeString(String str) {
+ if (!str.startsWith("http") && str.length() > MAX_STRING_LEN) {
+ // Trim non-URL strings.
+ str = str.substring(0, MAX_STRING_LEN) + "[...]";
+ }
+ return escapeString(str);
+ }
+
+ /**
+ * Escape everything except for low ASCII code points.
+ */
+ private static String escapeString(String str) {
+ int strLen = str.length();
+ StringBuilder b = new StringBuilder(strLen);
+ for (int i = 0; i < strLen; i++) {
+ char original = str.charAt(i);
+ if (original >= ' ' && original <= '~' && original != '"' && original != '\'') {
+ b.append(original);
+ } else {
+ b.append(String.format("\\u%04x", (int) original));
+ }
+ }
+ return b.toString();
+ }
+
+ /**
+ * Appends a quoted byte array to the provided {@code StringBuffer}.
+ */
+ private static void appendQuotedBytes(byte[] bytes, StringBuffer builder) {
+ if (bytes == null) {
+ builder.append("\"\"");
+ return;
+ }
+
+ builder.append('"');
+ for (int i = 0; i < bytes.length; ++i) {
+ int ch = bytes[i] & 0xff;
+ if (ch == '\\' || ch == '"') {
+ builder.append('\\').append((char) ch);
+ } else if (ch >= 32 && ch < 127) {
+ builder.append((char) ch);
+ } else {
+ builder.append(String.format("\\%03o", ch));
+ }
+ }
+ builder.append('"');
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
new file mode 100644
index 00000000..a17fccf3
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
@@ -0,0 +1,84 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Stores unknown fields. These might be extensions or fields that the generated
+ * API doesn't know about yet.
+ *
+ * @author bduff@google.com (Brian Duff)
+ */
+final class UnknownFieldData {
+
+ final int tag;
+ final byte[] bytes;
+
+ UnknownFieldData(int tag, byte[] bytes) {
+ this.tag = tag;
+ this.bytes = bytes;
+ }
+
+ int computeSerializedSize() {
+ int size = 0;
+ size += CodedOutputByteBufferNano.computeRawVarint32Size(tag);
+ size += bytes.length;
+ return size;
+ }
+
+ void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ output.writeRawVarint32(tag);
+ output.writeRawBytes(bytes);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof UnknownFieldData)) {
+ return false;
+ }
+
+ UnknownFieldData other = (UnknownFieldData) o;
+ return tag == other.tag && Arrays.equals(bytes, other.bytes);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + tag;
+ result = 31 * result + Arrays.hashCode(bytes);
+ return result;
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java b/javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java
new file mode 100644
index 00000000..bbb6370a
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java
@@ -0,0 +1,124 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.io.IOException;
+
+/**
+ * This class is used internally by the Protocol Buffer library and generated
+ * message implementations. It is public only because those generated messages
+ * do not reside in the {@code protobuf} package. Others should not use this
+ * class directly.
+ *
+ * This class contains constants and helper functions useful for dealing with
+ * the Protocol Buffer wire format.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class WireFormatNano {
+ // Do not allow instantiation.
+ private WireFormatNano() {}
+
+ static final int WIRETYPE_VARINT = 0;
+ static final int WIRETYPE_FIXED64 = 1;
+ static final int WIRETYPE_LENGTH_DELIMITED = 2;
+ static final int WIRETYPE_START_GROUP = 3;
+ static final int WIRETYPE_END_GROUP = 4;
+ static final int WIRETYPE_FIXED32 = 5;
+
+ static final int TAG_TYPE_BITS = 3;
+ static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
+
+ /** Given a tag value, determines the wire type (the lower 3 bits). */
+ static int getTagWireType(final int tag) {
+ return tag & TAG_TYPE_MASK;
+ }
+
+ /** Given a tag value, determines the field number (the upper 29 bits). */
+ public static int getTagFieldNumber(final int tag) {
+ return tag >>> TAG_TYPE_BITS;
+ }
+
+ /** Makes a tag value given a field number and wire type. */
+ static int makeTag(final int fieldNumber, final int wireType) {
+ return (fieldNumber << TAG_TYPE_BITS) | wireType;
+ }
+
+ public static final int EMPTY_INT_ARRAY[] = {};
+ public static final long EMPTY_LONG_ARRAY[] = {};
+ public static final float EMPTY_FLOAT_ARRAY[] = {};
+ public static final double EMPTY_DOUBLE_ARRAY[] = {};
+ public static final boolean EMPTY_BOOLEAN_ARRAY[] = {};
+ public static final String EMPTY_STRING_ARRAY[] = {};
+ public static final byte[] EMPTY_BYTES_ARRAY[] = {};
+ public static final byte[] EMPTY_BYTES = {};
+
+ /**
+ * Parses an unknown field. This implementation skips the field.
+ *
+ * <p>Generated messages will call this for unknown fields if the store_unknown_fields
+ * option is off.
+ *
+ * @return {@literal true} unless the tag is an end-group tag.
+ */
+ public static boolean parseUnknownField(
+ final CodedInputByteBufferNano input,
+ final int tag) throws IOException {
+ return input.skipField(tag);
+ }
+
+ /**
+ * Computes the array length of a repeated field. We assume that in the common case repeated
+ * fields are contiguously serialized but we still correctly handle interspersed values of a
+ * repeated field (but with extra allocations).
+ *
+ * Rewinds to current input position before returning.
+ *
+ * @param input stream input, pointing to the byte after the first tag
+ * @param tag repeated field tag just read
+ * @return length of array
+ * @throws IOException
+ */
+ public static final int getRepeatedFieldArrayLength(
+ final CodedInputByteBufferNano input,
+ final int tag) throws IOException {
+ int arrayLength = 1;
+ int startPos = input.getPosition();
+ input.skipField(tag);
+ while (input.readTag() == tag) {
+ input.skipField(tag);
+ arrayLength++;
+ }
+ input.rewindToPosition(startPos);
+ return arrayLength;
+ }
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
new file mode 100644
index 00000000..4cc77226
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
@@ -0,0 +1,4388 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import com.google.protobuf.nano.MapTestProto.TestMap;
+import com.google.protobuf.nano.MapTestProto.TestMap.MessageValue;
+import com.google.protobuf.nano.NanoAccessorsOuterClass.TestNanoAccessors;
+import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas;
+import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano;
+import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano;
+import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
+import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano;
+import com.google.protobuf.nano.testext.Extensions;
+import com.google.protobuf.nano.testext.Extensions.AnotherMessage;
+import com.google.protobuf.nano.testext.Extensions.MessageWithGroup;
+import com.google.protobuf.nano.testimport.UnittestImportNano;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Test nano runtime.
+ *
+ * @author ulas@google.com Ulas Kirazci
+ */
+public class NanoTest extends TestCase {
+ @Override
+ public void setUp() throws Exception {
+ }
+
+ public void testSimpleMessageNano() throws Exception {
+ SimpleMessageNano msg = new SimpleMessageNano();
+ assertEquals(123, msg.d);
+ assertEquals(null, msg.nestedMsg);
+ assertEquals(SimpleMessageNano.BAZ, msg.defaultNestedEnum);
+
+ msg.d = 456;
+ assertEquals(456, msg.d);
+
+ SimpleMessageNano.NestedMessage nestedMsg = new SimpleMessageNano.NestedMessage();
+ nestedMsg.bb = 2;
+ assertEquals(2, nestedMsg.bb);
+ msg.nestedMsg = nestedMsg;
+ assertEquals(2, msg.nestedMsg.bb);
+
+ msg.defaultNestedEnum = SimpleMessageNano.BAR;
+ assertEquals(SimpleMessageNano.BAR, msg.defaultNestedEnum);
+
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+
+ SimpleMessageNano newMsg = SimpleMessageNano.parseFrom(result);
+ assertEquals(456, newMsg.d);
+ assertEquals(2, msg.nestedMsg.bb);
+ assertEquals(SimpleMessageNano.BAR, msg.defaultNestedEnum);
+
+ msg.nestedMsg = null;
+ assertTrue(msgSerializedSize != msg.getSerializedSize());
+
+ msg.clear();
+ assertEquals(0, msg.getSerializedSize());
+ }
+
+ public void testRecursiveMessageNano() throws Exception {
+ RecursiveMessageNano msg = new RecursiveMessageNano();
+ assertTrue(msg.repeatedRecursiveMessageNano.length == 0);
+
+ RecursiveMessageNano msg1 = new RecursiveMessageNano();
+ msg1.id = 1;
+ assertEquals(1, msg1.id);
+ RecursiveMessageNano msg2 = new RecursiveMessageNano();
+ msg2.id = 2;
+ RecursiveMessageNano msg3 = new RecursiveMessageNano();
+ msg3.id = 3;
+
+ RecursiveMessageNano.NestedMessage nestedMsg = new RecursiveMessageNano.NestedMessage();
+ nestedMsg.a = msg1;
+ assertEquals(1, nestedMsg.a.id);
+
+ msg.id = 0;
+ msg.nestedMessage = nestedMsg;
+ msg.optionalRecursiveMessageNano = msg2;
+ msg.repeatedRecursiveMessageNano = new RecursiveMessageNano[] { msg3 };
+
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 16);
+ assertEquals(result.length, msgSerializedSize);
+
+ RecursiveMessageNano newMsg = RecursiveMessageNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedRecursiveMessageNano.length);
+
+ assertEquals(0, newMsg.id);
+ assertEquals(1, newMsg.nestedMessage.a.id);
+ assertEquals(2, newMsg.optionalRecursiveMessageNano.id);
+ assertEquals(3, newMsg.repeatedRecursiveMessageNano[0].id);
+ }
+
+ public void testMessageNoFields() {
+ SingleMessageNano msg = new SingleMessageNano();
+ assertEquals(0, msg.getSerializedSize());
+ assertEquals(0, MessageNano.toByteArray(msg).length);
+ }
+
+ public void testNanoRequiredInt32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.id = 123;
+ assertEquals(123, msg.id);
+ msg.clear().id = 456;
+ assertEquals(456, msg.id);
+ msg.clear();
+
+ msg.id = 123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 3);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(123, newMsg.id);
+ }
+
+ public void testNanoOptionalInt32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalInt32 = 123;
+ assertEquals(123, msg.optionalInt32);
+ msg.clear()
+ .optionalInt32 = 456;
+ assertEquals(456, msg.optionalInt32);
+ msg.clear();
+
+ msg.optionalInt32 = 123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 5);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(123, newMsg.optionalInt32);
+ }
+
+ public void testNanoOptionalInt64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalInt64 = 123;
+ assertEquals(123, msg.optionalInt64);
+ msg.clear()
+ .optionalInt64 = 456;
+ assertEquals(456, msg.optionalInt64);
+ msg.clear();
+ assertEquals(0, msg.optionalInt64);
+
+ msg.optionalInt64 = 123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 5);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(123, newMsg.optionalInt64);
+ }
+
+ public void testNanoOptionalUint32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalUint32 = 123;
+ assertEquals(123, msg.optionalUint32);
+ msg.clear()
+ .optionalUint32 = 456;
+ assertEquals(456, msg.optionalUint32);
+ msg.clear();
+ assertEquals(0, msg.optionalUint32);
+
+ msg.optionalUint32 = 123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 5);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(123, newMsg.optionalUint32);
+ }
+
+ public void testNanoOptionalUint64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalUint64 = 123;
+ assertEquals(123, msg.optionalUint64);
+ msg.clear()
+ .optionalUint64 = 456;
+ assertEquals(456, msg.optionalUint64);
+ msg.clear();
+ assertEquals(0, msg.optionalUint64);
+
+ msg.optionalUint64 = 123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 5);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(123, newMsg.optionalUint64);
+ }
+
+ public void testNanoOptionalSint32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalSint32 = 123;
+ assertEquals(123, msg.optionalSint32);
+ msg.clear()
+ .optionalSint32 = 456;
+ assertEquals(456, msg.optionalSint32);
+ msg.clear();
+ assertEquals(0, msg.optionalSint32);
+
+ msg.optionalSint32 = -123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(-123, newMsg.optionalSint32);
+ }
+
+ public void testNanoOptionalSint64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalSint64 = 123;
+ assertEquals(123, msg.optionalSint64);
+ msg.clear()
+ .optionalSint64 = 456;
+ assertEquals(456, msg.optionalSint64);
+ msg.clear();
+ assertEquals(0, msg.optionalSint64);
+
+ msg.optionalSint64 = -123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(-123, newMsg.optionalSint64);
+ }
+
+ public void testNanoOptionalFixed32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalFixed32 = 123;
+ assertEquals(123, msg.optionalFixed32);
+ msg.clear()
+ .optionalFixed32 = 456;
+ assertEquals(456, msg.optionalFixed32);
+ msg.clear();
+ assertEquals(0, msg.optionalFixed32);
+
+ msg.optionalFixed32 = 123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 8);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(123, newMsg.optionalFixed32);
+ }
+
+ public void testNanoOptionalFixed64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalFixed64 = 123;
+ assertEquals(123, msg.optionalFixed64);
+ msg.clear()
+ .optionalFixed64 = 456;
+ assertEquals(456, msg.optionalFixed64);
+ msg.clear();
+ assertEquals(0, msg.optionalFixed64);
+
+ msg.optionalFixed64 = 123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 12);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(123, newMsg.optionalFixed64);
+ }
+
+ public void testNanoOptionalSfixed32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalSfixed32 = 123;
+ assertEquals(123, msg.optionalSfixed32);
+ msg.clear()
+ .optionalSfixed32 = 456;
+ assertEquals(456, msg.optionalSfixed32);
+ msg.clear();
+ assertEquals(0, msg.optionalSfixed32);
+
+ msg.optionalSfixed32 = 123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 8);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(123, newMsg.optionalSfixed32);
+ }
+
+ public void testNanoOptionalSfixed64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalSfixed64 = 123;
+ assertEquals(123, msg.optionalSfixed64);
+ msg.clear()
+ .optionalSfixed64 = 456;
+ assertEquals(456, msg.optionalSfixed64);
+ msg.clear();
+ assertEquals(0, msg.optionalSfixed64);
+
+ msg.optionalSfixed64 = -123;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 12);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(-123, newMsg.optionalSfixed64);
+ }
+
+ public void testNanoOptionalFloat() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalFloat = 123f;
+ assertTrue(123.0f == msg.optionalFloat);
+ msg.clear()
+ .optionalFloat = 456.0f;
+ assertTrue(456.0f == msg.optionalFloat);
+ msg.clear();
+ assertTrue(0.0f == msg.optionalFloat);
+
+ msg.optionalFloat = -123.456f;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 8);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(-123.456f == newMsg.optionalFloat);
+ }
+
+ public void testNanoOptionalDouble() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalDouble = 123;
+ assertTrue(123.0 == msg.optionalDouble);
+ msg.clear()
+ .optionalDouble = 456.0;
+ assertTrue(456.0 == msg.optionalDouble);
+ msg.clear();
+ assertTrue(0.0 == msg.optionalDouble);
+
+ msg.optionalDouble = -123.456;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 12);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(-123.456 == newMsg.optionalDouble);
+ }
+
+ public void testNanoOptionalBool() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalBool = true;
+ assertTrue(msg.optionalBool);
+ msg.clear()
+ .optionalBool = true;
+ assertTrue(msg.optionalBool);
+ msg.clear();
+ assertFalse(msg.optionalBool);
+
+ msg.optionalBool = true;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 5);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(newMsg.optionalBool);
+ }
+
+ public void testNanoOptionalString() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalString = "hello";
+ assertEquals("hello", msg.optionalString);
+ msg.clear();
+ assertTrue(msg.optionalString.isEmpty());
+ msg.clear()
+ .optionalString = "hello2";
+ assertEquals("hello2", msg.optionalString);
+ msg.clear();
+ assertTrue(msg.optionalString.isEmpty());
+
+ msg.optionalString = "bye";
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 8);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(newMsg.optionalString != null);
+ assertEquals("bye", newMsg.optionalString);
+ }
+
+ public void testNanoOptionalBytes() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertFalse(msg.optionalBytes.length > 0);
+ msg.optionalBytes = InternalNano.copyFromUtf8("hello");
+ assertTrue(msg.optionalBytes.length > 0);
+ assertEquals("hello", new String(msg.optionalBytes, "UTF-8"));
+ msg.clear();
+ assertFalse(msg.optionalBytes.length > 0);
+ msg.clear()
+ .optionalBytes = InternalNano.copyFromUtf8("hello");
+ assertTrue(msg.optionalBytes.length > 0);
+ msg.clear();
+ assertFalse(msg.optionalBytes.length > 0);
+
+ msg.optionalBytes = InternalNano.copyFromUtf8("bye");
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 8);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(newMsg.optionalBytes.length > 0);
+ assertEquals("bye", new String(newMsg.optionalBytes, "UTF-8"));
+ }
+
+ public void testNanoOptionalGroup() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ TestAllTypesNano.OptionalGroup grp = new TestAllTypesNano.OptionalGroup();
+ grp.a = 1;
+ assertFalse(msg.optionalGroup != null);
+ msg.optionalGroup = grp;
+ assertTrue(msg.optionalGroup != null);
+ assertEquals(1, msg.optionalGroup.a);
+ msg.clear();
+ assertFalse(msg.optionalGroup != null);
+ msg.clear()
+ .optionalGroup = new TestAllTypesNano.OptionalGroup();
+ msg.optionalGroup.a = 2;
+ assertTrue(msg.optionalGroup != null);
+ msg.clear();
+ assertFalse(msg.optionalGroup != null);
+
+ msg.optionalGroup = grp;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 10);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(newMsg.optionalGroup != null);
+ assertEquals(1, newMsg.optionalGroup.a);
+ }
+
+ public void testNanoOptionalGroupWithUnknownFieldsEnabled() throws Exception {
+ MessageWithGroup msg = new MessageWithGroup();
+ MessageWithGroup.Group grp = new MessageWithGroup.Group();
+ grp.a = 1;
+ msg.group = grp;
+ byte [] serialized = MessageNano.toByteArray(msg);
+
+ MessageWithGroup parsed = MessageWithGroup.parseFrom(serialized);
+ assertEquals(1, parsed.group.a);
+
+ byte [] serialized2 = MessageNano.toByteArray(parsed);
+ assertEquals(serialized.length, serialized2.length);
+ MessageWithGroup parsed2 = MessageWithGroup.parseFrom(serialized2);
+ assertEquals(1, parsed2.group.a);
+ }
+
+ public void testNanoOptionalNestedMessage() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ TestAllTypesNano.NestedMessage nestedMsg = new TestAllTypesNano.NestedMessage();
+ nestedMsg.bb = 1;
+ assertFalse(msg.optionalNestedMessage != null);
+ msg.optionalNestedMessage = nestedMsg;
+ assertTrue(msg.optionalNestedMessage != null);
+ assertEquals(1, msg.optionalNestedMessage.bb);
+ msg.clear();
+ assertFalse(msg.optionalNestedMessage != null);
+ msg.clear()
+ .optionalNestedMessage = new TestAllTypesNano.NestedMessage();
+ msg.optionalNestedMessage.bb = 2;
+ assertTrue(msg.optionalNestedMessage != null);
+ msg.clear();
+ assertFalse(msg.optionalNestedMessage != null);
+
+ msg.optionalNestedMessage = nestedMsg;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 8);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(newMsg.optionalNestedMessage != null);
+ assertEquals(1, newMsg.optionalNestedMessage.bb);
+ }
+
+ public void testNanoOptionalForeignMessage() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ NanoOuterClass.ForeignMessageNano nestedMsg = new NanoOuterClass.ForeignMessageNano();
+ nestedMsg.c = 1;
+ assertFalse(msg.optionalForeignMessage != null);
+ msg.optionalForeignMessage = nestedMsg;
+ assertTrue(msg.optionalForeignMessage != null);
+ assertEquals(1, msg.optionalForeignMessage.c);
+ msg.clear();
+ assertFalse(msg.optionalForeignMessage != null);
+ msg.clear()
+ .optionalForeignMessage = new NanoOuterClass.ForeignMessageNano();
+ msg.optionalForeignMessage.c = 2;
+ assertTrue(msg.optionalForeignMessage != null);
+ msg.clear();
+ assertFalse(msg.optionalForeignMessage != null);
+
+ msg.optionalForeignMessage = nestedMsg;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 8);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(newMsg.optionalForeignMessage != null);
+ assertEquals(1, newMsg.optionalForeignMessage.c);
+ }
+
+ public void testNanoOptionalImportMessage() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ UnittestImportNano.ImportMessageNano nestedMsg = new UnittestImportNano.ImportMessageNano();
+ nestedMsg.d = 1;
+ assertFalse(msg.optionalImportMessage != null);
+ msg.optionalImportMessage = nestedMsg;
+ assertTrue(msg.optionalImportMessage != null);
+ assertEquals(1, msg.optionalImportMessage.d);
+ msg.clear();
+ assertFalse(msg.optionalImportMessage != null);
+ msg.clear()
+ .optionalImportMessage = new UnittestImportNano.ImportMessageNano();
+ msg.optionalImportMessage.d = 2;
+ assertTrue(msg.optionalImportMessage != null);
+ msg.clear();
+ assertFalse(msg.optionalImportMessage != null);
+
+ msg.optionalImportMessage = nestedMsg;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 8);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(newMsg.optionalImportMessage != null);
+ assertEquals(1, newMsg.optionalImportMessage.d);
+ }
+
+ public void testNanoOptionalNestedEnum() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalNestedEnum = TestAllTypesNano.BAR;
+ assertEquals(TestAllTypesNano.BAR, msg.optionalNestedEnum);
+ msg.clear()
+ .optionalNestedEnum = TestAllTypesNano.BAZ;
+ assertEquals(TestAllTypesNano.BAZ, msg.optionalNestedEnum);
+ msg.clear();
+ assertEquals(TestAllTypesNano.FOO, msg.optionalNestedEnum);
+
+ msg.optionalNestedEnum = TestAllTypesNano.BAR;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(TestAllTypesNano.BAR, newMsg.optionalNestedEnum);
+ }
+
+ public void testNanoOptionalForeignEnum() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAR;
+ assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.optionalForeignEnum);
+ msg.clear()
+ .optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAZ;
+ assertEquals(NanoOuterClass.FOREIGN_NANO_BAZ, msg.optionalForeignEnum);
+ msg.clear();
+ assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.optionalForeignEnum);
+
+ msg.optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAR;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, newMsg.optionalForeignEnum);
+ }
+
+ public void testNanoOptionalImportEnum() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAR;
+ assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.optionalImportEnum);
+ msg.clear()
+ .optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAZ;
+ assertEquals(UnittestImportNano.IMPORT_NANO_BAZ, msg.optionalImportEnum);
+ msg.clear();
+ assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.optionalImportEnum);
+
+ msg.optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAR;
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(UnittestImportNano.IMPORT_NANO_BAR, newMsg.optionalImportEnum);
+ }
+
+ public void testNanoOptionalStringPiece() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalStringPiece = "hello";
+ assertEquals("hello", msg.optionalStringPiece);
+ msg.clear();
+ assertTrue(msg.optionalStringPiece.isEmpty());
+ msg.clear()
+ .optionalStringPiece = "hello2";
+ assertEquals("hello2", msg.optionalStringPiece);
+ msg.clear();
+ assertTrue(msg.optionalStringPiece.isEmpty());
+
+ msg.optionalStringPiece = "bye";
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(newMsg.optionalStringPiece != null);
+ assertEquals("bye", newMsg.optionalStringPiece);
+ }
+
+ public void testNanoOptionalCord() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalCord = "hello";
+ assertEquals("hello", msg.optionalCord);
+ msg.clear();
+ assertTrue(msg.optionalCord.isEmpty());
+ msg.clear()
+ .optionalCord = "hello2";
+ assertEquals("hello2", msg.optionalCord);
+ msg.clear();
+ assertTrue(msg.optionalCord.isEmpty());
+
+ msg.optionalCord = "bye";
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertTrue(newMsg.optionalCord != null);
+ assertEquals("bye", newMsg.optionalCord);
+ }
+
+ public void testNanoRepeatedInt32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedInt32.length);
+ msg.repeatedInt32 = new int[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedInt32[1]);
+ assertEquals(456, msg.repeatedInt32[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedInt32.length);
+ msg.clear()
+ .repeatedInt32 = new int[] { 456 };
+ assertEquals(1, msg.repeatedInt32.length);
+ assertEquals(456, msg.repeatedInt32[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedInt32.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedInt32 = new int[] { 123 };
+ assertEquals(1, msg.repeatedInt32.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedInt32.length);
+ assertEquals(123, newMsg.repeatedInt32[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedInt32 = new int[] { 123, 456 };
+ assertEquals(2, msg.repeatedInt32.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 10);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedInt32.length);
+ assertEquals(123, newMsg.repeatedInt32[0]);
+ assertEquals(456, newMsg.repeatedInt32[1]);
+ }
+
+ public void testNanoRepeatedInt64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedInt64.length);
+ msg.repeatedInt64 = new long[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedInt64[1]);
+ assertEquals(456, msg.repeatedInt64[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedInt64.length);
+ msg.clear()
+ .repeatedInt64 = new long[] { 456 };
+ assertEquals(1, msg.repeatedInt64.length);
+ assertEquals(456, msg.repeatedInt64[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedInt64.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedInt64 = new long[] { 123 };
+ assertEquals(1, msg.repeatedInt64.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedInt64.length);
+ assertEquals(123, newMsg.repeatedInt64[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedInt64 = new long[] { 123, 456 };
+ assertEquals(2, msg.repeatedInt64.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 10);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedInt64.length);
+ assertEquals(123, newMsg.repeatedInt64[0]);
+ assertEquals(456, newMsg.repeatedInt64[1]);
+ }
+
+ public void testNanoRepeatedUint32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedUint32.length);
+ msg.repeatedUint32 = new int[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedUint32[1]);
+ assertEquals(456, msg.repeatedUint32[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedUint32.length);
+ msg.clear()
+ .repeatedUint32 = new int[] { 456 };
+ assertEquals(1, msg.repeatedUint32.length);
+ assertEquals(456, msg.repeatedUint32[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedUint32.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedUint32 = new int[] { 123 };
+ assertEquals(1, msg.repeatedUint32.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedUint32.length);
+ assertEquals(123, newMsg.repeatedUint32[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedUint32 = new int[] { 123, 456 };
+ assertEquals(2, msg.repeatedUint32.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 10);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedUint32.length);
+ assertEquals(123, newMsg.repeatedUint32[0]);
+ assertEquals(456, newMsg.repeatedUint32[1]);
+ }
+
+ public void testNanoRepeatedUint64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedUint64.length);
+ msg.repeatedUint64 = new long[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedUint64[1]);
+ assertEquals(456, msg.repeatedUint64[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedUint64.length);
+ msg.clear()
+ .repeatedUint64 = new long[] { 456 };
+ assertEquals(1, msg.repeatedUint64.length);
+ assertEquals(456, msg.repeatedUint64[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedUint64.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedUint64 = new long[] { 123 };
+ assertEquals(1, msg.repeatedUint64.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedUint64.length);
+ assertEquals(123, newMsg.repeatedUint64[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedUint64 = new long[] { 123, 456 };
+ assertEquals(2, msg.repeatedUint64.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 10);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedUint64.length);
+ assertEquals(123, newMsg.repeatedUint64[0]);
+ assertEquals(456, newMsg.repeatedUint64[1]);
+ }
+
+ public void testNanoRepeatedSint32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedSint32.length);
+ msg.repeatedSint32 = new int[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedSint32[1]);
+ assertEquals(456, msg.repeatedSint32[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedSint32.length);
+ msg.clear()
+ .repeatedSint32 = new int[] { 456 };
+ assertEquals(1, msg.repeatedSint32.length);
+ assertEquals(456, msg.repeatedSint32[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedSint32.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedSint32 = new int[] { 123 };
+ assertEquals(1, msg.repeatedSint32.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 7);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedSint32.length);
+ assertEquals(123, newMsg.repeatedSint32[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedSint32 = new int[] { 123, 456 };
+ assertEquals(2, msg.repeatedSint32.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 11);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedSint32.length);
+ assertEquals(123, newMsg.repeatedSint32[0]);
+ assertEquals(456, newMsg.repeatedSint32[1]);
+ }
+
+ public void testNanoRepeatedSint64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedSint64.length);
+ msg.repeatedSint64 = new long[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedSint64[1]);
+ assertEquals(456, msg.repeatedSint64[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedSint64.length);
+ msg.clear()
+ .repeatedSint64 = new long[] { 456 };
+ assertEquals(1, msg.repeatedSint64.length);
+ assertEquals(456, msg.repeatedSint64[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedSint64.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedSint64 = new long[] { 123 };
+ assertEquals(1, msg.repeatedSint64.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 7);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedSint64.length);
+ assertEquals(123, newMsg.repeatedSint64[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedSint64 = new long[] { 123, 456 };
+ assertEquals(2, msg.repeatedSint64.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 11);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedSint64.length);
+ assertEquals(123, newMsg.repeatedSint64[0]);
+ assertEquals(456, newMsg.repeatedSint64[1]);
+ }
+
+ public void testNanoRepeatedFixed32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedFixed32.length);
+ msg.repeatedFixed32 = new int[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedFixed32[1]);
+ assertEquals(456, msg.repeatedFixed32[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedFixed32.length);
+ msg.clear()
+ .repeatedFixed32 = new int[] { 456 };
+ assertEquals(1, msg.repeatedFixed32.length);
+ assertEquals(456, msg.repeatedFixed32[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedFixed32.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedFixed32 = new int[] { 123 };
+ assertEquals(1, msg.repeatedFixed32.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedFixed32.length);
+ assertEquals(123, newMsg.repeatedFixed32[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedFixed32 = new int[] { 123, 456 };
+ assertEquals(2, msg.repeatedFixed32.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 15);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedFixed32.length);
+ assertEquals(123, newMsg.repeatedFixed32[0]);
+ assertEquals(456, newMsg.repeatedFixed32[1]);
+ }
+
+ public void testNanoRepeatedFixed64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedFixed64.length);
+ msg.repeatedFixed64 = new long[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedFixed64[1]);
+ assertEquals(456, msg.repeatedFixed64[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedFixed64.length);
+ msg.clear()
+ .repeatedFixed64 = new long[] { 456 };
+ assertEquals(1, msg.repeatedFixed64.length);
+ assertEquals(456, msg.repeatedFixed64[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedFixed64.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedFixed64 = new long[] { 123 };
+ assertEquals(1, msg.repeatedFixed64.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 13);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedFixed64.length);
+ assertEquals(123, newMsg.repeatedFixed64[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedFixed64 = new long[] { 123, 456 };
+ assertEquals(2, msg.repeatedFixed64.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 23);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedFixed64.length);
+ assertEquals(123, newMsg.repeatedFixed64[0]);
+ assertEquals(456, newMsg.repeatedFixed64[1]);
+ }
+
+ public void testNanoRepeatedSfixed32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedSfixed32.length);
+ msg.repeatedSfixed32 = new int[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedSfixed32[1]);
+ assertEquals(456, msg.repeatedSfixed32[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedSfixed32.length);
+ msg.clear()
+ .repeatedSfixed32 = new int[] { 456 };
+ assertEquals(1, msg.repeatedSfixed32.length);
+ assertEquals(456, msg.repeatedSfixed32[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedSfixed32.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedSfixed32 = new int[] { 123 };
+ assertEquals(1, msg.repeatedSfixed32.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedSfixed32.length);
+ assertEquals(123, newMsg.repeatedSfixed32[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedSfixed32 = new int[] { 123, 456 };
+ assertEquals(2, msg.repeatedSfixed32.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 15);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedSfixed32.length);
+ assertEquals(123, newMsg.repeatedSfixed32[0]);
+ assertEquals(456, newMsg.repeatedSfixed32[1]);
+ }
+
+ public void testNanoRepeatedSfixed64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedSfixed64.length);
+ msg.repeatedSfixed64 = new long[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedSfixed64[1]);
+ assertEquals(456, msg.repeatedSfixed64[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedSfixed64.length);
+ msg.clear()
+ .repeatedSfixed64 = new long[] { 456 };
+ assertEquals(1, msg.repeatedSfixed64.length);
+ assertEquals(456, msg.repeatedSfixed64[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedSfixed64.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedSfixed64 = new long[] { 123 };
+ assertEquals(1, msg.repeatedSfixed64.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 13);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedSfixed64.length);
+ assertEquals(123, newMsg.repeatedSfixed64[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedSfixed64 = new long[] { 123, 456 };
+ assertEquals(2, msg.repeatedSfixed64.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 23);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedSfixed64.length);
+ assertEquals(123, newMsg.repeatedSfixed64[0]);
+ assertEquals(456, newMsg.repeatedSfixed64[1]);
+ }
+
+ public void testNanoRepeatedFloat() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedFloat.length);
+ msg.repeatedFloat = new float[] { 123f, 789f, 456f };
+ assertEquals(789f, msg.repeatedFloat[1]);
+ assertEquals(456f, msg.repeatedFloat[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedFloat.length);
+ msg.clear()
+ .repeatedFloat = new float[] { 456f };
+ assertEquals(1, msg.repeatedFloat.length);
+ assertEquals(456f, msg.repeatedFloat[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedFloat.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedFloat = new float[] { 123f };
+ assertEquals(1, msg.repeatedFloat.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedFloat.length);
+ assertEquals(123f, newMsg.repeatedFloat[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedFloat = new float[] { 123f, 456f };
+ assertEquals(2, msg.repeatedFloat.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 15);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedFloat.length);
+ assertEquals(123f, newMsg.repeatedFloat[0]);
+ assertEquals(456f, newMsg.repeatedFloat[1]);
+ }
+
+ public void testNanoRepeatedDouble() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedDouble.length);
+ msg.repeatedDouble = new double[] { 123.0, 789.0, 456.0 };
+ assertEquals(789.0, msg.repeatedDouble[1]);
+ assertEquals(456.0, msg.repeatedDouble[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedDouble.length);
+ msg.clear()
+ .repeatedDouble = new double[] { 456.0 };
+ assertEquals(1, msg.repeatedDouble.length);
+ assertEquals(456.0, msg.repeatedDouble[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedDouble.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedDouble = new double[] { 123.0 };
+ assertEquals(1, msg.repeatedDouble.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 13);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedDouble.length);
+ assertEquals(123.0, newMsg.repeatedDouble[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedDouble = new double[] { 123.0, 456.0 };
+ assertEquals(2, msg.repeatedDouble.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 23);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedDouble.length);
+ assertEquals(123.0, newMsg.repeatedDouble[0]);
+ assertEquals(456.0, newMsg.repeatedDouble[1]);
+ }
+
+ public void testNanoRepeatedBool() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedBool.length);
+ msg.repeatedBool = new boolean[] { false, true, false };
+ assertTrue(msg.repeatedBool[1]);
+ assertFalse(msg.repeatedBool[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedBool.length);
+ msg.clear()
+ .repeatedBool = new boolean[] { true };
+ assertEquals(1, msg.repeatedBool.length);
+ assertTrue(msg.repeatedBool[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedBool.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedBool = new boolean[] { false };
+ assertEquals(1, msg.repeatedBool.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedBool.length);
+ assertFalse(newMsg.repeatedBool[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedBool = new boolean[] { true, false };
+ assertEquals(2, msg.repeatedBool.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedBool.length);
+ assertTrue(newMsg.repeatedBool[0]);
+ assertFalse(newMsg.repeatedBool[1]);
+ }
+
+ public void testNanoRepeatedString() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedString.length);
+ msg.repeatedString = new String[] { "hello", "bye", "boo" };
+ assertEquals("bye", msg.repeatedString[1]);
+ assertEquals("boo", msg.repeatedString[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedString.length);
+ msg.clear()
+ .repeatedString = new String[] { "boo" };
+ assertEquals(1, msg.repeatedString.length);
+ assertEquals("boo", msg.repeatedString[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedString.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedString = new String[] { "" };
+ assertEquals(1, msg.repeatedString.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedString.length);
+ assertTrue(newMsg.repeatedString[0].isEmpty());
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedString = new String[] { "hello", "world" };
+ assertEquals(2, msg.repeatedString.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 19);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedString.length);
+ assertEquals("hello", newMsg.repeatedString[0]);
+ assertEquals("world", newMsg.repeatedString[1]);
+ }
+
+ public void testNanoRepeatedBytes() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedBytes.length);
+ msg.repeatedBytes = new byte[][] {
+ InternalNano.copyFromUtf8("hello"),
+ InternalNano.copyFromUtf8("bye"),
+ InternalNano.copyFromUtf8("boo")
+ };
+ assertEquals("bye", new String(msg.repeatedBytes[1], "UTF-8"));
+ assertEquals("boo", new String(msg.repeatedBytes[2], "UTF-8"));
+ msg.clear();
+ assertEquals(0, msg.repeatedBytes.length);
+ msg.clear()
+ .repeatedBytes = new byte[][] { InternalNano.copyFromUtf8("boo") };
+ assertEquals(1, msg.repeatedBytes.length);
+ assertEquals("boo", new String(msg.repeatedBytes[0], "UTF-8"));
+ msg.clear();
+ assertEquals(0, msg.repeatedBytes.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedBytes = new byte[][] { InternalNano.copyFromUtf8("") };
+ assertEquals(1, msg.repeatedBytes.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedBytes.length);
+ assertTrue(newMsg.repeatedBytes[0].length == 0);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedBytes = new byte[][] {
+ InternalNano.copyFromUtf8("hello"),
+ InternalNano.copyFromUtf8("world")
+ };
+ assertEquals(2, msg.repeatedBytes.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 19);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedBytes.length);
+ assertEquals("hello", new String(newMsg.repeatedBytes[0], "UTF-8"));
+ assertEquals("world", new String(newMsg.repeatedBytes[1], "UTF-8"));
+ }
+
+ public void testNanoRepeatedGroup() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ TestAllTypesNano.RepeatedGroup group0 =
+ new TestAllTypesNano.RepeatedGroup();
+ group0.a = 0;
+ TestAllTypesNano.RepeatedGroup group1 =
+ new TestAllTypesNano.RepeatedGroup();
+ group1.a = 1;
+ TestAllTypesNano.RepeatedGroup group2 =
+ new TestAllTypesNano.RepeatedGroup();
+ group2.a = 2;
+
+ msg.repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0, group1, group2 };
+ assertEquals(3, msg.repeatedGroup.length);
+ assertEquals(0, msg.repeatedGroup[0].a);
+ assertEquals(1, msg.repeatedGroup[1].a);
+ assertEquals(2, msg.repeatedGroup[2].a);
+ msg.clear();
+ assertEquals(0, msg.repeatedGroup.length);
+ msg.clear()
+ .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group1 };
+ assertEquals(1, msg.repeatedGroup.length);
+ assertEquals(1, msg.repeatedGroup[0].a);
+ msg.clear();
+ assertEquals(0, msg.repeatedGroup.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0 };
+ assertEquals(1, msg.repeatedGroup.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 7);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedGroup.length);
+ assertEquals(0, newMsg.repeatedGroup[0].a);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0, group1 };
+ assertEquals(2, msg.repeatedGroup.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 14);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedGroup.length);
+ assertEquals(0, newMsg.repeatedGroup[0].a);
+ assertEquals(1, newMsg.repeatedGroup[1].a);
+ }
+
+ public void testNanoRepeatedNestedMessage() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ TestAllTypesNano.NestedMessage nestedMsg0 =
+ new TestAllTypesNano.NestedMessage();
+ nestedMsg0.bb = 0;
+ TestAllTypesNano.NestedMessage nestedMsg1 =
+ new TestAllTypesNano.NestedMessage();
+ nestedMsg1.bb = 1;
+ TestAllTypesNano.NestedMessage nestedMsg2 =
+ new TestAllTypesNano.NestedMessage();
+ nestedMsg2.bb = 2;
+
+ msg.repeatedNestedMessage =
+ new TestAllTypesNano.NestedMessage[] { nestedMsg0, nestedMsg1, nestedMsg2 };
+ assertEquals(3, msg.repeatedNestedMessage.length);
+ assertEquals(0, msg.repeatedNestedMessage[0].bb);
+ assertEquals(1, msg.repeatedNestedMessage[1].bb);
+ assertEquals(2, msg.repeatedNestedMessage[2].bb);
+ msg.clear();
+ assertEquals(0, msg.repeatedNestedMessage.length);
+ msg.clear()
+ .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg1 };
+ assertEquals(1, msg.repeatedNestedMessage.length);
+ assertEquals(1, msg.repeatedNestedMessage[0].bb);
+ msg.clear();
+ assertEquals(0, msg.repeatedNestedMessage.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0 };
+ assertEquals(1, msg.repeatedNestedMessage.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedNestedMessage.length);
+ assertEquals(0, newMsg.repeatedNestedMessage[0].bb);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0, nestedMsg1 };
+ assertEquals(2, msg.repeatedNestedMessage.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 11);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedNestedMessage.length);
+ assertEquals(0, newMsg.repeatedNestedMessage[0].bb);
+ assertEquals(1, newMsg.repeatedNestedMessage[1].bb);
+ }
+
+ public void testNanoRepeatedForeignMessage() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ NanoOuterClass.ForeignMessageNano foreignMsg0 =
+ new NanoOuterClass.ForeignMessageNano();
+ foreignMsg0.c = 0;
+ NanoOuterClass.ForeignMessageNano foreignMsg1 =
+ new NanoOuterClass.ForeignMessageNano();
+ foreignMsg1.c = 1;
+ NanoOuterClass.ForeignMessageNano foreignMsg2 =
+ new NanoOuterClass.ForeignMessageNano();
+ foreignMsg2.c = 2;
+
+ msg.repeatedForeignMessage =
+ new NanoOuterClass.ForeignMessageNano[] { foreignMsg0, foreignMsg1, foreignMsg2 };
+ assertEquals(3, msg.repeatedForeignMessage.length);
+ assertEquals(0, msg.repeatedForeignMessage[0].c);
+ assertEquals(1, msg.repeatedForeignMessage[1].c);
+ assertEquals(2, msg.repeatedForeignMessage[2].c);
+ msg.clear();
+ assertEquals(0, msg.repeatedForeignMessage.length);
+ msg.clear()
+ .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg1 };
+ assertEquals(1, msg.repeatedForeignMessage.length);
+ assertEquals(1, msg.repeatedForeignMessage[0].c);
+ msg.clear();
+ assertEquals(0, msg.repeatedForeignMessage.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg0 };
+ assertEquals(1, msg.repeatedForeignMessage.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedForeignMessage.length);
+ assertEquals(0, newMsg.repeatedForeignMessage[0].c);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg0, foreignMsg1 };
+ assertEquals(2, msg.repeatedForeignMessage.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 11);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedForeignMessage.length);
+ assertEquals(0, newMsg.repeatedForeignMessage[0].c);
+ assertEquals(1, newMsg.repeatedForeignMessage[1].c);
+ }
+
+ public void testNanoRepeatedImportMessage() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ UnittestImportNano.ImportMessageNano foreignMsg0 =
+ new UnittestImportNano.ImportMessageNano();
+ foreignMsg0.d = 0;
+ UnittestImportNano.ImportMessageNano foreignMsg1 =
+ new UnittestImportNano.ImportMessageNano();
+ foreignMsg1.d = 1;
+ UnittestImportNano.ImportMessageNano foreignMsg2 =
+ new UnittestImportNano.ImportMessageNano();
+ foreignMsg2.d = 2;
+
+ msg.repeatedImportMessage =
+ new UnittestImportNano.ImportMessageNano[] { foreignMsg0, foreignMsg1, foreignMsg2 };
+ assertEquals(3, msg.repeatedImportMessage.length);
+ assertEquals(0, msg.repeatedImportMessage[0].d);
+ assertEquals(1, msg.repeatedImportMessage[1].d);
+ assertEquals(2, msg.repeatedImportMessage[2].d);
+ msg.clear();
+ assertEquals(0, msg.repeatedImportMessage.length);
+ msg.clear()
+ .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg1 };
+ assertEquals(1, msg.repeatedImportMessage.length);
+ assertEquals(1, msg.repeatedImportMessage[0].d);
+ msg.clear();
+ assertEquals(0, msg.repeatedImportMessage.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg0 };
+ assertEquals(1, msg.repeatedImportMessage.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedImportMessage.length);
+ assertEquals(0, newMsg.repeatedImportMessage[0].d);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg0, foreignMsg1 };
+ assertEquals(2, msg.repeatedImportMessage.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 11);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedImportMessage.length);
+ assertEquals(0, newMsg.repeatedImportMessage[0].d);
+ assertEquals(1, newMsg.repeatedImportMessage[1].d);
+ }
+
+ public void testNanoRepeatedNestedEnum() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.repeatedNestedEnum = new int[] {
+ TestAllTypesNano.FOO,
+ TestAllTypesNano.BAR,
+ TestAllTypesNano.BAZ
+ };
+ assertEquals(3, msg.repeatedNestedEnum.length);
+ assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]);
+ assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[1]);
+ assertEquals(TestAllTypesNano.BAZ, msg.repeatedNestedEnum[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedNestedEnum.length);
+ msg.clear()
+ .repeatedNestedEnum = new int[] { TestAllTypesNano.BAR };
+ assertEquals(1, msg.repeatedNestedEnum.length);
+ assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedNestedEnum.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedNestedEnum.length);
+ assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedNestedEnum = new int[] { TestAllTypesNano.FOO, TestAllTypesNano.BAR };
+ assertEquals(2, msg.repeatedNestedEnum.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedNestedEnum.length);
+ assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]);
+ assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[1]);
+ }
+
+ public void testNanoRepeatedForeignEnum() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.repeatedForeignEnum = new int[] {
+ NanoOuterClass.FOREIGN_NANO_FOO,
+ NanoOuterClass.FOREIGN_NANO_BAR,
+ NanoOuterClass.FOREIGN_NANO_BAZ
+ };
+ assertEquals(3, msg.repeatedForeignEnum.length);
+ assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]);
+ assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[1]);
+ assertEquals(NanoOuterClass.FOREIGN_NANO_BAZ, msg.repeatedForeignEnum[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedForeignEnum.length);
+ msg.clear()
+ .repeatedForeignEnum = new int[] { NanoOuterClass.FOREIGN_NANO_BAR };
+ assertEquals(1, msg.repeatedForeignEnum.length);
+ assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedForeignEnum.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedForeignEnum = new int[] { NanoOuterClass.FOREIGN_NANO_FOO };
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedForeignEnum.length);
+ assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedForeignEnum = new int[] {
+ NanoOuterClass.FOREIGN_NANO_FOO,
+ NanoOuterClass.FOREIGN_NANO_BAR
+ };
+ assertEquals(2, msg.repeatedForeignEnum.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedForeignEnum.length);
+ assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]);
+ assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[1]);
+ }
+
+ public void testNanoRepeatedImportEnum() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.repeatedImportEnum = new int[] {
+ UnittestImportNano.IMPORT_NANO_FOO,
+ UnittestImportNano.IMPORT_NANO_BAR,
+ UnittestImportNano.IMPORT_NANO_BAZ
+ };
+ assertEquals(3, msg.repeatedImportEnum.length);
+ assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]);
+ assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[1]);
+ assertEquals(UnittestImportNano.IMPORT_NANO_BAZ, msg.repeatedImportEnum[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedImportEnum.length);
+ msg.clear()
+ .repeatedImportEnum = new int[] { UnittestImportNano.IMPORT_NANO_BAR };
+ assertEquals(1, msg.repeatedImportEnum.length);
+ assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedImportEnum.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedImportEnum = new int[] { UnittestImportNano.IMPORT_NANO_FOO };
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedImportEnum.length);
+ assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedImportEnum = new int[] {
+ UnittestImportNano.IMPORT_NANO_FOO,
+ UnittestImportNano.IMPORT_NANO_BAR
+ };
+ assertEquals(2, msg.repeatedImportEnum.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedImportEnum.length);
+ assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]);
+ assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[1]);
+ }
+
+ public void testNanoRepeatedStringPiece() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedStringPiece.length);
+ msg.repeatedStringPiece = new String[] { "hello", "bye", "boo" };
+ assertEquals("bye", msg.repeatedStringPiece[1]);
+ assertEquals("boo", msg.repeatedStringPiece[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedStringPiece.length);
+ msg.clear()
+ .repeatedStringPiece = new String[] { "boo" };
+ assertEquals(1, msg.repeatedStringPiece.length);
+ assertEquals("boo", msg.repeatedStringPiece[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedStringPiece.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedStringPiece = new String[] { "" };
+ assertEquals(1, msg.repeatedStringPiece.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedStringPiece.length);
+ assertTrue(newMsg.repeatedStringPiece[0].isEmpty());
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedStringPiece = new String[] { "hello", "world" };
+ assertEquals(2, msg.repeatedStringPiece.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 19);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedStringPiece.length);
+ assertEquals("hello", newMsg.repeatedStringPiece[0]);
+ assertEquals("world", newMsg.repeatedStringPiece[1]);
+ }
+
+ public void testNanoRepeatedCord() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedCord.length);
+ msg.repeatedCord = new String[] { "hello", "bye", "boo" };
+ assertEquals("bye", msg.repeatedCord[1]);
+ assertEquals("boo", msg.repeatedCord[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedCord.length);
+ msg.clear()
+ .repeatedCord = new String[] { "boo" };
+ assertEquals(1, msg.repeatedCord.length);
+ assertEquals("boo", msg.repeatedCord[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedCord.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedCord = new String[] { "" };
+ assertEquals(1, msg.repeatedCord.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 6);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedCord.length);
+ assertTrue(newMsg.repeatedCord[0].isEmpty());
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedCord = new String[] { "hello", "world" };
+ assertEquals(2, msg.repeatedCord.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 19);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedCord.length);
+ assertEquals("hello", newMsg.repeatedCord[0]);
+ assertEquals("world", newMsg.repeatedCord[1]);
+ }
+
+ public void testNanoRepeatedPackedInt32() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedPackedInt32.length);
+ msg.repeatedPackedInt32 = new int[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedPackedInt32[1]);
+ assertEquals(456, msg.repeatedPackedInt32[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedPackedInt32.length);
+ msg.clear()
+ .repeatedPackedInt32 = new int[] { 456 };
+ assertEquals(1, msg.repeatedPackedInt32.length);
+ assertEquals(456, msg.repeatedPackedInt32[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedPackedInt32.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedPackedInt32 = new int[] { 123 };
+ assertEquals(1, msg.repeatedPackedInt32.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 7);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedPackedInt32.length);
+ assertEquals(123, newMsg.repeatedPackedInt32[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedPackedInt32 = new int[] { 123, 456 };
+ assertEquals(2, msg.repeatedPackedInt32.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 9);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedPackedInt32.length);
+ assertEquals(123, newMsg.repeatedPackedInt32[0]);
+ assertEquals(456, newMsg.repeatedPackedInt32[1]);
+ }
+
+ public void testNanoRepeatedPackedSfixed64() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ assertEquals(0, msg.repeatedPackedSfixed64.length);
+ msg.repeatedPackedSfixed64 = new long[] { 123, 789, 456 };
+ assertEquals(789, msg.repeatedPackedSfixed64[1]);
+ assertEquals(456, msg.repeatedPackedSfixed64[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedPackedSfixed64.length);
+ msg.clear()
+ .repeatedPackedSfixed64 = new long[] { 456 };
+ assertEquals(1, msg.repeatedPackedSfixed64.length);
+ assertEquals(456, msg.repeatedPackedSfixed64[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedPackedSfixed64.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedPackedSfixed64 = new long[] { 123 };
+ assertEquals(1, msg.repeatedPackedSfixed64.length);
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 14);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedPackedSfixed64.length);
+ assertEquals(123, newMsg.repeatedPackedSfixed64[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedPackedSfixed64 = new long[] { 123, 456 };
+ assertEquals(2, msg.repeatedPackedSfixed64.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 22);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedPackedSfixed64.length);
+ assertEquals(123, newMsg.repeatedPackedSfixed64[0]);
+ assertEquals(456, newMsg.repeatedPackedSfixed64[1]);
+ }
+
+ public void testNanoRepeatedPackedNestedEnum() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.repeatedPackedNestedEnum = new int[] {
+ TestAllTypesNano.FOO,
+ TestAllTypesNano.BAR,
+ TestAllTypesNano.BAZ
+ };
+ assertEquals(3, msg.repeatedPackedNestedEnum.length);
+ assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]);
+ assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[1]);
+ assertEquals(TestAllTypesNano.BAZ, msg.repeatedPackedNestedEnum[2]);
+ msg.clear();
+ assertEquals(0, msg.repeatedPackedNestedEnum.length);
+ msg.clear()
+ .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.BAR };
+ assertEquals(1, msg.repeatedPackedNestedEnum.length);
+ assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[0]);
+ msg.clear();
+ assertEquals(0, msg.repeatedPackedNestedEnum.length);
+
+ // Test 1 entry
+ msg.clear()
+ .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.FOO };
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 7);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(1, newMsg.repeatedPackedNestedEnum.length);
+ assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]);
+
+ // Test 2 entries
+ msg.clear()
+ .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.FOO, TestAllTypesNano.BAR };
+ assertEquals(2, msg.repeatedPackedNestedEnum.length);
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 8);
+ assertEquals(result.length, msgSerializedSize);
+
+ newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(2, newMsg.repeatedPackedNestedEnum.length);
+ assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]);
+ assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[1]);
+ }
+
+ public void testNanoRepeatedPackedSerializedSize() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.repeatedPackedInt32 = new int[] { 123, 789, 456 };
+ int msgSerializedSize = msg.getSerializedSize();
+ byte [] result = MessageNano.toByteArray(msg);
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 11);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano msg2 = new TestAllTypesNano();
+ msg2.repeatedPackedInt32 = new int[] { 123, 789, 456 };
+ byte [] result2 = new byte[msgSerializedSize];
+ MessageNano.toByteArray(msg2, result2, 0, msgSerializedSize);
+
+ // Check equal size and content.
+ assertEquals(msgSerializedSize, msg2.getSerializedSize());
+ assertTrue(Arrays.equals(result, result2));
+ }
+
+ public void testNanoRepeatedInt32ReMerge() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.repeatedInt32 = new int[] { 234 };
+ byte [] result1 = MessageNano.toByteArray(msg);
+
+ msg.clear().optionalInt32 = 789;
+ byte [] result2 = MessageNano.toByteArray(msg);
+
+ msg.clear().repeatedInt32 = new int[] { 123, 456 };
+ byte [] result3 = MessageNano.toByteArray(msg);
+
+ // Concatenate the three serializations and read as one message.
+ byte [] result = new byte[result1.length + result2.length + result3.length];
+ System.arraycopy(result1, 0, result, 0, result1.length);
+ System.arraycopy(result2, 0, result, result1.length, result2.length);
+ System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(789, newMsg.optionalInt32);
+ assertEquals(3, newMsg.repeatedInt32.length);
+ assertEquals(234, newMsg.repeatedInt32[0]);
+ assertEquals(123, newMsg.repeatedInt32[1]);
+ assertEquals(456, newMsg.repeatedInt32[2]);
+ }
+
+ public void testNanoRepeatedNestedEnumReMerge() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
+ byte [] result1 = MessageNano.toByteArray(msg);
+
+ msg.clear().optionalInt32 = 789;
+ byte [] result2 = MessageNano.toByteArray(msg);
+
+ msg.clear().repeatedNestedEnum = new int[] { TestAllTypesNano.BAR, TestAllTypesNano.FOO };
+ byte [] result3 = MessageNano.toByteArray(msg);
+
+ // Concatenate the three serializations and read as one message.
+ byte [] result = new byte[result1.length + result2.length + result3.length];
+ System.arraycopy(result1, 0, result, 0, result1.length);
+ System.arraycopy(result2, 0, result, result1.length, result2.length);
+ System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(789, newMsg.optionalInt32);
+ assertEquals(3, newMsg.repeatedNestedEnum.length);
+ assertEquals(TestAllTypesNano.FOO, newMsg.repeatedNestedEnum[0]);
+ assertEquals(TestAllTypesNano.BAR, newMsg.repeatedNestedEnum[1]);
+ assertEquals(TestAllTypesNano.FOO, newMsg.repeatedNestedEnum[2]);
+ }
+
+ public void testNanoRepeatedNestedMessageReMerge() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ TestAllTypesNano.NestedMessage nestedMsg0 =
+ new TestAllTypesNano.NestedMessage();
+ nestedMsg0.bb = 0;
+ TestAllTypesNano.NestedMessage nestedMsg1 =
+ new TestAllTypesNano.NestedMessage();
+ nestedMsg1.bb = 1;
+ TestAllTypesNano.NestedMessage nestedMsg2 =
+ new TestAllTypesNano.NestedMessage();
+ nestedMsg2.bb = 2;
+
+ msg.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0 };
+ byte [] result1 = MessageNano.toByteArray(msg);
+
+ msg.clear().optionalInt32 = 789;
+ byte [] result2 = MessageNano.toByteArray(msg);
+
+ msg.clear().repeatedNestedMessage =
+ new TestAllTypesNano.NestedMessage[] { nestedMsg1, nestedMsg2 };
+ byte [] result3 = MessageNano.toByteArray(msg);
+
+ // Concatenate the three serializations and read as one message.
+ byte [] result = new byte[result1.length + result2.length + result3.length];
+ System.arraycopy(result1, 0, result, 0, result1.length);
+ System.arraycopy(result2, 0, result, result1.length, result2.length);
+ System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length);
+
+ TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+ assertEquals(789, newMsg.optionalInt32);
+ assertEquals(3, newMsg.repeatedNestedMessage.length);
+ assertEquals(nestedMsg0.bb, newMsg.repeatedNestedMessage[0].bb);
+ assertEquals(nestedMsg1.bb, newMsg.repeatedNestedMessage[1].bb);
+ assertEquals(nestedMsg2.bb, newMsg.repeatedNestedMessage[2].bb);
+ }
+
+ /**
+ * Tests that invalid enum values from the wire are not accepted.
+ */
+ public void testNanoEnumValidity() throws Exception {
+ final int invalid = 120;
+ final int alsoInvalid = 121;
+
+ EnumValidity.M m = new EnumValidity.M();
+ // Sanity check & baseline of the assertions for the first case below.
+ assertEquals(EnumValidity.E.default_, m.optionalE);
+ assertEquals(EnumValidity.E.BAZ, m.defaultE);
+
+ m.optionalE = invalid;
+ m.defaultE = invalid;
+ // E contains all valid values
+ m.repeatedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR};
+ m.packedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ};
+ // E2 contains some invalid values
+ m.repeatedE2 = new int[] {invalid, EnumValidity.E.BAR, alsoInvalid};
+ m.packedE2 = new int[] {EnumValidity.E.FOO, invalid, alsoInvalid};
+ // E3 contains all invalid values
+ m.repeatedE3 = new int[] {invalid, invalid};
+ m.packedE3 = new int[] {alsoInvalid, alsoInvalid};
+ byte[] serialized = MessageNano.toByteArray(m);
+ // Sanity check that we do have all data in the byte array.
+ assertEquals(31, serialized.length);
+
+ // Test 1: tests that invalid values aren't included in the deserialized message.
+ EnumValidity.M deserialized = MessageNano.mergeFrom(new EnumValidity.M(), serialized);
+ assertEquals(EnumValidity.E.default_, deserialized.optionalE);
+ assertEquals(EnumValidity.E.BAZ, deserialized.defaultE);
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR}, deserialized.repeatedE));
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ}, deserialized.packedE));
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.BAR}, deserialized.repeatedE2));
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.FOO}, deserialized.packedE2));
+ assertEquals(0, deserialized.repeatedE3.length);
+ assertEquals(0, deserialized.packedE3.length);
+
+ // Test 2: tests that invalid values do not override previous values in the field, including
+ // arrays, including pre-existing invalid values.
+ deserialized.optionalE = EnumValidity.E.BAR;
+ deserialized.defaultE = alsoInvalid;
+ deserialized.repeatedE = new int[] {EnumValidity.E.BAZ};
+ deserialized.packedE = new int[] {EnumValidity.E.BAZ, alsoInvalid};
+ deserialized.repeatedE2 = new int[] {invalid, alsoInvalid};
+ deserialized.packedE2 = null;
+ deserialized.repeatedE3 = null;
+ deserialized.packedE3 = new int[0];
+ MessageNano.mergeFrom(deserialized, serialized);
+ assertEquals(EnumValidity.E.BAR, deserialized.optionalE);
+ assertEquals(alsoInvalid, deserialized.defaultE);
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.BAZ, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAR},
+ deserialized.repeatedE));
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.BAZ, alsoInvalid, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAZ},
+ deserialized.packedE));
+ assertTrue(Arrays.equals(
+ new int[] {invalid, alsoInvalid, /* + */ EnumValidity.E.BAR},
+ deserialized.repeatedE2));
+ assertTrue(Arrays.equals(
+ new int[] {/* <null> + */ EnumValidity.E.FOO},
+ deserialized.packedE2));
+ assertNull(deserialized.repeatedE3); // null + all invalid == null
+ assertEquals(0, deserialized.packedE3.length); // empty + all invalid == empty
+
+ // Test 3: reading by alternative forms
+ EnumValidity.Alt alt = MessageNano.mergeFrom(new EnumValidity.Alt(), serialized);
+ assertEquals(EnumValidity.E.BAR, // last valid value in m.repeatedE2
+ alt.repeatedE2AsOptional);
+ assertTrue(Arrays.equals(new int[] {EnumValidity.E.FOO}, alt.packedE2AsNonPacked));
+ assertEquals(0, alt.nonPackedE3AsPacked.length);
+ }
+
+ /**
+ * Tests the same as {@link #testNanoEnumValidity()} with accessor style. Repeated fields are
+ * not re-tested here because they are not affected by the accessor style.
+ */
+ public void testNanoEnumValidityAccessors() throws Exception {
+ final int invalid = 120;
+ final int alsoInvalid = 121;
+
+ EnumValidityAccessors.M m = new EnumValidityAccessors.M();
+ // Sanity check & baseline of the assertions for the first case below.
+ assertEquals(EnumValidityAccessors.default_, m.getOptionalE());
+ assertEquals(EnumValidityAccessors.BAZ, m.getDefaultE());
+
+ m.setOptionalE(invalid);
+ m.setDefaultE(invalid);
+ // Set repeatedE2 for Alt.repeatedE2AsOptional
+ m.repeatedE2 = new int[] {invalid, EnumValidityAccessors.BAR, alsoInvalid};
+ byte[] serialized = MessageNano.toByteArray(m);
+ // Sanity check that we do have all data in the byte array.
+ assertEquals(10, serialized.length);
+
+ // Test 1: tests that invalid values aren't included in the deserialized message.
+ EnumValidityAccessors.M deserialized =
+ MessageNano.mergeFrom(new EnumValidityAccessors.M(), serialized);
+ assertEquals(EnumValidityAccessors.default_, deserialized.getOptionalE());
+ assertEquals(EnumValidityAccessors.BAZ, deserialized.getDefaultE());
+
+ // Test 2: tests that invalid values do not override previous values in the field, including
+ // pre-existing invalid values.
+ deserialized.setOptionalE(EnumValidityAccessors.BAR);
+ deserialized.setDefaultE(alsoInvalid);
+ MessageNano.mergeFrom(deserialized, serialized);
+ assertEquals(EnumValidityAccessors.BAR, deserialized.getOptionalE());
+ assertEquals(alsoInvalid, deserialized.getDefaultE());
+
+ // Test 3: reading by alternative forms
+ EnumValidityAccessors.Alt alt =
+ MessageNano.mergeFrom(new EnumValidityAccessors.Alt(), serialized);
+ assertEquals(EnumValidityAccessors.BAR, // last valid value in m.repeatedE2
+ alt.getRepeatedE2AsOptional());
+ }
+
+ /**
+ * Tests that code generation correctly wraps a single message into its outer
+ * class. The class {@code SingleMessageNano} is imported from the outer
+ * class {@code UnittestSingleNano}, whose name is implicit. Any error would
+ * cause this method to fail compilation.
+ */
+ public void testNanoSingle() throws Exception {
+ SingleMessageNano msg = new SingleMessageNano();
+ assertNotNull(msg);
+ }
+
+ /**
+ * Tests that code generation correctly skips generating the outer class if
+ * unnecessary, letting a file-scope entity have the same name. The class
+ * {@code MultipleNameClashNano} shares the same name with the file's outer
+ * class defined explicitly, but the file contains no other entities and has
+ * java_multiple_files set. Any error would cause this method to fail
+ * compilation.
+ */
+ public void testNanoMultipleNameClash() throws Exception {
+ MultipleNameClashNano msg = new MultipleNameClashNano();
+ msg.field = 0;
+ }
+
+ /**
+ * Tests that code generation correctly handles enums in different scopes in
+ * a source file with the option java_multiple_files set to true. Any error
+ * would cause this method to fail compilation.
+ */
+ public void testNanoMultipleEnumScoping() throws Exception {
+ FileScopeEnumRefNano msg1 = new FileScopeEnumRefNano();
+ msg1.enumField = UnittestMultipleNano.ONE;
+ MessageScopeEnumRefNano msg2 = new MessageScopeEnumRefNano();
+ msg2.enumField = MessageScopeEnumRefNano.TWO;
+ }
+
+ /**
+ * Tests that code generation with mixed values of the java_multiple_files
+ * options between the main source file and the imported source files would
+ * generate correct references. Any error would cause this method to fail
+ * compilation.
+ */
+ public void testNanoMultipleImportingNonMultiple() throws Exception {
+ UnittestImportNano.ImportMessageNano importMsg = new UnittestImportNano.ImportMessageNano();
+ MultipleImportingNonMultipleNano1 nano1 = new MultipleImportingNonMultipleNano1();
+ nano1.field = importMsg;
+ MultipleImportingNonMultipleNano2 nano2 = new MultipleImportingNonMultipleNano2();
+ nano2.nano1 = nano1;
+ }
+
+ public void testNanoDefaults() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ for (int i = 0; i < 2; i++) {
+ assertEquals(41, msg.defaultInt32);
+ assertEquals(42, msg.defaultInt64);
+ assertEquals(43, msg.defaultUint32);
+ assertEquals(44, msg.defaultUint64);
+ assertEquals(-45, msg.defaultSint32);
+ assertEquals(46, msg.defaultSint64);
+ assertEquals(47, msg.defaultFixed32);
+ assertEquals(48, msg.defaultFixed64);
+ assertEquals(49, msg.defaultSfixed32);
+ assertEquals(-50, msg.defaultSfixed64);
+ assertTrue(51.5f == msg.defaultFloat);
+ assertTrue(52.0e3 == msg.defaultDouble);
+ assertEquals(true, msg.defaultBool);
+ assertEquals("hello", msg.defaultString);
+ assertEquals("world", new String(msg.defaultBytes, "UTF-8"));
+ assertEquals("dünya", msg.defaultStringNonascii);
+ assertEquals("dünyab", new String(msg.defaultBytesNonascii, "UTF-8"));
+ assertEquals(TestAllTypesNano.BAR, msg.defaultNestedEnum);
+ assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.defaultForeignEnum);
+ assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.defaultImportEnum);
+ assertEquals(Float.POSITIVE_INFINITY, msg.defaultFloatInf);
+ assertEquals(Float.NEGATIVE_INFINITY, msg.defaultFloatNegInf);
+ assertEquals(Float.NaN, msg.defaultFloatNan);
+ assertEquals(Double.POSITIVE_INFINITY, msg.defaultDoubleInf);
+ assertEquals(Double.NEGATIVE_INFINITY, msg.defaultDoubleNegInf);
+ assertEquals(Double.NaN, msg.defaultDoubleNan);
+
+ // Default values are not output, except for required fields.
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 3);
+ assertEquals(result.length, msgSerializedSize);
+ msg.clear();
+ }
+ }
+
+ public void testNanoWithHasParseFrom() throws Exception {
+ TestAllTypesNanoHas msg = null;
+ // Test false on creation, after clear and upon empty parse.
+ for (int i = 0; i < 3; i++) {
+ if (i == 0) {
+ msg = new TestAllTypesNanoHas();
+ } else if (i == 1) {
+ msg.clear();
+ } else if (i == 2) {
+ msg = TestAllTypesNanoHas.parseFrom(new byte[0]);
+ }
+ assertFalse(msg.hasOptionalInt32);
+ assertFalse(msg.hasOptionalString);
+ assertFalse(msg.hasOptionalBytes);
+ assertFalse(msg.hasOptionalNestedEnum);
+ assertFalse(msg.hasDefaultInt32);
+ assertFalse(msg.hasDefaultString);
+ assertFalse(msg.hasDefaultBytes);
+ assertFalse(msg.hasDefaultFloatNan);
+ assertFalse(msg.hasDefaultNestedEnum);
+ assertFalse(msg.hasId);
+ assertFalse(msg.hasRequiredEnum);
+ msg.optionalInt32 = 123;
+ msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
+ msg.optionalNestedMessage.bb = 2;
+ msg.optionalNestedEnum = TestAllTypesNano.BAZ;
+ }
+
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 10);
+ assertEquals(result.length, msgSerializedSize);
+
+ // Has fields true upon parse.
+ TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result);
+ assertEquals(123, newMsg.optionalInt32);
+ assertTrue(newMsg.hasOptionalInt32);
+ assertEquals(2, newMsg.optionalNestedMessage.bb);
+ assertTrue(newMsg.optionalNestedMessage.hasBb);
+ assertEquals(TestAllTypesNanoHas.BAZ, newMsg.optionalNestedEnum);
+ assertTrue(newMsg.hasOptionalNestedEnum);
+ }
+
+ public void testNanoWithHasSerialize() throws Exception {
+ TestAllTypesNanoHas msg = new TestAllTypesNanoHas();
+ msg.hasOptionalInt32 = true;
+ msg.hasOptionalString = true;
+ msg.hasOptionalBytes = true;
+ msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
+ msg.optionalNestedMessage.hasBb = true;
+ msg.hasOptionalNestedEnum = true;
+ msg.hasDefaultInt32 = true;
+ msg.hasDefaultString = true;
+ msg.hasDefaultBytes = true;
+ msg.hasDefaultFloatNan = true;
+ msg.hasDefaultNestedEnum = true;
+ msg.hasId = true;
+ msg.hasRequiredEnum = true;
+
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ assertEquals(result.length, msgSerializedSize);
+
+ // Now deserialize and find that all fields are set and equal to their defaults.
+ TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result);
+ assertTrue(newMsg.hasOptionalInt32);
+ assertTrue(newMsg.hasOptionalString);
+ assertTrue(newMsg.hasOptionalBytes);
+ assertTrue(newMsg.optionalNestedMessage.hasBb);
+ assertTrue(newMsg.hasOptionalNestedEnum);
+ assertTrue(newMsg.hasDefaultInt32);
+ assertTrue(newMsg.hasDefaultString);
+ assertTrue(newMsg.hasDefaultBytes);
+ assertTrue(newMsg.hasDefaultFloatNan);
+ assertTrue(newMsg.hasDefaultNestedEnum);
+ assertTrue(newMsg.hasId);
+ assertTrue(newMsg.hasRequiredEnum);
+ assertEquals(0, newMsg.optionalInt32);
+ assertEquals(0, newMsg.optionalString.length());
+ assertEquals(0, newMsg.optionalBytes.length);
+ assertEquals(0, newMsg.optionalNestedMessage.bb);
+ assertEquals(TestAllTypesNanoHas.FOO, newMsg.optionalNestedEnum);
+ assertEquals(41, newMsg.defaultInt32);
+ assertEquals("hello", newMsg.defaultString);
+ assertEquals("world", new String(newMsg.defaultBytes, "UTF-8"));
+ assertEquals(TestAllTypesNanoHas.BAR, newMsg.defaultNestedEnum);
+ assertEquals(Float.NaN, newMsg.defaultFloatNan);
+ assertEquals(0, newMsg.id);
+ assertEquals(TestAllTypesNanoHas.FOO, newMsg.requiredEnum);
+ }
+
+ public void testNanoWithAccessorsBasic() throws Exception {
+ TestNanoAccessors msg = new TestNanoAccessors();
+
+ // Makes sure required, repeated, and message fields are still public
+ msg.id = 3;
+ msg.repeatedBytes = new byte[2][3];
+ msg.optionalNestedMessage = null;
+
+ // Test accessors
+ assertEquals(0, msg.getOptionalInt32());
+ assertFalse(msg.hasOptionalInt32());
+ msg.setOptionalInt32(135);
+ assertEquals(135, msg.getOptionalInt32());
+ assertTrue(msg.hasOptionalInt32());
+ msg.clearOptionalInt32();
+ assertFalse(msg.hasOptionalInt32());
+ msg.setOptionalInt32(0); // default value
+ assertTrue(msg.hasOptionalInt32());
+
+ // Test NPE
+ try {
+ msg.setOptionalBytes(null);
+ fail();
+ } catch (NullPointerException expected) {}
+ try {
+ msg.setOptionalString(null);
+ fail();
+ } catch (NullPointerException expected) {}
+
+ // Test has bit on bytes field with defaults and clear() re-clones the default array
+ assertFalse(msg.hasDefaultBytes());
+ byte[] defaultBytes = msg.getDefaultBytes();
+ msg.setDefaultBytes(defaultBytes);
+ assertTrue(msg.hasDefaultBytes());
+ msg.clearDefaultBytes();
+ assertFalse(msg.hasDefaultBytes());
+ defaultBytes[0]++; // modify original array
+ assertFalse(Arrays.equals(defaultBytes, msg.getDefaultBytes()));
+
+ // Test has bits that require additional bit fields
+ assertFalse(msg.hasBitFieldCheck());
+ msg.setBitFieldCheck(0);
+ assertTrue(msg.hasBitFieldCheck());
+ assertFalse(msg.hasBeforeBitFieldCheck()); // checks bit field does not leak
+ assertFalse(msg.hasAfterBitFieldCheck());
+
+ // Test clear() clears has bits
+ msg.setOptionalString("hi");
+ msg.setDefaultString("there");
+ msg.clear();
+ assertFalse(msg.hasOptionalString());
+ assertFalse(msg.hasDefaultString());
+ assertFalse(msg.hasBitFieldCheck());
+
+ // Test set() and clear() returns itself (compiles = success)
+ msg.clear()
+ .setOptionalInt32(3)
+ .clearDefaultBytes()
+ .setOptionalString("4");
+ }
+
+ public void testNanoWithAccessorsParseFrom() throws Exception {
+ TestNanoAccessors msg = null;
+ // Test false on creation, after clear and upon empty parse.
+ for (int i = 0; i < 3; i++) {
+ if (i == 0) {
+ msg = new TestNanoAccessors();
+ } else if (i == 1) {
+ msg.clear();
+ } else if (i == 2) {
+ msg = TestNanoAccessors.parseFrom(new byte[0]);
+ }
+ assertFalse(msg.hasOptionalInt32());
+ assertFalse(msg.hasOptionalString());
+ assertFalse(msg.hasOptionalBytes());
+ assertFalse(msg.hasOptionalNestedEnum());
+ assertFalse(msg.hasDefaultInt32());
+ assertFalse(msg.hasDefaultString());
+ assertFalse(msg.hasDefaultBytes());
+ assertFalse(msg.hasDefaultFloatNan());
+ assertFalse(msg.hasDefaultNestedEnum());
+ msg.optionalNestedMessage = new TestNanoAccessors.NestedMessage();
+ msg.optionalNestedMessage.setBb(2);
+ msg.setOptionalNestedEnum(TestNanoAccessors.BAZ);
+ msg.setDefaultInt32(msg.getDefaultInt32());
+ }
+
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 14);
+ assertEquals(result.length, msgSerializedSize);
+
+ // Has fields true upon parse.
+ TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
+ assertEquals(2, newMsg.optionalNestedMessage.getBb());
+ assertTrue(newMsg.optionalNestedMessage.hasBb());
+ assertEquals(TestNanoAccessors.BAZ, newMsg.getOptionalNestedEnum());
+ assertTrue(newMsg.hasOptionalNestedEnum());
+
+ // Has field true on fields with explicit default values from wire.
+ assertTrue(newMsg.hasDefaultInt32());
+ assertEquals(41, newMsg.getDefaultInt32());
+ }
+
+ public void testNanoWithAccessorsPublicFieldTypes() throws Exception {
+ TestNanoAccessors msg = new TestNanoAccessors();
+ assertNull(msg.optionalNestedMessage);
+ assertEquals(0, msg.id);
+ assertEquals(0, msg.repeatedNestedEnum.length);
+
+ TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(MessageNano.toByteArray(msg));
+ assertNull(newMsg.optionalNestedMessage);
+ assertEquals(0, newMsg.id);
+ assertEquals(0, newMsg.repeatedNestedEnum.length);
+
+ TestNanoAccessors.NestedMessage nestedMessage = new TestNanoAccessors.NestedMessage();
+ nestedMessage.setBb(5);
+ newMsg.optionalNestedMessage = nestedMessage;
+ newMsg.id = -1;
+ newMsg.repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
+
+ TestNanoAccessors newMsg2 = TestNanoAccessors.parseFrom(MessageNano.toByteArray(newMsg));
+ assertEquals(nestedMessage.getBb(), newMsg2.optionalNestedMessage.getBb());
+ assertEquals(-1, newMsg2.id);
+ assertEquals(TestAllTypesNano.FOO, newMsg2.repeatedNestedEnum[0]);
+
+ newMsg2.optionalNestedMessage = null;
+ newMsg2.id = 0;
+ newMsg2.repeatedNestedEnum = null;
+
+ TestNanoAccessors newMsg3 = TestNanoAccessors.parseFrom(MessageNano.toByteArray(newMsg2));
+ assertNull(newMsg3.optionalNestedMessage);
+ assertEquals(0, newMsg3.id);
+ assertEquals(0, newMsg3.repeatedNestedEnum.length);
+ }
+
+ public void testNanoWithAccessorsSerialize() throws Exception {
+ TestNanoAccessors msg = new TestNanoAccessors();
+ msg.setOptionalInt32(msg.getOptionalInt32());
+ msg.setOptionalString(msg.getOptionalString());
+ msg.setOptionalBytes(msg.getOptionalBytes());
+ TestNanoAccessors.NestedMessage nestedMessage = new TestNanoAccessors.NestedMessage();
+ nestedMessage.setBb(nestedMessage.getBb());
+ msg.optionalNestedMessage = nestedMessage;
+ msg.setOptionalNestedEnum(msg.getOptionalNestedEnum());
+ msg.setDefaultInt32(msg.getDefaultInt32());
+ msg.setDefaultString(msg.getDefaultString());
+ msg.setDefaultBytes(msg.getDefaultBytes());
+ msg.setDefaultFloatNan(msg.getDefaultFloatNan());
+ msg.setDefaultNestedEnum(msg.getDefaultNestedEnum());
+
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ assertEquals(result.length, msgSerializedSize);
+
+ // Now deserialize and find that all fields are set and equal to their defaults.
+ TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
+ assertTrue(newMsg.hasOptionalInt32());
+ assertTrue(newMsg.hasOptionalString());
+ assertTrue(newMsg.hasOptionalBytes());
+ assertTrue(newMsg.optionalNestedMessage.hasBb());
+ assertTrue(newMsg.hasOptionalNestedEnum());
+ assertTrue(newMsg.hasDefaultInt32());
+ assertTrue(newMsg.hasDefaultString());
+ assertTrue(newMsg.hasDefaultBytes());
+ assertTrue(newMsg.hasDefaultFloatNan());
+ assertTrue(newMsg.hasDefaultNestedEnum());
+ assertEquals(0, newMsg.getOptionalInt32());
+ assertEquals(0, newMsg.getOptionalString().length());
+ assertEquals(0, newMsg.getOptionalBytes().length);
+ assertEquals(0, newMsg.optionalNestedMessage.getBb());
+ assertEquals(TestNanoAccessors.FOO, newMsg.getOptionalNestedEnum());
+ assertEquals(41, newMsg.getDefaultInt32());
+ assertEquals("hello", newMsg.getDefaultString());
+ assertEquals("world", new String(newMsg.getDefaultBytes(), "UTF-8"));
+ assertEquals(TestNanoAccessors.BAR, newMsg.getDefaultNestedEnum());
+ assertEquals(Float.NaN, newMsg.getDefaultFloatNan());
+ assertEquals(0, newMsg.id);
+ }
+
+ public void testNanoJavaEnumStyle() throws Exception {
+ EnumClassNanos.EnumClassNano msg = new EnumClassNanos.EnumClassNano();
+ assertEquals(EnumClassNanos.FileScopeEnum.ONE, msg.one);
+ assertEquals(EnumClassNanos.EnumClassNano.MessageScopeEnum.TWO, msg.two);
+
+ EnumClassNanoMultiple msg2 = new EnumClassNanoMultiple();
+ assertEquals(FileScopeEnumMultiple.THREE, msg2.three);
+ assertEquals(EnumClassNanoMultiple.MessageScopeEnumMultiple.FOUR, msg2.four);
+ }
+
+ /**
+ * Tests that fields with a default value of NaN are not serialized when
+ * set to NaN. This is a special case as NaN != NaN, so normal equality
+ * checks don't work.
+ */
+ public void testNanoNotANumberDefaults() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.defaultDoubleNan = 0;
+ msg.defaultFloatNan = 0;
+ byte[] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ assertTrue(result.length == msgSerializedSize);
+ assertTrue(msgSerializedSize > 3);
+
+ msg.defaultDoubleNan = Double.NaN;
+ msg.defaultFloatNan = Float.NaN;
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ assertEquals(3, result.length);
+ assertEquals(3, msgSerializedSize);
+ }
+
+ /**
+ * Test that a bug in skipRawBytes() has been fixed: if the skip skips
+ * exactly up to a limit, this should not break things.
+ */
+ public void testSkipRawBytesBug() throws Exception {
+ byte[] rawBytes = new byte[] { 1, 2 };
+ CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(rawBytes);
+
+ int limit = input.pushLimit(1);
+ input.skipRawBytes(1);
+ input.popLimit(limit);
+ assertEquals(2, input.readRawByte());
+ }
+
+ /**
+ * Test that a bug in skipRawBytes() has been fixed: if the skip skips
+ * past the end of a buffer with a limit that has been set past the end of
+ * that buffer, this should not break things.
+ */
+ public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
+ byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
+ CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(rawBytes);
+
+ int limit = input.pushLimit(4);
+ // In order to expose the bug we need to read at least one byte to prime the
+ // buffer inside the CodedInputStream.
+ assertEquals(1, input.readRawByte());
+ // Skip to the end of the limit.
+ input.skipRawBytes(3);
+ assertTrue(input.isAtEnd());
+ input.popLimit(limit);
+ assertEquals(5, input.readRawByte());
+ }
+
+ // Test a smattering of various proto types for printing
+ public void testMessageNanoPrinter() {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalInt32 = 14;
+ msg.optionalFloat = 42.3f;
+ msg.optionalString = "String \"with' both quotes";
+ msg.optionalBytes = new byte[] {'"', '\0', 1, 8};
+ msg.optionalGroup = new TestAllTypesNano.OptionalGroup();
+ msg.optionalGroup.a = 15;
+ msg.repeatedInt64 = new long[2];
+ msg.repeatedInt64[0] = 1L;
+ msg.repeatedInt64[1] = -1L;
+ msg.repeatedBytes = new byte[2][];
+ msg.repeatedBytes[1] = new byte[] {'h', 'e', 'l', 'l', 'o'};
+ msg.repeatedGroup = new TestAllTypesNano.RepeatedGroup[2];
+ msg.repeatedGroup[0] = new TestAllTypesNano.RepeatedGroup();
+ msg.repeatedGroup[0].a = -27;
+ msg.repeatedGroup[1] = new TestAllTypesNano.RepeatedGroup();
+ msg.repeatedGroup[1].a = -72;
+ msg.optionalNestedMessage = new TestAllTypesNano.NestedMessage();
+ msg.optionalNestedMessage.bb = 7;
+ msg.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[2];
+ msg.repeatedNestedMessage[0] = new TestAllTypesNano.NestedMessage();
+ msg.repeatedNestedMessage[0].bb = 77;
+ msg.repeatedNestedMessage[1] = new TestAllTypesNano.NestedMessage();
+ msg.repeatedNestedMessage[1].bb = 88;
+ msg.optionalNestedEnum = TestAllTypesNano.BAZ;
+ msg.repeatedNestedEnum = new int[2];
+ msg.repeatedNestedEnum[0] = TestAllTypesNano.BAR;
+ msg.repeatedNestedEnum[1] = TestAllTypesNano.FOO;
+ msg.repeatedStringPiece = new String[] {null, "world"};
+ msg.setOneofString("hello");
+
+ String protoPrint = msg.toString();
+ assertTrue(protoPrint.contains("optional_int32: 14"));
+ assertTrue(protoPrint.contains("optional_float: 42.3"));
+ assertTrue(protoPrint.contains("optional_double: 0.0"));
+ assertTrue(protoPrint.contains("optional_string: \"String \\u0022with\\u0027 both quotes\""));
+ assertTrue(protoPrint.contains("optional_bytes: \"\\\"\\000\\001\\010\""));
+ assertTrue(protoPrint.contains("optional_group <\n a: 15\n>"));
+
+ assertTrue(protoPrint.contains("repeated_int64: 1\nrepeated_int64: -1"));
+ assertFalse(protoPrint.contains("repeated_bytes: \"\"")); // null should be dropped
+ assertTrue(protoPrint.contains("repeated_bytes: \"hello\""));
+ assertTrue(protoPrint.contains("repeated_group <\n a: -27\n>\n"
+ + "repeated_group <\n a: -72\n>"));
+ assertTrue(protoPrint.contains("optional_nested_message <\n bb: 7\n>"));
+ assertTrue(protoPrint.contains("repeated_nested_message <\n bb: 77\n>\n"
+ + "repeated_nested_message <\n bb: 88\n>"));
+ assertTrue(protoPrint.contains("optional_nested_enum: 3"));
+ assertTrue(protoPrint.contains("repeated_nested_enum: 2\nrepeated_nested_enum: 1"));
+ assertTrue(protoPrint.contains("default_int32: 41"));
+ assertTrue(protoPrint.contains("default_string: \"hello\""));
+ assertFalse(protoPrint.contains("repeated_string_piece: \"\"")); // null should be dropped
+ assertTrue(protoPrint.contains("repeated_string_piece: \"world\""));
+ assertTrue(protoPrint.contains("oneof_string: \"hello\""));
+ }
+
+ public void testMessageNanoPrinterAccessors() throws Exception {
+ TestNanoAccessors msg = new TestNanoAccessors();
+ msg.setOptionalInt32(13);
+ msg.setOptionalString("foo");
+ msg.setOptionalBytes(new byte[] {'"', '\0', 1, 8});
+ msg.optionalNestedMessage = new TestNanoAccessors.NestedMessage();
+ msg.optionalNestedMessage.setBb(7);
+ msg.setOptionalNestedEnum(TestNanoAccessors.BAZ);
+ msg.repeatedInt32 = new int[] { 1, -1 };
+ msg.repeatedString = new String[] { "Hello", "world" };
+ msg.repeatedBytes = new byte[2][];
+ msg.repeatedBytes[1] = new byte[] {'h', 'e', 'l', 'l', 'o'};
+ msg.repeatedNestedMessage = new TestNanoAccessors.NestedMessage[2];
+ msg.repeatedNestedMessage[0] = new TestNanoAccessors.NestedMessage();
+ msg.repeatedNestedMessage[0].setBb(5);
+ msg.repeatedNestedMessage[1] = new TestNanoAccessors.NestedMessage();
+ msg.repeatedNestedMessage[1].setBb(6);
+ msg.repeatedNestedEnum = new int[] { TestNanoAccessors.FOO, TestNanoAccessors.BAR };
+ msg.id = 33;
+
+ String protoPrint = msg.toString();
+ assertTrue(protoPrint.contains("optional_int32: 13"));
+ assertTrue(protoPrint.contains("optional_string: \"foo\""));
+ assertTrue(protoPrint.contains("optional_bytes: \"\\\"\\000\\001\\010\""));
+ assertTrue(protoPrint.contains("optional_nested_message <\n bb: 7\n>"));
+ assertTrue(protoPrint.contains("optional_nested_enum: 3"));
+ assertTrue(protoPrint.contains("repeated_int32: 1\nrepeated_int32: -1"));
+ assertTrue(protoPrint.contains("repeated_string: \"Hello\"\nrepeated_string: \"world\""));
+ assertFalse(protoPrint.contains("repeated_bytes: \"\"")); // null should be dropped
+ assertTrue(protoPrint.contains("repeated_bytes: \"hello\""));
+ assertTrue(protoPrint.contains("repeated_nested_message <\n bb: 5\n>\n"
+ + "repeated_nested_message <\n bb: 6\n>"));
+ assertTrue(protoPrint.contains("repeated_nested_enum: 1\nrepeated_nested_enum: 2"));
+ assertTrue(protoPrint.contains("id: 33"));
+ }
+
+ public void testMessageNanoPrinterForMaps() throws Exception {
+ TestMap msg = new TestMap();
+ MessageValue msgValues[] = new MessageValue[] {
+ new MessageValue(), new MessageValue()
+ };
+ msgValues[0].value = 1;
+ msgValues[1].value = 2;
+ msg.int32ToBytesField = new HashMap<Integer, byte[]>();
+ msg.int32ToBytesField.put(1, new byte[] {'"', '\0'});
+ msg.int32ToBytesField.put(2, new byte[] {1, 8});
+ msg.stringToInt32Field = new HashMap<String, Integer>();
+ msg.stringToInt32Field.put("hello", 1);
+ msg.stringToInt32Field.put("world", 2);
+ msg.int32ToMessageField = new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ msg.int32ToMessageField.put(0, msgValues[0]);
+ msg.int32ToMessageField.put(1, msgValues[1]);
+ msg.int32ToEnumField = new HashMap<Integer, Integer>();
+ msg.int32ToEnumField.put(1, 2);
+ msg.int32ToEnumField.put(2, 3);
+ String protoPrint = msg.toString();
+
+ assertTrue(protoPrint.contains(
+ "int32_to_bytes_field <\n key: 1\n value: \"\\\"\\000\"\n>"));
+ assertTrue(protoPrint.contains(
+ "int32_to_bytes_field <\n key: 2\n value: \"\\001\\010\"\n>"));
+ assertTrue(protoPrint.contains(
+ "string_to_int32_field <\n key: \"hello\"\n value: 1\n>"));
+ assertTrue(protoPrint.contains(
+ "string_to_int32_field <\n key: \"world\"\n value: 2\n>"));
+ assertTrue(protoPrint.contains(
+ "int32_to_message_field <\n key: 0\n value <\n value: 1\n"));
+ assertTrue(protoPrint.contains(
+ "int32_to_message_field <\n key: 1\n value <\n value: 2\n"));
+ assertTrue(protoPrint.contains(
+ "int32_to_enum_field <\n key: 1\n value: 2\n>"));
+ assertTrue(protoPrint.contains(
+ "int32_to_enum_field <\n key: 2\n value: 3\n>"));
+ }
+
+ public void testExtensions() throws Exception {
+ Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
+ message.field = 5;
+ int[] int32s = {1, 2};
+ int[] uint32s = {3, 4};
+ int[] sint32s = {-5, -6};
+ long[] int64s = {7, 8};
+ long[] uint64s = {9, 10};
+ long[] sint64s = {-11, -12};
+ int[] fixed32s = {13, 14};
+ int[] sfixed32s = {-15, -16};
+ long[] fixed64s = {17, 18};
+ long[] sfixed64s = {-19, -20};
+ boolean[] bools = {true, false};
+ float[] floats = {2.1f, 2.2f};
+ double[] doubles = {2.3, 2.4};
+ int[] enums = {Extensions.SECOND_VALUE, Extensions.FIRST_VALUE};
+ String[] strings = {"vijfentwintig", "twenty-six"};
+ byte[][] bytess = {{2, 7}, {2, 8}};
+ AnotherMessage another1 = new AnotherMessage();
+ another1.string = "er shi jiu";
+ another1.value = false;
+ AnotherMessage another2 = new AnotherMessage();
+ another2.string = "trente";
+ another2.value = true;
+ AnotherMessage[] messages = {another1, another2};
+ RepeatedExtensions.RepeatedGroup group1 = new RepeatedExtensions.RepeatedGroup();
+ group1.a = 31;
+ RepeatedExtensions.RepeatedGroup group2 = new RepeatedExtensions.RepeatedGroup();
+ group2.a = 32;
+ RepeatedExtensions.RepeatedGroup[] groups = {group1, group2};
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedInt32));
+ message.setExtension(RepeatedExtensions.repeatedInt32, int32s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedInt32));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedUint32));
+ message.setExtension(RepeatedExtensions.repeatedUint32, uint32s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedUint32));
+ message.setExtension(RepeatedExtensions.repeatedSint32, sint32s);
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedInt64));
+ message.setExtension(RepeatedExtensions.repeatedInt64, int64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedInt64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedUint64));
+ message.setExtension(RepeatedExtensions.repeatedUint64, uint64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedUint64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedSint64));
+ message.setExtension(RepeatedExtensions.repeatedSint64, sint64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedSint64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedFixed32));
+ message.setExtension(RepeatedExtensions.repeatedFixed32, fixed32s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedFixed32));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedSfixed32));
+ message.setExtension(RepeatedExtensions.repeatedSfixed32, sfixed32s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedSfixed32));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedFixed64));
+ message.setExtension(RepeatedExtensions.repeatedFixed64, fixed64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedFixed64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedSfixed64));
+ message.setExtension(RepeatedExtensions.repeatedSfixed64, sfixed64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedSfixed64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedBool));
+ message.setExtension(RepeatedExtensions.repeatedBool, bools);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedBool));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedFloat));
+ message.setExtension(RepeatedExtensions.repeatedFloat, floats);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedFloat));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedDouble));
+ message.setExtension(RepeatedExtensions.repeatedDouble, doubles);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedDouble));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedEnum));
+ message.setExtension(RepeatedExtensions.repeatedEnum, enums);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedEnum));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedString));
+ message.setExtension(RepeatedExtensions.repeatedString, strings);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedString));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedBytes));
+ message.setExtension(RepeatedExtensions.repeatedBytes, bytess);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedBytes));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedMessage));
+ message.setExtension(RepeatedExtensions.repeatedMessage, messages);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedMessage));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedGroup));
+ message.setExtension(RepeatedExtensions.repeatedGroup, groups);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedGroup));
+
+ byte[] data = MessageNano.toByteArray(message);
+ message = Extensions.ExtendableMessage.parseFrom(data);
+ assertEquals(5, message.field);
+
+ // Test reading back using SingularExtensions: the retrieved value should equal the last
+ // in each array.
+ assertEquals(int32s[1], (int) message.getExtension(SingularExtensions.someInt32));
+ assertEquals(uint32s[1], (int) message.getExtension(SingularExtensions.someUint32));
+ assertEquals(sint32s[1], (int) message.getExtension(SingularExtensions.someSint32));
+ assertEquals(int64s[1], (long) message.getExtension(SingularExtensions.someInt64));
+ assertEquals(uint64s[1], (long) message.getExtension(SingularExtensions.someUint64));
+ assertEquals(sint64s[1], (long) message.getExtension(SingularExtensions.someSint64));
+ assertEquals(fixed32s[1], (int) message.getExtension(SingularExtensions.someFixed32));
+ assertEquals(sfixed32s[1], (int) message.getExtension(SingularExtensions.someSfixed32));
+ assertEquals(fixed64s[1], (long) message.getExtension(SingularExtensions.someFixed64));
+ assertEquals(sfixed64s[1], (long) message.getExtension(SingularExtensions.someSfixed64));
+ assertEquals(bools[1], (boolean) message.getExtension(SingularExtensions.someBool));
+ assertEquals(floats[1], (float) message.getExtension(SingularExtensions.someFloat));
+ assertEquals(doubles[1], (double) message.getExtension(SingularExtensions.someDouble));
+ assertEquals(enums[1], (int) message.getExtension(SingularExtensions.someEnum));
+ assertEquals(strings[1], message.getExtension(SingularExtensions.someString));
+ assertTrue(Arrays.equals(bytess[1], message.getExtension(SingularExtensions.someBytes)));
+ AnotherMessage deserializedMessage = message.getExtension(SingularExtensions.someMessage);
+ assertEquals(another2.string, deserializedMessage.string);
+ assertEquals(another2.value, deserializedMessage.value);
+ assertEquals(group2.a, message.getExtension(SingularExtensions.someGroup).a);
+
+ // Test reading back using RepeatedExtensions: the arrays should be equal.
+ message = Extensions.ExtendableMessage.parseFrom(data);
+ assertEquals(5, message.field);
+ assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
+ assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
+ assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
+ assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
+ assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
+ assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
+ assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
+ assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
+ assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
+ assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
+ assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
+ assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
+ assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
+ assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
+ assertTrue(Arrays.equals(strings, message.getExtension(RepeatedExtensions.repeatedString)));
+ byte[][] deserializedRepeatedBytes = message.getExtension(RepeatedExtensions.repeatedBytes);
+ assertEquals(2, deserializedRepeatedBytes.length);
+ assertTrue(Arrays.equals(bytess[0], deserializedRepeatedBytes[0]));
+ assertTrue(Arrays.equals(bytess[1], deserializedRepeatedBytes[1]));
+ AnotherMessage[] deserializedRepeatedMessage =
+ message.getExtension(RepeatedExtensions.repeatedMessage);
+ assertEquals(2, deserializedRepeatedMessage.length);
+ assertEquals(another1.string, deserializedRepeatedMessage[0].string);
+ assertEquals(another1.value, deserializedRepeatedMessage[0].value);
+ assertEquals(another2.string, deserializedRepeatedMessage[1].string);
+ assertEquals(another2.value, deserializedRepeatedMessage[1].value);
+ RepeatedExtensions.RepeatedGroup[] deserializedRepeatedGroup =
+ message.getExtension(RepeatedExtensions.repeatedGroup);
+ assertEquals(2, deserializedRepeatedGroup.length);
+ assertEquals(group1.a, deserializedRepeatedGroup[0].a);
+ assertEquals(group2.a, deserializedRepeatedGroup[1].a);
+
+ message = Extensions.ExtendableMessage.parseFrom(data);
+ assertEquals(5, message.field);
+ // Test hasExtension using PackedExtensions.
+ assertTrue(message.hasExtension(PackedExtensions.packedInt32));
+ assertTrue(message.hasExtension(PackedExtensions.packedUint32));
+ assertTrue(message.hasExtension(PackedExtensions.packedSint32));
+ assertTrue(message.hasExtension(PackedExtensions.packedInt64));
+ assertTrue(message.hasExtension(PackedExtensions.packedUint64));
+ assertTrue(message.hasExtension(PackedExtensions.packedSint64));
+ assertTrue(message.hasExtension(PackedExtensions.packedFixed32));
+ assertTrue(message.hasExtension(PackedExtensions.packedSfixed32));
+ assertTrue(message.hasExtension(PackedExtensions.packedFixed64));
+ assertTrue(message.hasExtension(PackedExtensions.packedSfixed64));
+ assertTrue(message.hasExtension(PackedExtensions.packedBool));
+ assertTrue(message.hasExtension(PackedExtensions.packedFloat));
+ assertTrue(message.hasExtension(PackedExtensions.packedDouble));
+ assertTrue(message.hasExtension(PackedExtensions.packedEnum));
+
+ // Test reading back using PackedExtensions: the arrays should be equal, even the fields
+ // are non-packed.
+ assertTrue(Arrays.equals(int32s, message.getExtension(PackedExtensions.packedInt32)));
+ assertTrue(Arrays.equals(uint32s, message.getExtension(PackedExtensions.packedUint32)));
+ assertTrue(Arrays.equals(sint32s, message.getExtension(PackedExtensions.packedSint32)));
+ assertTrue(Arrays.equals(int64s, message.getExtension(PackedExtensions.packedInt64)));
+ assertTrue(Arrays.equals(uint64s, message.getExtension(PackedExtensions.packedUint64)));
+ assertTrue(Arrays.equals(sint64s, message.getExtension(PackedExtensions.packedSint64)));
+ assertTrue(Arrays.equals(fixed32s, message.getExtension(PackedExtensions.packedFixed32)));
+ assertTrue(Arrays.equals(sfixed32s, message.getExtension(PackedExtensions.packedSfixed32)));
+ assertTrue(Arrays.equals(fixed64s, message.getExtension(PackedExtensions.packedFixed64)));
+ assertTrue(Arrays.equals(sfixed64s, message.getExtension(PackedExtensions.packedSfixed64)));
+ assertTrue(Arrays.equals(bools, message.getExtension(PackedExtensions.packedBool)));
+ assertTrue(Arrays.equals(floats, message.getExtension(PackedExtensions.packedFloat)));
+ assertTrue(Arrays.equals(doubles, message.getExtension(PackedExtensions.packedDouble)));
+ assertTrue(Arrays.equals(enums, message.getExtension(PackedExtensions.packedEnum)));
+
+ // Now set the packable extension values using PackedExtensions so they're serialized packed.
+ message.setExtension(PackedExtensions.packedInt32, int32s);
+ message.setExtension(PackedExtensions.packedUint32, uint32s);
+ message.setExtension(PackedExtensions.packedSint32, sint32s);
+ message.setExtension(PackedExtensions.packedInt64, int64s);
+ message.setExtension(PackedExtensions.packedUint64, uint64s);
+ message.setExtension(PackedExtensions.packedSint64, sint64s);
+ message.setExtension(PackedExtensions.packedFixed32, fixed32s);
+ message.setExtension(PackedExtensions.packedSfixed32, sfixed32s);
+ message.setExtension(PackedExtensions.packedFixed64, fixed64s);
+ message.setExtension(PackedExtensions.packedSfixed64, sfixed64s);
+ message.setExtension(PackedExtensions.packedBool, bools);
+ message.setExtension(PackedExtensions.packedFloat, floats);
+ message.setExtension(PackedExtensions.packedDouble, doubles);
+ message.setExtension(PackedExtensions.packedEnum, enums);
+
+ // And read back using non-packed RepeatedExtensions.
+ byte[] data2 = MessageNano.toByteArray(message);
+ message = MessageNano.mergeFrom(new Extensions.ExtendableMessage(), data2);
+ assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
+ assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
+ assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
+ assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
+ assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
+ assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
+ assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
+ assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
+ assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
+ assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
+ assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
+ assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
+ assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
+ assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
+ }
+
+ public void testNullExtensions() throws Exception {
+ // Check that clearing the extension on an empty message is a no-op.
+ Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
+ assertFalse(message.hasExtension(SingularExtensions.someMessage));
+ message.setExtension(SingularExtensions.someMessage, null);
+ assertFalse(message.hasExtension(SingularExtensions.someMessage));
+ assertEquals(0, MessageNano.toByteArray(message).length);
+
+ // Check that the message is empty after setting and clearing an extension.
+ AnotherMessage another = new AnotherMessage();
+ assertFalse(message.hasExtension(SingularExtensions.someMessage));
+ message.setExtension(SingularExtensions.someMessage, another);
+ assertTrue(message.hasExtension(SingularExtensions.someMessage));
+ assertTrue(MessageNano.toByteArray(message).length > 0);
+ message.setExtension(SingularExtensions.someMessage, null);
+ assertFalse(message.hasExtension(SingularExtensions.someMessage));
+ assertEquals(0, MessageNano.toByteArray(message).length);
+ }
+
+ public void testExtensionsMutation() {
+ Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
+ extendableMessage.setExtension(SingularExtensions.someMessage,
+ new Extensions.AnotherMessage());
+
+ extendableMessage.getExtension(SingularExtensions.someMessage).string = "not empty";
+
+ assertEquals("not empty",
+ extendableMessage.getExtension(SingularExtensions.someMessage).string);
+ }
+
+ public void testExtensionsMutation_Equals() throws InvalidProtocolBufferNanoException {
+ Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
+ extendableMessage.field = 5;
+ int int32 = 42;
+ int[] uint32s = {3, 4};
+ int[] sint32s = {-5, -6};
+ long[] int64s = {7, 8};
+ long[] uint64s = {9, 10};
+ long[] sint64s = {-11, -12};
+ int[] fixed32s = {13, 14};
+ int[] sfixed32s = {-15, -16};
+ long[] fixed64s = {17, 18};
+ long[] sfixed64s = {-19, -20};
+ boolean[] bools = {true, false};
+ float[] floats = {2.1f, 2.2f};
+ double[] doubles = {2.3, 2.4};
+ int[] enums = {Extensions.SECOND_VALUE, Extensions.FIRST_VALUE};
+ String[] strings = {"vijfentwintig", "twenty-six"};
+ byte[][] bytess = {{2, 7}, {2, 8}};
+ AnotherMessage another1 = new AnotherMessage();
+ another1.string = "er shi jiu";
+ another1.value = false;
+ AnotherMessage another2 = new AnotherMessage();
+ another2.string = "trente";
+ another2.value = true;
+ AnotherMessage[] messages = {another1, another2};
+ RepeatedExtensions.RepeatedGroup group1 = new RepeatedExtensions.RepeatedGroup();
+ group1.a = 31;
+ RepeatedExtensions.RepeatedGroup group2 = new RepeatedExtensions.RepeatedGroup();
+ group2.a = 32;
+ RepeatedExtensions.RepeatedGroup[] groups = {group1, group2};
+ extendableMessage.setExtension(SingularExtensions.someInt32, int32);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedUint32, uint32s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedSint32, sint32s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedInt64, int64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedUint64, uint64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedSint64, sint64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedFixed32, fixed32s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedSfixed32, sfixed32s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedFixed64, fixed64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedSfixed64, sfixed64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedBool, bools);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedFloat, floats);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedDouble, doubles);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedEnum, enums);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedString, strings);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedBytes, bytess);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedMessage, messages);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedGroup, groups);
+
+ byte[] data = MessageNano.toByteArray(extendableMessage);
+
+ extendableMessage = Extensions.ExtendableMessage.parseFrom(data);
+ Extensions.ExtendableMessage messageCopy = Extensions.ExtendableMessage.parseFrom(data);
+
+ // Without deserialising.
+ assertEquals(extendableMessage, messageCopy);
+ assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
+
+ // Only one deserialized.
+ extendableMessage.getExtension(SingularExtensions.someInt32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedUint32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedSint32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedInt64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedUint64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedSint64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedFixed32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedSfixed32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedFixed64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedSfixed64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedBool);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedFloat);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedDouble);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedEnum);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedString);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedBytes);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedMessage);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedGroup);
+ assertEquals(extendableMessage, messageCopy);
+ assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
+
+ // Both deserialized.
+ messageCopy.getExtension(SingularExtensions.someInt32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedUint32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedSint32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedInt64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedUint64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedSint64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedFixed32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedSfixed32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedFixed64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedSfixed64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedBool);
+ messageCopy.getExtension(RepeatedExtensions.repeatedFloat);
+ messageCopy.getExtension(RepeatedExtensions.repeatedDouble);
+ messageCopy.getExtension(RepeatedExtensions.repeatedEnum);
+ messageCopy.getExtension(RepeatedExtensions.repeatedString);
+ messageCopy.getExtension(RepeatedExtensions.repeatedBytes);
+ messageCopy.getExtension(RepeatedExtensions.repeatedMessage);
+ messageCopy.getExtension(RepeatedExtensions.repeatedGroup);
+ assertEquals(extendableMessage, messageCopy);
+ assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
+
+ // Change one, make sure they are still different.
+ messageCopy.getExtension(RepeatedExtensions.repeatedMessage)[0].string = "not empty";
+ assertFalse(extendableMessage.equals(messageCopy));
+
+ // Even if the extension hasn't been deserialized.
+ extendableMessage = Extensions.ExtendableMessage.parseFrom(data);
+ assertFalse(extendableMessage.equals(messageCopy));
+ }
+
+ public void testExtensionsCaching() {
+ Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
+ extendableMessage.setExtension(SingularExtensions.someMessage,
+ new Extensions.AnotherMessage());
+ assertSame("Consecutive calls to getExtensions should return the same object",
+ extendableMessage.getExtension(SingularExtensions.someMessage),
+ extendableMessage.getExtension(SingularExtensions.someMessage));
+ }
+
+ public void testUnknownFields() throws Exception {
+ // Check that we roundtrip (serialize and deserialize) unrecognized fields.
+ AnotherMessage message = new AnotherMessage();
+ message.string = "Hello World";
+ message.value = false;
+
+ byte[] bytes = MessageNano.toByteArray(message);
+ int extraFieldSize = CodedOutputByteBufferNano.computeStringSize(
+ 1001, "This is an unknown field");
+ byte[] newBytes = new byte[bytes.length + extraFieldSize];
+ System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
+ CodedOutputByteBufferNano.newInstance(newBytes, bytes.length, extraFieldSize)
+ .writeString(1001, "This is an unknown field");
+
+ // Deserialize with an unknown field.
+ AnotherMessage deserialized = AnotherMessage.parseFrom(newBytes);
+ byte[] serialized = MessageNano.toByteArray(deserialized);
+
+ assertEquals(newBytes.length, serialized.length);
+
+ // Clear, and make sure it clears everything.
+ deserialized.clear();
+ assertEquals(0, MessageNano.toByteArray(deserialized).length);
+ }
+
+ public void testMergeFrom() throws Exception {
+ SimpleMessageNano message = new SimpleMessageNano();
+ message.d = 123;
+ byte[] bytes = MessageNano.toByteArray(message);
+
+ SimpleMessageNano newMessage = MessageNano.mergeFrom(new SimpleMessageNano(), bytes);
+ assertEquals(message.d, newMessage.d);
+ }
+
+ public void testJavaKeyword() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.synchronized_ = 123;
+ assertEquals(123, msg.synchronized_);
+ }
+
+ public void testReferenceTypesForPrimitives() throws Exception {
+ NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
+
+ // Base check - when nothing is set, we serialize nothing.
+ assertHasWireData(message, false);
+
+ message.defaultBool = true;
+ assertHasWireData(message, true);
+
+ message.defaultBool = false;
+ assertHasWireData(message, true);
+
+ message.defaultBool = null;
+ assertHasWireData(message, false);
+
+ message.defaultInt32 = 5;
+ assertHasWireData(message, true);
+
+ message.defaultInt32 = null;
+ assertHasWireData(message, false);
+
+ message.defaultInt64 = 123456L;
+ assertHasWireData(message, true);
+
+ message.defaultInt64 = null;
+ assertHasWireData(message, false);
+
+ message.defaultFloat = 1f;
+ assertHasWireData(message, true);
+
+ message.defaultFloat = null;
+ assertHasWireData(message, false);
+
+ message.defaultDouble = 2.1;
+ assertHasWireData(message, true);
+
+ message.defaultDouble = null;
+ assertHasWireData(message, false);
+
+ message.defaultString = "hello";
+ assertHasWireData(message, true);
+
+ message.defaultString = null;
+ assertHasWireData(message, false);
+
+ message.defaultBytes = new byte[] { 1, 2, 3 };
+ assertHasWireData(message, true);
+
+ message.defaultBytes = null;
+ assertHasWireData(message, false);
+ }
+
+ public void testHashCodeEquals() throws Exception {
+ // Complete equality:
+ TestAllTypesNano a = createMessageForHashCodeEqualsTest();
+ TestAllTypesNano aEquivalent = createMessageForHashCodeEqualsTest();
+
+ assertTrue(MessageNano.messageNanoEquals(a, aEquivalent));
+ assertFalse(MessageNano.messageNanoEquals(a, new TestAllTypesNano()));
+
+ // Null and empty array for repeated fields equality:
+ TestAllTypesNano b = createMessageForHashCodeEqualsTest();
+ b.repeatedBool = null;
+ b.repeatedFloat = new float[0];
+ TestAllTypesNano bEquivalent = createMessageForHashCodeEqualsTest();
+ bEquivalent.repeatedBool = new boolean[0];
+ bEquivalent.repeatedFloat = null;
+
+ // Ref-element-type repeated fields use non-null subsequence equality:
+ TestAllTypesNano c = createMessageForHashCodeEqualsTest();
+ c.repeatedString = null;
+ c.repeatedStringPiece = new String[] {null, "one", null, "two"};
+ c.repeatedBytes = new byte[][] {{3, 4}, null};
+ TestAllTypesNano cEquivalent = createMessageForHashCodeEqualsTest();
+ cEquivalent.repeatedString = new String[3];
+ cEquivalent.repeatedStringPiece = new String[] {"one", "two", null};
+ cEquivalent.repeatedBytes = new byte[][] {{3, 4}};
+
+ // Complete equality for messages with has fields:
+ TestAllTypesNanoHas d = createMessageWithHasForHashCodeEqualsTest();
+ TestAllTypesNanoHas dEquivalent = createMessageWithHasForHashCodeEqualsTest();
+
+ // If has-fields exist, fields with the same default values but
+ // different has-field values are different.
+ TestAllTypesNanoHas e = createMessageWithHasForHashCodeEqualsTest();
+ e.optionalInt32++; // make different from d
+ e.hasDefaultString = false;
+ TestAllTypesNanoHas eDifferent = createMessageWithHasForHashCodeEqualsTest();
+ eDifferent.optionalInt32 = e.optionalInt32;
+ eDifferent.hasDefaultString = true;
+
+ // Complete equality for messages with accessors:
+ TestNanoAccessors f = createMessageWithAccessorsForHashCodeEqualsTest();
+ TestNanoAccessors fEquivalent = createMessageWithAccessorsForHashCodeEqualsTest();
+
+ // If using accessors, explicitly setting a field to its default value
+ // should make the message different.
+ TestNanoAccessors g = createMessageWithAccessorsForHashCodeEqualsTest();
+ g.setOptionalInt32(g.getOptionalInt32() + 1); // make different from f
+ g.clearDefaultString();
+ TestNanoAccessors gDifferent = createMessageWithAccessorsForHashCodeEqualsTest();
+ gDifferent.setOptionalInt32(g.getOptionalInt32());
+ gDifferent.setDefaultString(g.getDefaultString());
+
+ // Complete equality for reference typed messages:
+ NanoReferenceTypes.TestAllTypesNano h = createRefTypedMessageForHashCodeEqualsTest();
+ NanoReferenceTypes.TestAllTypesNano hEquivalent = createRefTypedMessageForHashCodeEqualsTest();
+
+ // Inequality of null and default value for reference typed messages:
+ NanoReferenceTypes.TestAllTypesNano i = createRefTypedMessageForHashCodeEqualsTest();
+ i.optionalInt32 = 1; // make different from h
+ i.optionalFloat = null;
+ NanoReferenceTypes.TestAllTypesNano iDifferent = createRefTypedMessageForHashCodeEqualsTest();
+ iDifferent.optionalInt32 = i.optionalInt32;
+ iDifferent.optionalFloat = 0.0f;
+
+ HashMap<MessageNano, String> hashMap = new HashMap<MessageNano, String>();
+ hashMap.put(a, "a");
+ hashMap.put(b, "b");
+ hashMap.put(c, "c");
+ hashMap.put(d, "d");
+ hashMap.put(e, "e");
+ hashMap.put(f, "f");
+ hashMap.put(g, "g");
+ hashMap.put(h, "h");
+ hashMap.put(i, "i");
+
+ assertEquals(9, hashMap.size()); // a-i should be different from each other.
+
+ assertEquals("a", hashMap.get(a));
+ assertEquals("a", hashMap.get(aEquivalent));
+
+ assertEquals("b", hashMap.get(b));
+ assertEquals("b", hashMap.get(bEquivalent));
+
+ assertEquals("c", hashMap.get(c));
+ assertEquals("c", hashMap.get(cEquivalent));
+
+ assertEquals("d", hashMap.get(d));
+ assertEquals("d", hashMap.get(dEquivalent));
+
+ assertEquals("e", hashMap.get(e));
+ assertNull(hashMap.get(eDifferent));
+
+ assertEquals("f", hashMap.get(f));
+ assertEquals("f", hashMap.get(fEquivalent));
+
+ assertEquals("g", hashMap.get(g));
+ assertNull(hashMap.get(gDifferent));
+
+ assertEquals("h", hashMap.get(h));
+ assertEquals("h", hashMap.get(hEquivalent));
+
+ assertEquals("i", hashMap.get(i));
+ assertNull(hashMap.get(iDifferent));
+ }
+
+ private TestAllTypesNano createMessageForHashCodeEqualsTest() {
+ TestAllTypesNano message = new TestAllTypesNano();
+ message.optionalInt32 = 5;
+ message.optionalInt64 = 777;
+ message.optionalFloat = 1.0f;
+ message.optionalDouble = 2.0;
+ message.optionalBool = true;
+ message.optionalString = "Hello";
+ message.optionalBytes = new byte[] { 1, 2, 3 };
+ message.optionalNestedMessage = new TestAllTypesNano.NestedMessage();
+ message.optionalNestedMessage.bb = 27;
+ message.optionalNestedEnum = TestAllTypesNano.BAR;
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+ message.repeatedInt64 = new long[] { 27L, 28L, 29L };
+ message.repeatedFloat = new float[] { 5.0f, 6.0f };
+ message.repeatedDouble = new double[] { 99.1, 22.5 };
+ message.repeatedBool = new boolean[] { true, false, true };
+ message.repeatedString = new String[] { "One", "Two" };
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+ message.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
+ message.optionalNestedMessage,
+ message.optionalNestedMessage
+ };
+ message.repeatedNestedEnum = new int[] {
+ TestAllTypesNano.BAR,
+ TestAllTypesNano.BAZ
+ };
+ message.setOneofUint32(3);
+ return message;
+ }
+
+ private TestAllTypesNanoHas createMessageWithHasForHashCodeEqualsTest() {
+ TestAllTypesNanoHas message = new TestAllTypesNanoHas();
+ message.optionalInt32 = 5;
+ message.optionalString = "Hello";
+ message.optionalBytes = new byte[] { 1, 2, 3 };
+ message.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
+ message.optionalNestedMessage.bb = 27;
+ message.optionalNestedEnum = TestAllTypesNano.BAR;
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+ message.repeatedString = new String[] { "One", "Two" };
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+ message.repeatedNestedMessage = new TestAllTypesNanoHas.NestedMessage[] {
+ message.optionalNestedMessage,
+ message.optionalNestedMessage
+ };
+ message.repeatedNestedEnum = new int[] {
+ TestAllTypesNano.BAR,
+ TestAllTypesNano.BAZ
+ };
+ return message;
+ }
+
+ private TestNanoAccessors createMessageWithAccessorsForHashCodeEqualsTest() {
+ TestNanoAccessors message = new TestNanoAccessors()
+ .setOptionalInt32(5)
+ .setOptionalString("Hello")
+ .setOptionalBytes(new byte[] {1, 2, 3})
+ .setOptionalNestedEnum(TestNanoAccessors.BAR);
+ message.optionalNestedMessage = new TestNanoAccessors.NestedMessage().setBb(27);
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+ message.repeatedString = new String[] { "One", "Two" };
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+ message.repeatedNestedMessage = new TestNanoAccessors.NestedMessage[] {
+ message.optionalNestedMessage,
+ message.optionalNestedMessage
+ };
+ message.repeatedNestedEnum = new int[] {
+ TestAllTypesNano.BAR,
+ TestAllTypesNano.BAZ
+ };
+ return message;
+ }
+
+ private NanoReferenceTypes.TestAllTypesNano createRefTypedMessageForHashCodeEqualsTest() {
+ NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
+ message.optionalInt32 = 5;
+ message.optionalInt64 = 777L;
+ message.optionalFloat = 1.0f;
+ message.optionalDouble = 2.0;
+ message.optionalBool = true;
+ message.optionalString = "Hello";
+ message.optionalBytes = new byte[] { 1, 2, 3 };
+ message.optionalNestedMessage =
+ new NanoReferenceTypes.TestAllTypesNano.NestedMessage();
+ message.optionalNestedMessage.foo = 27;
+ message.optionalNestedEnum = NanoReferenceTypes.TestAllTypesNano.BAR;
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+ message.repeatedInt64 = new long[] { 27L, 28L, 29L };
+ message.repeatedFloat = new float[] { 5.0f, 6.0f };
+ message.repeatedDouble = new double[] { 99.1, 22.5 };
+ message.repeatedBool = new boolean[] { true, false, true };
+ message.repeatedString = new String[] { "One", "Two" };
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+ message.repeatedNestedMessage =
+ new NanoReferenceTypes.TestAllTypesNano.NestedMessage[] {
+ message.optionalNestedMessage,
+ message.optionalNestedMessage
+ };
+ message.repeatedNestedEnum = new int[] {
+ NanoReferenceTypes.TestAllTypesNano.BAR,
+ NanoReferenceTypes.TestAllTypesNano.BAZ
+ };
+ return message;
+ }
+
+ public void testEqualsWithSpecialFloatingPointValues() throws Exception {
+ // Checks that the nano implementation complies with Object.equals() when treating
+ // floating point numbers, i.e. NaN == NaN and +0.0 != -0.0.
+ // This test assumes that the generated equals() implementations are symmetric, so
+ // there will only be one direction for each equality check.
+
+ TestAllTypesNano m1 = new TestAllTypesNano();
+ m1.optionalFloat = Float.NaN;
+ m1.optionalDouble = Double.NaN;
+ TestAllTypesNano m2 = new TestAllTypesNano();
+ m2.optionalFloat = Float.NaN;
+ m2.optionalDouble = Double.NaN;
+ assertTrue(m1.equals(m2));
+ assertTrue(m1.equals(
+ MessageNano.mergeFrom(new TestAllTypesNano(), MessageNano.toByteArray(m1))));
+
+ m1.optionalFloat = +0f;
+ m2.optionalFloat = -0f;
+ assertFalse(m1.equals(m2));
+
+ m1.optionalFloat = -0f;
+ m1.optionalDouble = +0d;
+ m2.optionalDouble = -0d;
+ assertFalse(m1.equals(m2));
+
+ m1.optionalDouble = -0d;
+ assertTrue(m1.equals(m2));
+ assertFalse(m1.equals(new TestAllTypesNano())); // -0 does not equals() the default +0
+ assertTrue(m1.equals(
+ MessageNano.mergeFrom(new TestAllTypesNano(), MessageNano.toByteArray(m1))));
+
+ // -------
+
+ TestAllTypesNanoHas m3 = new TestAllTypesNanoHas();
+ m3.optionalFloat = Float.NaN;
+ m3.hasOptionalFloat = true;
+ m3.optionalDouble = Double.NaN;
+ m3.hasOptionalDouble = true;
+ TestAllTypesNanoHas m4 = new TestAllTypesNanoHas();
+ m4.optionalFloat = Float.NaN;
+ m4.hasOptionalFloat = true;
+ m4.optionalDouble = Double.NaN;
+ m4.hasOptionalDouble = true;
+ assertTrue(m3.equals(m4));
+ assertTrue(m3.equals(
+ MessageNano.mergeFrom(new TestAllTypesNanoHas(), MessageNano.toByteArray(m3))));
+
+ m3.optionalFloat = +0f;
+ m4.optionalFloat = -0f;
+ assertFalse(m3.equals(m4));
+
+ m3.optionalFloat = -0f;
+ m3.optionalDouble = +0d;
+ m4.optionalDouble = -0d;
+ assertFalse(m3.equals(m4));
+
+ m3.optionalDouble = -0d;
+ m3.hasOptionalFloat = false; // -0 does not equals() the default +0,
+ m3.hasOptionalDouble = false; // so these incorrect 'has' flags should be disregarded.
+ assertTrue(m3.equals(m4)); // note: m4 has the 'has' flags set.
+ assertFalse(m3.equals(new TestAllTypesNanoHas())); // note: the new message has +0 defaults
+ assertTrue(m3.equals(
+ MessageNano.mergeFrom(new TestAllTypesNanoHas(), MessageNano.toByteArray(m3))));
+ // note: the deserialized message has the 'has' flags set.
+
+ // -------
+
+ TestNanoAccessors m5 = new TestNanoAccessors();
+ m5.setOptionalFloat(Float.NaN);
+ m5.setOptionalDouble(Double.NaN);
+ TestNanoAccessors m6 = new TestNanoAccessors();
+ m6.setOptionalFloat(Float.NaN);
+ m6.setOptionalDouble(Double.NaN);
+ assertTrue(m5.equals(m6));
+ assertTrue(m5.equals(
+ MessageNano.mergeFrom(new TestNanoAccessors(), MessageNano.toByteArray(m6))));
+
+ m5.setOptionalFloat(+0f);
+ m6.setOptionalFloat(-0f);
+ assertFalse(m5.equals(m6));
+
+ m5.setOptionalFloat(-0f);
+ m5.setOptionalDouble(+0d);
+ m6.setOptionalDouble(-0d);
+ assertFalse(m5.equals(m6));
+
+ m5.setOptionalDouble(-0d);
+ assertTrue(m5.equals(m6));
+ assertFalse(m5.equals(new TestNanoAccessors()));
+ assertTrue(m5.equals(
+ MessageNano.mergeFrom(new TestNanoAccessors(), MessageNano.toByteArray(m6))));
+
+ // -------
+
+ NanoReferenceTypes.TestAllTypesNano m7 = new NanoReferenceTypes.TestAllTypesNano();
+ m7.optionalFloat = Float.NaN;
+ m7.optionalDouble = Double.NaN;
+ NanoReferenceTypes.TestAllTypesNano m8 = new NanoReferenceTypes.TestAllTypesNano();
+ m8.optionalFloat = Float.NaN;
+ m8.optionalDouble = Double.NaN;
+ assertTrue(m7.equals(m8));
+ assertTrue(m7.equals(MessageNano.mergeFrom(
+ new NanoReferenceTypes.TestAllTypesNano(), MessageNano.toByteArray(m7))));
+
+ m7.optionalFloat = +0f;
+ m8.optionalFloat = -0f;
+ assertFalse(m7.equals(m8));
+
+ m7.optionalFloat = -0f;
+ m7.optionalDouble = +0d;
+ m8.optionalDouble = -0d;
+ assertFalse(m7.equals(m8));
+
+ m7.optionalDouble = -0d;
+ assertTrue(m7.equals(m8));
+ assertFalse(m7.equals(new NanoReferenceTypes.TestAllTypesNano()));
+ assertTrue(m7.equals(MessageNano.mergeFrom(
+ new NanoReferenceTypes.TestAllTypesNano(), MessageNano.toByteArray(m7))));
+ }
+
+ private static TestAllTypesNano generateMessageForOneof(int caseNumber) {
+ TestAllTypesNano result = new TestAllTypesNano();
+ TestAllTypesNano.NestedMessage nested =
+ new TestAllTypesNano.NestedMessage();
+ nested.bb = 2;
+ switch (caseNumber) {
+ case TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER:
+ result.setOneofUint32(1);
+ break;
+ case TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER:
+ result.setOneofEnum(TestAllTypesNano.BAR);
+ break;
+ case TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER:
+ result.setOneofNestedMessage(nested);
+ break;
+ case TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER:
+ result.setOneofBytes(new byte[] {1, 2});
+ break;
+ case TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER:
+ result.setOneofString("hello");
+ break;
+ case TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER:
+ result.setOneofFixed64(-1L);
+ break;
+ default:
+ throw new RuntimeException("unexpected case number: " + caseNumber);
+ }
+ return result;
+ }
+
+ public void testOneofHashCodeEquals() throws Exception {
+ TestAllTypesNano m1 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER);
+ assertEquals(m1, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER));
+ assertFalse(m1.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m2 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(m2, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER));
+ assertFalse(m2.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m3 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER);
+ assertEquals(m3, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER));
+ assertFalse(m3.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m4 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+ assertEquals(m4, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER));
+ assertFalse(m4.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m5 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER);
+ assertEquals(m5, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER));
+ assertFalse(m5.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m6 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER);
+ assertEquals(m6, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER));
+ assertFalse(m6.equals(new TestAllTypesNano()));
+
+ Map<TestAllTypesNano, Integer> map =
+ new HashMap<TestAllTypesNano, Integer>();
+ map.put(m1, 1);
+ map.put(m2, 2);
+ map.put(m3, 3);
+ map.put(m4, 4);
+ map.put(m5, 5);
+ map.put(m6, 6);
+
+ assertEquals(6, map.size());
+ }
+
+ private void checkOneofCase(TestAllTypesNano nano, int field)
+ throws Exception {
+ assertEquals(field, nano.getOneofFieldCase());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER,
+ nano.hasOneofBytes());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER,
+ nano.hasOneofEnum());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER,
+ nano.hasOneofFixed64());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER,
+ nano.hasOneofNestedMessage());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER,
+ nano.hasOneofString());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER,
+ nano.hasOneofUint32());
+
+ }
+
+ public void testOneofDefault() throws Exception {
+ TestAllTypesNano m1 = new TestAllTypesNano();
+ checkOneofCase(m1, 0);
+ assertEquals(WireFormatNano.EMPTY_BYTES, m1.getOneofBytes());
+ assertEquals(TestAllTypesNano.FOO, m1.getOneofEnum());
+ assertEquals(0L, m1.getOneofFixed64());
+ assertEquals(null, m1.getOneofNestedMessage());
+ assertEquals("", m1.getOneofString());
+ assertEquals(0, m1.getOneofUint32());
+ }
+
+ public void testOneofExclusiveness() throws Exception {
+ TestAllTypesNano m = new TestAllTypesNano();
+ checkOneofCase(m, 0);
+
+ m.setOneofBytes(new byte[]{0, 1});
+ checkOneofCase(m, TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+ assertTrue(Arrays.equals(new byte[]{0, 1}, m.getOneofBytes()));
+
+ m.setOneofEnum(TestAllTypesNano.BAZ);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(TestAllTypesNano.BAZ, m.getOneofEnum());
+ assertEquals(WireFormatNano.EMPTY_BYTES, m.getOneofBytes());
+
+ m.setOneofFixed64(-1L);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER);
+ assertEquals(-1L, m.getOneofFixed64());
+ assertEquals(TestAllTypesNano.FOO, m.getOneofEnum());
+
+ m.setOneofNestedMessage(new TestAllTypesNano.NestedMessage());
+ checkOneofCase(m, TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER);
+ assertEquals(
+ new TestAllTypesNano.NestedMessage(), m.getOneofNestedMessage());
+ assertEquals(0L, m.getOneofFixed64());
+
+ m.setOneofString("hello");
+ checkOneofCase(m, TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER);
+ assertEquals("hello", m.getOneofString());
+ assertNull(m.getOneofNestedMessage());
+
+ m.setOneofUint32(10);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER);
+ assertEquals(10, m.getOneofUint32());
+ assertEquals("", m.getOneofString());
+
+ m.setOneofBytes(new byte[]{0, 1});
+ checkOneofCase(m, TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+ assertTrue(Arrays.equals(new byte[]{0, 1}, m.getOneofBytes()));
+ assertEquals(0, m.getOneofUint32());
+ }
+
+ public void testOneofClear() throws Exception {
+ TestAllTypesNano m = new TestAllTypesNano();
+ m.setOneofBytes(new byte[]{0, 1});
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofEnum(TestAllTypesNano.BAZ);
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofFixed64(-1L);
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofNestedMessage(new TestAllTypesNano.NestedMessage());
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofString("hello");
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofUint32(10);
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+ }
+
+ public void testOneofMarshaling() throws Exception {
+ TestAllTypesNano m = new TestAllTypesNano();
+ TestAllTypesNano parsed = new TestAllTypesNano();
+ {
+ m.setOneofBytes(new byte[]{0, 1});
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(parsed, TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+ assertTrue(Arrays.equals(new byte[]{0, 1}, parsed.getOneofBytes()));
+ }
+ {
+ m.setOneofEnum(TestAllTypesNano.BAZ);
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(TestAllTypesNano.BAZ, m.getOneofEnum());
+ }
+ {
+ m.setOneofEnum(TestAllTypesNano.BAZ);
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(TestAllTypesNano.BAZ, m.getOneofEnum());
+ }
+ {
+ m.setOneofFixed64(-1L);
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER);
+ assertEquals(-1L, m.getOneofFixed64());
+ }
+ {
+ m.setOneofNestedMessage(new TestAllTypesNano.NestedMessage());
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER);
+ assertEquals(
+ new TestAllTypesNano.NestedMessage(), m.getOneofNestedMessage());
+ }
+ {
+ m.setOneofString("hello");
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ assertEquals("hello", m.getOneofString());
+ assertNull(m.getOneofNestedMessage());
+ }
+ {
+ m.setOneofUint32(10);
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER);
+ assertEquals(10, m.getOneofUint32());
+ }
+ }
+
+ public void testOneofSerializedConcat() throws Exception {
+ TestAllTypesNano m1 = new TestAllTypesNano();
+ m1.setOneofBytes(new byte[] {0, 1});
+ byte[] b1 = MessageNano.toByteArray(m1);
+ TestAllTypesNano m2 = new TestAllTypesNano();
+ m2.setOneofEnum(TestAllTypesNano.BAZ);
+ byte[] b2 = MessageNano.toByteArray(m2);
+ byte[] b3 = new byte[b1.length + b2.length];
+ System.arraycopy(b1, 0, b3, 0, b1.length);
+ System.arraycopy(b2, 0, b3, b1.length, b2.length);
+ TestAllTypesNano parsed = new TestAllTypesNano();
+ MessageNano.mergeFrom(parsed, b3);
+ // the last on the wire wins.
+ checkOneofCase(parsed, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(TestAllTypesNano.BAZ, parsed.getOneofEnum());
+ }
+
+ public void testNullRepeatedFields() throws Exception {
+ // Check that serialization after explicitly setting a repeated field
+ // to null doesn't NPE.
+ TestAllTypesNano message = new TestAllTypesNano();
+ message.repeatedInt32 = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedNestedEnum = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedBytes = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedNestedMessage = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedPackedInt32 = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedPackedNestedEnum = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ // Create a second message to merge into message.
+ TestAllTypesNano secondMessage = new TestAllTypesNano();
+ secondMessage.repeatedInt32 = new int[] {1, 2, 3};
+ secondMessage.repeatedNestedEnum = new int[] {
+ TestAllTypesNano.FOO, TestAllTypesNano.BAR
+ };
+ secondMessage.repeatedBytes = new byte[][] {{1, 2}, {3, 4}};
+ TestAllTypesNano.NestedMessage nested =
+ new TestAllTypesNano.NestedMessage();
+ nested.bb = 55;
+ secondMessage.repeatedNestedMessage =
+ new TestAllTypesNano.NestedMessage[] {nested};
+ secondMessage.repeatedPackedInt32 = new int[] {1, 2, 3};
+ secondMessage.repeatedPackedNestedEnum = new int[] {
+ TestAllTypesNano.FOO, TestAllTypesNano.BAR
+ };
+
+ // Should not NPE
+ message.mergeFrom(CodedInputByteBufferNano.newInstance(
+ MessageNano.toByteArray(secondMessage)));
+ assertEquals(3, message.repeatedInt32.length);
+ assertEquals(3, message.repeatedInt32[2]);
+ assertEquals(2, message.repeatedNestedEnum.length);
+ assertEquals(TestAllTypesNano.FOO, message.repeatedNestedEnum[0]);
+ assertEquals(2, message.repeatedBytes.length);
+ assertEquals(4, message.repeatedBytes[1][1]);
+ assertEquals(1, message.repeatedNestedMessage.length);
+ assertEquals(55, message.repeatedNestedMessage[0].bb);
+ assertEquals(3, message.repeatedPackedInt32.length);
+ assertEquals(2, message.repeatedPackedInt32[1]);
+ assertEquals(2, message.repeatedPackedNestedEnum.length);
+ assertEquals(TestAllTypesNano.BAR, message.repeatedPackedNestedEnum[1]);
+ }
+
+ public void testNullRepeatedFieldElements() throws Exception {
+ // Check that serialization with null array elements doesn't NPE.
+ String string1 = "1";
+ String string2 = "2";
+ byte[] bytes1 = {3, 4};
+ byte[] bytes2 = {5, 6};
+ TestAllTypesNano.NestedMessage msg1 = new TestAllTypesNano.NestedMessage();
+ msg1.bb = 7;
+ TestAllTypesNano.NestedMessage msg2 = new TestAllTypesNano.NestedMessage();
+ msg2.bb = 8;
+
+ TestAllTypesNano message = new TestAllTypesNano();
+ message.repeatedString = new String[] {null, string1, string2};
+ message.repeatedBytes = new byte[][] {bytes1, null, bytes2};
+ message.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {msg1, msg2, null};
+ message.repeatedGroup = new TestAllTypesNano.RepeatedGroup[] {null, null, null};
+
+ byte[] serialized = MessageNano.toByteArray(message); // should not NPE
+ TestAllTypesNano deserialized = MessageNano.mergeFrom(new TestAllTypesNano(), serialized);
+ assertEquals(2, deserialized.repeatedString.length);
+ assertEquals(string1, deserialized.repeatedString[0]);
+ assertEquals(string2, deserialized.repeatedString[1]);
+ assertEquals(2, deserialized.repeatedBytes.length);
+ assertTrue(Arrays.equals(bytes1, deserialized.repeatedBytes[0]));
+ assertTrue(Arrays.equals(bytes2, deserialized.repeatedBytes[1]));
+ assertEquals(2, deserialized.repeatedNestedMessage.length);
+ assertEquals(msg1.bb, deserialized.repeatedNestedMessage[0].bb);
+ assertEquals(msg2.bb, deserialized.repeatedNestedMessage[1].bb);
+ assertEquals(0, deserialized.repeatedGroup.length);
+ }
+
+ public void testRepeatedMerge() throws Exception {
+ // Check that merging repeated fields cause the arrays to expand with
+ // new data.
+ TestAllTypesNano first = new TestAllTypesNano();
+ first.repeatedInt32 = new int[] {1, 2, 3};
+ TestAllTypesNano second = new TestAllTypesNano();
+ second.repeatedInt32 = new int[] {4, 5};
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(5, first.repeatedInt32.length);
+ assertEquals(1, first.repeatedInt32[0]);
+ assertEquals(4, first.repeatedInt32[3]);
+
+ first = new TestAllTypesNano();
+ first.repeatedNestedEnum = new int[] {TestAllTypesNano.BAR};
+ second = new TestAllTypesNano();
+ second.repeatedNestedEnum = new int[] {TestAllTypesNano.FOO};
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(2, first.repeatedNestedEnum.length);
+ assertEquals(TestAllTypesNano.BAR, first.repeatedNestedEnum[0]);
+ assertEquals(TestAllTypesNano.FOO, first.repeatedNestedEnum[1]);
+
+ first = new TestAllTypesNano();
+ first.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
+ new TestAllTypesNano.NestedMessage()
+ };
+ first.repeatedNestedMessage[0].bb = 3;
+ second = new TestAllTypesNano();
+ second.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
+ new TestAllTypesNano.NestedMessage()
+ };
+ second.repeatedNestedMessage[0].bb = 5;
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(2, first.repeatedNestedMessage.length);
+ assertEquals(3, first.repeatedNestedMessage[0].bb);
+ assertEquals(5, first.repeatedNestedMessage[1].bb);
+
+ first = new TestAllTypesNano();
+ first.repeatedPackedSfixed64 = new long[] {-1, -2, -3};
+ second = new TestAllTypesNano();
+ second.repeatedPackedSfixed64 = new long[] {-4, -5};
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(5, first.repeatedPackedSfixed64.length);
+ assertEquals(-1, first.repeatedPackedSfixed64[0]);
+ assertEquals(-4, first.repeatedPackedSfixed64[3]);
+
+ first = new TestAllTypesNano();
+ first.repeatedPackedNestedEnum = new int[] {TestAllTypesNano.BAR};
+ second = new TestAllTypesNano();
+ second.repeatedPackedNestedEnum = new int[] {TestAllTypesNano.FOO};
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(2, first.repeatedPackedNestedEnum.length);
+ assertEquals(TestAllTypesNano.BAR, first.repeatedPackedNestedEnum[0]);
+ assertEquals(TestAllTypesNano.FOO, first.repeatedPackedNestedEnum[1]);
+
+ // Now test repeated merging in a nested scope
+ TestRepeatedMergeNano firstContainer = new TestRepeatedMergeNano();
+ firstContainer.contained = new TestAllTypesNano();
+ firstContainer.contained.repeatedInt32 = new int[] {10, 20};
+ TestRepeatedMergeNano secondContainer = new TestRepeatedMergeNano();
+ secondContainer.contained = new TestAllTypesNano();
+ secondContainer.contained.repeatedInt32 = new int[] {30};
+ MessageNano.mergeFrom(firstContainer, MessageNano.toByteArray(secondContainer));
+ assertEquals(3, firstContainer.contained.repeatedInt32.length);
+ assertEquals(20, firstContainer.contained.repeatedInt32[1]);
+ assertEquals(30, firstContainer.contained.repeatedInt32[2]);
+ }
+
+ public void testRepeatedPackables() throws Exception {
+ // Check that repeated fields with packable types can accept both packed and unpacked
+ // serialized forms.
+ NanoRepeatedPackables.NonPacked nonPacked = new NanoRepeatedPackables.NonPacked();
+ // Exaggerates the first values of varint-typed arrays. This is to test that the parsing code
+ // of packed fields handles non-packed data correctly. If the code incorrectly thinks it is
+ // reading from a packed tag, it will read the first value as the byte length of the field,
+ // and the large number will cause the input to go out of bounds, thus capturing the error.
+ nonPacked.int32S = new int[] {1000, 2, 3};
+ nonPacked.int64S = new long[] {4000, 5, 6};
+ nonPacked.uint32S = new int[] {7000, 8, 9};
+ nonPacked.uint64S = new long[] {10000, 11, 12};
+ nonPacked.sint32S = new int[] {13000, 14, 15};
+ nonPacked.sint64S = new long[] {16000, 17, 18};
+ nonPacked.fixed32S = new int[] {19, 20, 21};
+ nonPacked.fixed64S = new long[] {22, 23, 24};
+ nonPacked.sfixed32S = new int[] {25, 26, 27};
+ nonPacked.sfixed64S = new long[] {28, 29, 30};
+ nonPacked.floats = new float[] {31, 32, 33};
+ nonPacked.doubles = new double[] {34, 35, 36};
+ nonPacked.bools = new boolean[] {false, true};
+ nonPacked.enums = new int[] {
+ NanoRepeatedPackables.Enum.OPTION_ONE,
+ NanoRepeatedPackables.Enum.OPTION_TWO,
+ };
+ nonPacked.noise = 13579;
+
+ byte[] nonPackedSerialized = MessageNano.toByteArray(nonPacked);
+
+ NanoRepeatedPackables.Packed packed =
+ MessageNano.mergeFrom(new NanoRepeatedPackables.Packed(), nonPackedSerialized);
+ assertRepeatedPackablesEqual(nonPacked, packed);
+
+ byte[] packedSerialized = MessageNano.toByteArray(packed);
+ // Just a cautious check that the two serialized forms are different,
+ // to make sure the remaining of this test is useful:
+ assertFalse(Arrays.equals(nonPackedSerialized, packedSerialized));
+
+ nonPacked = MessageNano.mergeFrom(new NanoRepeatedPackables.NonPacked(), packedSerialized);
+ assertRepeatedPackablesEqual(nonPacked, packed);
+
+ // Test mixed serialized form.
+ byte[] mixedSerialized = new byte[nonPackedSerialized.length + packedSerialized.length];
+ System.arraycopy(nonPackedSerialized, 0, mixedSerialized, 0, nonPackedSerialized.length);
+ System.arraycopy(packedSerialized, 0,
+ mixedSerialized, nonPackedSerialized.length, packedSerialized.length);
+
+ nonPacked = MessageNano.mergeFrom(new NanoRepeatedPackables.NonPacked(), mixedSerialized);
+ packed = MessageNano.mergeFrom(new NanoRepeatedPackables.Packed(), mixedSerialized);
+ assertRepeatedPackablesEqual(nonPacked, packed);
+ assertTrue(Arrays.equals(new int[] {1000, 2, 3, 1000, 2, 3}, nonPacked.int32S));
+ assertTrue(Arrays.equals(new int[] {13000, 14, 15, 13000, 14, 15}, nonPacked.sint32S));
+ assertTrue(Arrays.equals(new int[] {25, 26, 27, 25, 26, 27}, nonPacked.sfixed32S));
+ assertTrue(Arrays.equals(new boolean[] {false, true, false, true}, nonPacked.bools));
+ }
+
+ public void testMapsSerializeAndParse() throws Exception {
+ TestMap origin = new TestMap();
+ setMapMessage(origin);
+ assertMapMessageSet(origin);
+
+ byte[] output = MessageNano.toByteArray(origin);
+ TestMap parsed = new TestMap();
+ MessageNano.mergeFrom(parsed, output);
+ }
+
+ public void testMapSerializeRejectNull() throws Exception {
+ TestMap primitiveMap = new TestMap();
+ primitiveMap.int32ToInt32Field = new HashMap<Integer, Integer>();
+ primitiveMap.int32ToInt32Field.put(null, 1);
+ try {
+ MessageNano.toByteArray(primitiveMap);
+ fail("should reject null keys");
+ } catch (IllegalStateException e) {
+ // pass.
+ }
+
+ TestMap messageMap = new TestMap();
+ messageMap.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ messageMap.int32ToMessageField.put(0, null);
+ try {
+ MessageNano.toByteArray(messageMap);
+ fail("should reject null values");
+ } catch (IllegalStateException e) {
+ // pass.
+ }
+ }
+
+ /**
+ * Tests that merging bytes containing conflicting keys with override the
+ * message value instead of merging the message value into the existing entry.
+ */
+ public void testMapMergeOverrideMessageValues() throws Exception {
+ TestMap.MessageValue origValue = new TestMap.MessageValue();
+ origValue.value = 1;
+ origValue.value2 = 2;
+ TestMap.MessageValue newValue = new TestMap.MessageValue();
+ newValue.value = 3;
+
+ TestMap origMessage = new TestMap();
+ origMessage.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ origMessage.int32ToMessageField.put(1, origValue);
+
+ TestMap newMessage = new TestMap();
+ newMessage.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ newMessage.int32ToMessageField.put(1, newValue);
+ MessageNano.mergeFrom(origMessage,
+ MessageNano.toByteArray(newMessage));
+ TestMap.MessageValue mergedValue = origMessage.int32ToMessageField.get(1);
+ assertEquals(3, mergedValue.value);
+ assertEquals(0, mergedValue.value2);
+ }
+
+ /**
+ * Tests that when merging with empty entries,
+ * we will use default for the key and value, instead of null.
+ */
+ public void testMapMergeEmptyEntry() throws Exception {
+ TestMap testMap = new TestMap();
+ byte[] buffer = new byte[1024];
+ CodedOutputByteBufferNano output =
+ CodedOutputByteBufferNano.newInstance(buffer);
+ // An empty entry for int32_to_int32 map.
+ output.writeTag(1, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(0);
+ // An empty entry for int32_to_message map.
+ output.writeTag(5, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(0);
+
+ CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(
+ buffer, 0, buffer.length - output.spaceLeft());
+ testMap.mergeFrom(input);
+ assertNotNull(testMap.int32ToInt32Field);;
+ assertEquals(1, testMap.int32ToInt32Field.size());
+ assertEquals(Integer.valueOf(0), testMap.int32ToInt32Field.get(0));
+ assertNotNull(testMap.int32ToMessageField);
+ assertEquals(1, testMap.int32ToMessageField.size());
+ TestMap.MessageValue messageValue = testMap.int32ToMessageField.get(0);
+ assertNotNull(messageValue);
+ assertEquals(0, messageValue.value);
+ assertEquals(0, messageValue.value2);
+ }
+
+ public void testMapEquals() throws Exception {
+ TestMap a = new TestMap();
+ TestMap b = new TestMap();
+
+ // empty and null map fields are equal.
+ assertTestMapEqual(a, b);
+ a.int32ToBytesField = new HashMap<Integer, byte[]>();
+ assertTestMapEqual(a, b);
+
+ a.int32ToInt32Field = new HashMap<Integer, Integer>();
+ b.int32ToInt32Field = new HashMap<Integer, Integer>();
+ setMap(a.int32ToInt32Field, deepCopy(int32Values), deepCopy(int32Values));
+ setMap(b.int32ToInt32Field, deepCopy(int32Values), deepCopy(int32Values));
+ assertTestMapEqual(a, b);
+
+ a.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ b.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ setMap(a.int32ToMessageField,
+ deepCopy(int32Values), deepCopy(messageValues));
+ setMap(b.int32ToMessageField,
+ deepCopy(int32Values), deepCopy(messageValues));
+ assertTestMapEqual(a, b);
+
+ a.stringToInt32Field = new HashMap<String, Integer>();
+ b.stringToInt32Field = new HashMap<String, Integer>();
+ setMap(a.stringToInt32Field, deepCopy(stringValues), deepCopy(int32Values));
+ setMap(b.stringToInt32Field, deepCopy(stringValues), deepCopy(int32Values));
+ assertTestMapEqual(a, b);
+
+ a.int32ToBytesField = new HashMap<Integer, byte[]>();
+ b.int32ToBytesField = new HashMap<Integer, byte[]>();
+ setMap(a.int32ToBytesField, deepCopy(int32Values), deepCopy(bytesValues));
+ setMap(b.int32ToBytesField, deepCopy(int32Values), deepCopy(bytesValues));
+ assertTestMapEqual(a, b);
+
+ // Make sure the map implementation does not matter.
+ a.int32ToStringField = new TreeMap<Integer, String>();
+ b.int32ToStringField = new HashMap<Integer, String>();
+ setMap(a.int32ToStringField, deepCopy(int32Values), deepCopy(stringValues));
+ setMap(b.int32ToStringField, deepCopy(int32Values), deepCopy(stringValues));
+ assertTestMapEqual(a, b);
+
+ a.clear();
+ b.clear();
+
+ // unequal cases: different value
+ a.int32ToInt32Field = new HashMap<Integer, Integer>();
+ b.int32ToInt32Field = new HashMap<Integer, Integer>();
+ a.int32ToInt32Field.put(1, 1);
+ b.int32ToInt32Field.put(1, 2);
+ assertTestMapUnequal(a, b);
+ // unequal case: additional entry
+ b.int32ToInt32Field.put(1, 1);
+ b.int32ToInt32Field.put(2, 1);
+ assertTestMapUnequal(a, b);
+ a.int32ToInt32Field.put(2, 1);
+ assertTestMapEqual(a, b);
+
+ // unequal case: different message value.
+ a.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ b.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ MessageValue va = new MessageValue();
+ va.value = 1;
+ MessageValue vb = new MessageValue();
+ vb.value = 1;
+ a.int32ToMessageField.put(1, va);
+ b.int32ToMessageField.put(1, vb);
+ assertTestMapEqual(a, b);
+ vb.value = 2;
+ assertTestMapUnequal(a, b);
+ }
+
+ private static void assertTestMapEqual(TestMap a, TestMap b)
+ throws Exception {
+ assertEquals(a.hashCode(), b.hashCode());
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ }
+
+ private static void assertTestMapUnequal(TestMap a, TestMap b)
+ throws Exception {
+ assertFalse(a.equals(b));
+ assertFalse(b.equals(a));
+ }
+
+ private static final Integer[] int32Values = new Integer[] {
+ 0, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE,
+ };
+
+ private static final Long[] int64Values = new Long[] {
+ 0L, 1L, -1L, Long.MAX_VALUE, Long.MIN_VALUE,
+ };
+
+ private static final String[] stringValues = new String[] {
+ "", "hello", "world", "foo", "bar",
+ };
+
+ private static final byte[][] bytesValues = new byte[][] {
+ new byte[] {},
+ new byte[] {0},
+ new byte[] {1, -1},
+ new byte[] {127, -128},
+ new byte[] {'a', 'b', '0', '1'},
+ };
+
+ private static final Boolean[] boolValues = new Boolean[] {
+ false, true,
+ };
+
+ private static final Integer[] enumValues = new Integer[] {
+ TestMap.FOO, TestMap.BAR, TestMap.BAZ, TestMap.QUX,
+ Integer.MAX_VALUE /* unknown */,
+ };
+
+ private static final TestMap.MessageValue[] messageValues =
+ new TestMap.MessageValue[] {
+ newMapValueMessage(0),
+ newMapValueMessage(1),
+ newMapValueMessage(-1),
+ newMapValueMessage(Integer.MAX_VALUE),
+ newMapValueMessage(Integer.MIN_VALUE),
+ };
+
+ private static TestMap.MessageValue newMapValueMessage(int value) {
+ TestMap.MessageValue result = new TestMap.MessageValue();
+ result.value = value;
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T[] deepCopy(T[] orig) throws Exception {
+ if (orig instanceof MessageValue[]) {
+ MessageValue[] result = new MessageValue[orig.length];
+ for (int i = 0; i < orig.length; i++) {
+ result[i] = new MessageValue();
+ MessageNano.mergeFrom(
+ result[i], MessageNano.toByteArray((MessageValue) orig[i]));
+ }
+ return (T[]) result;
+ }
+ if (orig instanceof byte[][]) {
+ byte[][] result = new byte[orig.length][];
+ for (int i = 0; i < orig.length; i++) {
+ byte[] origBytes = (byte[]) orig[i];
+ result[i] = Arrays.copyOf(origBytes, origBytes.length);
+ }
+ }
+ return Arrays.copyOf(orig, orig.length);
+ }
+
+ private <K, V> void setMap(Map<K, V> map, K[] keys, V[] values) {
+ assert(keys.length == values.length);
+ for (int i = 0; i < keys.length; i++) {
+ map.put(keys[i], values[i]);
+ }
+ }
+
+ private <K, V> void assertMapSet(
+ Map<K, V> map, K[] keys, V[] values) throws Exception {
+ assert(keys.length == values.length);
+ for (int i = 0; i < values.length; i++) {
+ assertEquals(values[i], map.get(keys[i]));
+ }
+ assertEquals(keys.length, map.size());
+ }
+
+ private void setMapMessage(TestMap testMap) {
+ testMap.int32ToInt32Field = new HashMap<Integer, Integer>();
+ testMap.int32ToBytesField = new HashMap<Integer, byte[]>();
+ testMap.int32ToEnumField = new HashMap<Integer, Integer>();
+ testMap.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ testMap.int32ToStringField = new HashMap<Integer, String>();
+ testMap.stringToInt32Field = new HashMap<String, Integer>();
+ testMap.boolToBoolField = new HashMap<Boolean, Boolean>();
+ testMap.uint32ToUint32Field = new HashMap<Integer, Integer>();
+ testMap.sint32ToSint32Field = new HashMap<Integer, Integer>();
+ testMap.fixed32ToFixed32Field = new HashMap<Integer, Integer>();
+ testMap.sfixed32ToSfixed32Field = new HashMap<Integer, Integer>();
+ testMap.int64ToInt64Field = new HashMap<Long, Long>();
+ testMap.uint64ToUint64Field = new HashMap<Long, Long>();
+ testMap.sint64ToSint64Field = new HashMap<Long, Long>();
+ testMap.fixed64ToFixed64Field = new HashMap<Long, Long>();
+ testMap.sfixed64ToSfixed64Field = new HashMap<Long, Long>();
+ setMap(testMap.int32ToInt32Field, int32Values, int32Values);
+ setMap(testMap.int32ToBytesField, int32Values, bytesValues);
+ setMap(testMap.int32ToEnumField, int32Values, enumValues);
+ setMap(testMap.int32ToMessageField, int32Values, messageValues);
+ setMap(testMap.int32ToStringField, int32Values, stringValues);
+ setMap(testMap.stringToInt32Field, stringValues, int32Values);
+ setMap(testMap.boolToBoolField, boolValues, boolValues);
+ setMap(testMap.uint32ToUint32Field, int32Values, int32Values);
+ setMap(testMap.sint32ToSint32Field, int32Values, int32Values);
+ setMap(testMap.fixed32ToFixed32Field, int32Values, int32Values);
+ setMap(testMap.sfixed32ToSfixed32Field, int32Values, int32Values);
+ setMap(testMap.int64ToInt64Field, int64Values, int64Values);
+ setMap(testMap.uint64ToUint64Field, int64Values, int64Values);
+ setMap(testMap.sint64ToSint64Field, int64Values, int64Values);
+ setMap(testMap.fixed64ToFixed64Field, int64Values, int64Values);
+ setMap(testMap.sfixed64ToSfixed64Field, int64Values, int64Values);
+ }
+ private void assertMapMessageSet(TestMap testMap) throws Exception {
+ assertMapSet(testMap.int32ToInt32Field, int32Values, int32Values);
+ assertMapSet(testMap.int32ToBytesField, int32Values, bytesValues);
+ assertMapSet(testMap.int32ToEnumField, int32Values, enumValues);
+ assertMapSet(testMap.int32ToMessageField, int32Values, messageValues);
+ assertMapSet(testMap.int32ToStringField, int32Values, stringValues);
+ assertMapSet(testMap.stringToInt32Field, stringValues, int32Values);
+ assertMapSet(testMap.boolToBoolField, boolValues, boolValues);
+ assertMapSet(testMap.uint32ToUint32Field, int32Values, int32Values);
+ assertMapSet(testMap.sint32ToSint32Field, int32Values, int32Values);
+ assertMapSet(testMap.fixed32ToFixed32Field, int32Values, int32Values);
+ assertMapSet(testMap.sfixed32ToSfixed32Field, int32Values, int32Values);
+ assertMapSet(testMap.int64ToInt64Field, int64Values, int64Values);
+ assertMapSet(testMap.uint64ToUint64Field, int64Values, int64Values);
+ assertMapSet(testMap.sint64ToSint64Field, int64Values, int64Values);
+ assertMapSet(testMap.fixed64ToFixed64Field, int64Values, int64Values);
+ assertMapSet(testMap.sfixed64ToSfixed64Field, int64Values, int64Values);
+ }
+
+ private void assertRepeatedPackablesEqual(
+ NanoRepeatedPackables.NonPacked nonPacked, NanoRepeatedPackables.Packed packed) {
+ // Not using MessageNano.equals() -- that belongs to a separate test.
+ assertTrue(Arrays.equals(nonPacked.int32S, packed.int32S));
+ assertTrue(Arrays.equals(nonPacked.int64S, packed.int64S));
+ assertTrue(Arrays.equals(nonPacked.uint32S, packed.uint32S));
+ assertTrue(Arrays.equals(nonPacked.uint64S, packed.uint64S));
+ assertTrue(Arrays.equals(nonPacked.sint32S, packed.sint32S));
+ assertTrue(Arrays.equals(nonPacked.sint64S, packed.sint64S));
+ assertTrue(Arrays.equals(nonPacked.fixed32S, packed.fixed32S));
+ assertTrue(Arrays.equals(nonPacked.fixed64S, packed.fixed64S));
+ assertTrue(Arrays.equals(nonPacked.sfixed32S, packed.sfixed32S));
+ assertTrue(Arrays.equals(nonPacked.sfixed64S, packed.sfixed64S));
+ assertTrue(Arrays.equals(nonPacked.floats, packed.floats));
+ assertTrue(Arrays.equals(nonPacked.doubles, packed.doubles));
+ assertTrue(Arrays.equals(nonPacked.bools, packed.bools));
+ assertTrue(Arrays.equals(nonPacked.enums, packed.enums));
+ }
+
+ private void assertHasWireData(MessageNano message, boolean expected) {
+ byte[] bytes = MessageNano.toByteArray(message);
+ int wireLength = bytes.length;
+ if (expected) {
+ assertFalse(wireLength == 0);
+ } else {
+ if (wireLength != 0) {
+ fail("Expected no wire data for message \n" + message
+ + "\nBut got:\n"
+ + hexDump(bytes));
+ }
+ }
+ }
+
+ private static String hexDump(byte[] bytes) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append(String.format("%02x ", b));
+ }
+ return sb.toString();
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/map_test.proto b/javanano/src/test/java/com/google/protobuf/nano/map_test.proto
new file mode 100644
index 00000000..f72833ad
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/map_test.proto
@@ -0,0 +1,70 @@
+// 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 = "com.google.protobuf.nano";
+option java_outer_classname = "MapTestProto";
+
+message TestMap {
+ message MessageValue {
+ int32 value = 1;
+ int32 value2 = 2;
+ }
+ enum EnumValue {
+ FOO = 0;
+ BAR = 1;
+ BAZ = 2;
+ QUX = 3;
+ }
+
+ map<int32, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, MessageValue> int32_to_message_field = 5;
+ map<string, int32> string_to_int32_field = 6;
+ map<bool, bool> bool_to_bool_field = 7;
+
+ // Test all the other primitive types. As the key and value are not coupled in
+ // the implementation, we do not test all the combinations of key/value pairs,
+ // so that we can keep the number of test cases manageable
+ map<uint32, uint32> uint32_to_uint32_field = 11;
+ map<sint32, sint32> sint32_to_sint32_field = 12;
+ map<fixed32, fixed32> fixed32_to_fixed32_field = 13;
+ map<sfixed32, sfixed32> sfixed32_to_sfixed32_field = 14;
+ map<int64, int64> int64_to_int64_field = 15;
+ map<uint64, uint64> uint64_to_uint64_field = 16;
+ map<sint64, sint64> sint64_to_sint64_field = 17;
+ map<fixed64, fixed64> fixed64_to_fixed64_field = 18;
+ map<sfixed64, sfixed64> sfixed64_to_sfixed64_field = 19;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto
new file mode 100644
index 00000000..6e5a40f6
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto
@@ -0,0 +1,118 @@
+// 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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoAccessorsOuterClass";
+
+message TestNanoAccessors {
+
+ message NestedMessage {
+ optional int32 bb = 1;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+
+ // Singular
+ optional int32 optional_int32 = 1;
+ optional float optional_float = 11;
+ optional double optional_double = 12;
+ optional string optional_string = 14;
+ optional bytes optional_bytes = 15;
+
+ optional NestedMessage optional_nested_message = 18;
+
+ optional NestedEnum optional_nested_enum = 21;
+
+ // Repeated
+ repeated int32 repeated_int32 = 31;
+ repeated string repeated_string = 44;
+ repeated bytes repeated_bytes = 45;
+
+ repeated NestedMessage repeated_nested_message = 48;
+
+ repeated NestedEnum repeated_nested_enum = 51;
+
+ // Singular with defaults
+ optional int32 default_int32 = 61 [default = 41 ];
+ optional string default_string = 74 [default = "hello"];
+ optional bytes default_bytes = 75 [default = "world"];
+
+ optional float default_float_nan = 99 [default = nan];
+
+ optional NestedEnum default_nested_enum = 81 [default = BAR];
+
+ // Required
+ required int32 id = 86;
+
+ // Add enough optional fields to make 2 bit fields in total
+ optional int32 filler100 = 100;
+ optional int32 filler101 = 101;
+ optional int32 filler102 = 102;
+ optional int32 filler103 = 103;
+ optional int32 filler104 = 104;
+ optional int32 filler105 = 105;
+ optional int32 filler106 = 106;
+ optional int32 filler107 = 107;
+ optional int32 filler108 = 108;
+ optional int32 filler109 = 109;
+ optional int32 filler110 = 110;
+ optional int32 filler111 = 111;
+ optional int32 filler112 = 112;
+ optional int32 filler113 = 113;
+ optional int32 filler114 = 114;
+ optional int32 filler115 = 115;
+ optional int32 filler116 = 116;
+ optional int32 filler117 = 117;
+ optional int32 filler118 = 118;
+ optional int32 filler119 = 119;
+ optional int32 filler120 = 120;
+ optional int32 filler121 = 121;
+ optional int32 filler122 = 122;
+ optional int32 filler123 = 123;
+ optional int32 filler124 = 124;
+ optional int32 filler125 = 125;
+ optional int32 filler126 = 126;
+ optional int32 filler127 = 127;
+ optional int32 filler128 = 128;
+ optional int32 filler129 = 129;
+ optional int32 filler130 = 130;
+
+ optional int32 before_bit_field_check = 139;
+ optional int32 bit_field_check = 140;
+ optional int32 after_bit_field_check = 141;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto
new file mode 100644
index 00000000..e6246bb1
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto
@@ -0,0 +1,48 @@
+// 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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_multiple_files = true;
+
+enum FileScopeEnumMultiple {
+ THREE = 3;
+}
+
+message EnumClassNanoMultiple {
+ enum MessageScopeEnumMultiple {
+ FOUR = 4;
+ }
+ optional FileScopeEnumMultiple three = 3 [ default = THREE ];
+ optional MessageScopeEnumMultiple four = 4 [ default = FOUR ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto
new file mode 100644
index 00000000..33a86225
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto
@@ -0,0 +1,48 @@
+// 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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "EnumClassNanos";
+
+enum FileScopeEnum {
+ ONE = 1;
+}
+
+message EnumClassNano {
+ enum MessageScopeEnum {
+ TWO = 2;
+ }
+ optional FileScopeEnum one = 1 [ default = ONE ];
+ optional MessageScopeEnum two = 2 [ default = TWO ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto
new file mode 100644
index 00000000..f7f57427
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto
@@ -0,0 +1,28 @@
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "EnumValidity";
+
+enum E {
+ default = 1; // test java keyword renaming
+ FOO = 2;
+ BAR = 3;
+ BAZ = 4;
+}
+
+message M {
+ optional E optional_e = 1;
+ optional E default_e = 2 [ default = BAZ ];
+ repeated E repeated_e = 3;
+ repeated E packed_e = 4 [ packed = true ];
+ repeated E repeated_e2 = 5;
+ repeated E packed_e2 = 6 [ packed = true ];
+ repeated E repeated_e3 = 7;
+ repeated E packed_e3 = 8 [ packed = true ];
+}
+
+message Alt {
+ optional E repeated_e2_as_optional = 5;
+ repeated E packed_e2_as_non_packed = 6;
+ repeated E non_packed_e3_as_packed = 7 [ packed = true ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
new file mode 100644
index 00000000..2a678a80
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
@@ -0,0 +1,33 @@
+syntax = "proto2";
+
+option java_outer_classname = "Extensions";
+option java_package = "com.google.protobuf.nano.testext";
+
+message ExtendableMessage {
+ optional int32 field = 1;
+ extensions 10 to max;
+}
+
+enum AnEnum {
+ FIRST_VALUE = 1;
+ SECOND_VALUE = 2;
+}
+
+message AnotherMessage {
+ optional string string = 1;
+ optional bool value = 2;
+}
+
+message ContainerMessage {
+ extend ExtendableMessage {
+ optional bool another_thing = 100;
+ }
+}
+
+// For testNanoOptionalGroupWithUnknownFieldsEnabled;
+// not part of the extensions tests.
+message MessageWithGroup {
+ optional group Group = 1 {
+ optional int32 a = 2;
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto
new file mode 100644
index 00000000..7d47682d
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto
@@ -0,0 +1,29 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.nano";
+
+import "google/protobuf/nano/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message PackedExtensions {
+ extend ExtendableMessage {
+ repeated int32 packed_int32 = 10 [ packed = true ];
+ repeated uint32 packed_uint32 = 11 [ packed = true ];
+ repeated sint32 packed_sint32 = 12 [ packed = true ];
+ repeated int64 packed_int64 = 13 [ packed = true ];
+ repeated uint64 packed_uint64 = 14 [ packed = true ];
+ repeated sint64 packed_sint64 = 15 [ packed = true ];
+ repeated fixed32 packed_fixed32 = 16 [ packed = true ];
+ repeated sfixed32 packed_sfixed32 = 17 [ packed = true ];
+ repeated fixed64 packed_fixed64 = 18 [ packed = true ];
+ repeated sfixed64 packed_sfixed64 = 19 [ packed = true ];
+ repeated bool packed_bool = 20 [ packed = true ];
+ repeated float packed_float = 21 [ packed = true ];
+ repeated double packed_double = 22 [ packed = true ];
+ repeated AnEnum packed_enum = 23 [ packed = true ];
+ // Non-packable types omitted.
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto
new file mode 100644
index 00000000..6d4b5dfb
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto
@@ -0,0 +1,34 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.nano";
+
+import "google/protobuf/nano/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message RepeatedExtensions {
+ extend ExtendableMessage {
+ repeated int32 repeated_int32 = 10;
+ repeated uint32 repeated_uint32 = 11;
+ repeated sint32 repeated_sint32 = 12;
+ repeated int64 repeated_int64 = 13;
+ repeated uint64 repeated_uint64 = 14;
+ repeated sint64 repeated_sint64 = 15;
+ repeated fixed32 repeated_fixed32 = 16;
+ repeated sfixed32 repeated_sfixed32 = 17;
+ repeated fixed64 repeated_fixed64 = 18;
+ repeated sfixed64 repeated_sfixed64 = 19;
+ repeated bool repeated_bool = 20;
+ repeated float repeated_float = 21;
+ repeated double repeated_double = 22;
+ repeated AnEnum repeated_enum = 23;
+ repeated string repeated_string = 24;
+ repeated bytes repeated_bytes = 25;
+ repeated AnotherMessage repeated_message = 26;
+ repeated group RepeatedGroup = 27 {
+ optional int32 a = 1;
+ }
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto
new file mode 100644
index 00000000..589754e7
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto
@@ -0,0 +1,34 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.nano";
+
+import "google/protobuf/nano/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message SingularExtensions {
+ extend ExtendableMessage {
+ optional int32 some_int32 = 10;
+ optional uint32 some_uint32 = 11;
+ optional sint32 some_sint32 = 12;
+ optional int64 some_int64 = 13;
+ optional uint64 some_uint64 = 14;
+ optional sint64 some_sint64 = 15;
+ optional fixed32 some_fixed32 = 16;
+ optional sfixed32 some_sfixed32 = 17;
+ optional fixed64 some_fixed64 = 18;
+ optional sfixed64 some_sfixed64 = 19;
+ optional bool some_bool = 20;
+ optional float some_float = 21;
+ optional double some_double = 22;
+ optional AnEnum some_enum = 23;
+ optional string some_string = 24;
+ optional bytes some_bytes = 25;
+ optional AnotherMessage some_message = 26;
+ optional group SomeGroup = 27 {
+ optional int32 a = 1;
+ }
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto
new file mode 100644
index 00000000..bda1a6ef
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto
@@ -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.
+
+// Author: ulas@google.com (Ulas Kirazci)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoHasOuterClass";
+
+message TestAllTypesNanoHas {
+
+ message NestedMessage {
+ optional int32 bb = 1;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+
+ // Singular
+ optional int32 optional_int32 = 1;
+ optional float optional_float = 11;
+ optional double optional_double = 12;
+ optional string optional_string = 14;
+ optional bytes optional_bytes = 15;
+
+ optional NestedMessage optional_nested_message = 18;
+
+ optional NestedEnum optional_nested_enum = 21;
+
+ // Repeated
+ repeated int32 repeated_int32 = 31;
+ repeated string repeated_string = 44;
+ repeated bytes repeated_bytes = 45;
+
+ repeated NestedMessage repeated_nested_message = 48;
+
+ repeated NestedEnum repeated_nested_enum = 51;
+
+ // Singular with defaults
+ optional int32 default_int32 = 61 [default = 41 ];
+ optional string default_string = 74 [default = "hello"];
+ optional bytes default_bytes = 75 [default = "world"];
+
+ optional float default_float_nan = 99 [default = nan];
+
+ optional NestedEnum default_nested_enum = 81 [default = BAR];
+
+ required int32 id = 86;
+ required NestedEnum required_enum = 87;
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto
new file mode 100644
index 00000000..1a3ddc57
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto
@@ -0,0 +1,48 @@
+// 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)
+//
+// This is like unittest_import.proto but with optimize_for = NANO_RUNTIME.
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano.testimport";
+option java_outer_classname = "UnittestImportNano";
+
+message ImportMessageNano {
+ optional int32 d = 1;
+}
+
+enum ImportEnumNano {
+ IMPORT_NANO_FOO = 7;
+ IMPORT_NANO_BAR = 8;
+ IMPORT_NANO_BAZ = 9;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto
new file mode 100644
index 00000000..9db2d3e3
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto
@@ -0,0 +1,41 @@
+// 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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "MultipleNameClashNano";
+option java_multiple_files = true;
+
+message MultipleNameClashNano {
+ optional int32 field = 1;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto
new file mode 100644
index 00000000..9dbf0de4
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.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.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest_import;
+
+import "google/protobuf/nano/unittest_import_nano.proto";
+
+option java_package = "com.google.protobuf.nano";
+option java_multiple_files = true;
+
+enum FileScopeEnum {
+ ONE = 1;
+ TWO = 2;
+}
+
+message FileScopeEnumRefNano {
+ optional FileScopeEnum enum_field = 1;
+}
+
+message MessageScopeEnumRefNano {
+ enum MessageScopeEnum {
+ ONE = 1;
+ TWO = 2;
+ }
+ optional MessageScopeEnum enum_field = 1;
+}
+
+message MultipleImportingNonMultipleNano1 {
+ optional ImportMessageNano field = 1;
+}
+
+message MultipleImportingNonMultipleNano2 {
+ optional MultipleImportingNonMultipleNano1 nano1 = 1;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
new file mode 100644
index 00000000..efaf5269
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
@@ -0,0 +1,195 @@
+// 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: wink@google.com (Wink Saville)
+
+package protobuf_unittest;
+
+import "google/protobuf/nano/unittest_import_nano.proto";
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoOuterClass";
+
+// Same as TestAllTypes but with the nano runtime.
+message TestAllTypesNano {
+
+ message NestedMessage {
+ optional int32 bb = 1;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+
+ // 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 ForeignMessageNano optional_foreign_message = 19;
+ optional protobuf_unittest_import.ImportMessageNano
+ optional_import_message = 20;
+
+ optional NestedEnum optional_nested_enum = 21;
+ optional ForeignEnumNano optional_foreign_enum = 22;
+ optional protobuf_unittest_import.ImportEnumNano optional_import_enum = 23;
+
+ optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+ optional string optional_cord = 25 [ctype=CORD];
+
+ // 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 ForeignMessageNano repeated_foreign_message = 49;
+ repeated protobuf_unittest_import.ImportMessageNano
+ repeated_import_message = 50;
+
+ repeated NestedEnum repeated_nested_enum = 51;
+ repeated ForeignEnumNano repeated_foreign_enum = 52;
+ repeated protobuf_unittest_import.ImportEnumNano repeated_import_enum = 53;
+
+ repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+ repeated string repeated_cord = 55 [ctype=CORD];
+
+ // Repeated packed
+ repeated int32 repeated_packed_int32 = 87 [packed=true];
+ repeated sfixed64 repeated_packed_sfixed64 = 88 [packed=true];
+
+ repeated NestedEnum repeated_packed_nested_enum = 89 [packed=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 string default_string_nonascii = 76 [default = "dünya"];
+ optional bytes default_bytes_nonascii = 77 [default = "dünyab"];
+
+ optional float default_float_inf = 97 [default = inf];
+ optional float default_float_neg_inf = 98 [default = -inf];
+ optional float default_float_nan = 99 [default = nan];
+ optional double default_double_inf = 100 [default = inf];
+ optional double default_double_neg_inf = 101 [default = -inf];
+ optional double default_double_nan = 102 [default = nan];
+
+ optional NestedEnum default_nested_enum = 81 [default = BAR];
+ optional ForeignEnumNano default_foreign_enum = 82
+ [default = FOREIGN_NANO_BAR];
+ optional protobuf_unittest_import.ImportEnumNano
+ default_import_enum = 83 [default = IMPORT_NANO_BAR];
+
+ optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+ optional string default_cord = 85 [ctype=CORD,default="123"];
+
+ required int32 id = 86;
+
+ // Try to cause conflicts.
+ optional int32 tag = 93;
+ optional int32 get_serialized_size = 94;
+ optional int32 write_to = 95;
+
+ // Try to fail with java reserved keywords
+ optional int32 synchronized = 96;
+
+ oneof oneof_field {
+ uint32 oneof_uint32 = 111;
+ NestedMessage oneof_nested_message = 112;
+ string oneof_string = 123;
+ bytes oneof_bytes = 124;
+ fixed64 oneof_fixed64 = 115;
+ NestedEnum oneof_enum = 116;
+ }
+}
+
+message ForeignMessageNano {
+ optional int32 c = 1;
+}
+
+enum ForeignEnumNano {
+ FOREIGN_NANO_FOO = 4;
+ FOREIGN_NANO_BAR = 5;
+ FOREIGN_NANO_BAZ = 6;
+}
+
+// Test that deprecated fields work. We only verify that they compile (at one
+// point this failed).
+message TestDeprecatedNano {
+ optional int32 deprecated_field = 1 [deprecated = true];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto
new file mode 100644
index 00000000..69d05834
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto
@@ -0,0 +1,49 @@
+// 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: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano";
+// Explicit outer classname to suppress legacy info.
+option java_outer_classname = "UnittestRecursiveNano";
+
+message RecursiveMessageNano {
+ message NestedMessage {
+ optional RecursiveMessageNano a = 1;
+ }
+
+ required int32 id = 1;
+ optional NestedMessage nested_message = 2;
+ optional RecursiveMessageNano optional_recursive_message_nano = 3;
+ repeated RecursiveMessageNano repeated_recursive_message_nano = 4;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto
new file mode 100644
index 00000000..2b246150
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto
@@ -0,0 +1,116 @@
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoReferenceTypes";
+
+message TestAllTypesNano {
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+
+ message NestedMessage {
+ optional int32 foo = 1;
+ }
+
+ // 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 NestedEnum optional_nested_enum = 21;
+
+ optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+ optional string optional_cord = 25 [ctype=CORD];
+
+ // 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 NestedEnum repeated_nested_enum = 51;
+
+ repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+ repeated string repeated_cord = 55 [ctype=CORD];
+
+ // Repeated packed
+ repeated int32 repeated_packed_int32 = 87 [packed=true];
+ repeated sfixed64 repeated_packed_sfixed64 = 88 [packed=true];
+
+ repeated NestedEnum repeated_packed_nested_enum = 89 [packed=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 float default_float_inf = 97 [default = inf];
+ optional float default_float_neg_inf = 98 [default = -inf];
+ optional float default_float_nan = 99 [default = nan];
+ optional double default_double_inf = 100 [default = inf];
+ optional double default_double_neg_inf = 101 [default = -inf];
+ optional double default_double_nan = 102 [default = nan];
+
+}
+
+message ForeignMessageNano {
+ optional int32 c = 1;
+}
+
+enum ForeignEnumNano {
+ FOREIGN_NANO_FOO = 4;
+ FOREIGN_NANO_BAR = 5;
+ FOREIGN_NANO_BAZ = 6;
+}
+
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto
new file mode 100644
index 00000000..9bfc3ad1
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto
@@ -0,0 +1,47 @@
+// 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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+import "google/protobuf/nano/unittest_nano.proto";
+
+option java_package = "com.google.protobuf.nano";
+option java_multiple_files = true;
+
+// A container message for testing the merging of repeated fields at a
+// nested level. Other tests will be done using the repeated fields in
+// TestAllTypesNano.
+message TestRepeatedMergeNano {
+
+ optional TestAllTypesNano contained = 1;
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto
new file mode 100644
index 00000000..a7ca7527
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto
@@ -0,0 +1,95 @@
+// 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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoRepeatedPackables";
+
+enum Enum {
+ OPTION_ONE = 1;
+ OPTION_TWO = 2;
+}
+
+// Two almost identical messages with all packable repeated field types.
+// One with none marked as packed and the other all packed. For
+// compatibility, they should be able to parse each other's serialized
+// forms.
+
+message NonPacked {
+
+ // All packable types, none marked as packed.
+
+ repeated int32 int32s = 1;
+ repeated int64 int64s = 2;
+ repeated uint32 uint32s = 3;
+ repeated uint64 uint64s = 4;
+ repeated sint32 sint32s = 5;
+ repeated sint64 sint64s = 6;
+ repeated fixed32 fixed32s = 7;
+ repeated fixed64 fixed64s = 8;
+ repeated sfixed32 sfixed32s = 9;
+ repeated sfixed64 sfixed64s = 10;
+ repeated float floats = 11;
+ repeated double doubles = 12;
+ repeated bool bools = 13;
+ repeated Enum enums = 14;
+
+ // Noise for testing merged deserialization.
+ optional int32 noise = 15;
+
+}
+
+message Packed {
+
+ // All packable types, all matching the field numbers in NonPacked,
+ // all marked as packed.
+
+ repeated int32 int32s = 1 [ packed = true ];
+ repeated int64 int64s = 2 [ packed = true ];
+ repeated uint32 uint32s = 3 [ packed = true ];
+ repeated uint64 uint64s = 4 [ packed = true ];
+ repeated sint32 sint32s = 5 [ packed = true ];
+ repeated sint64 sint64s = 6 [ packed = true ];
+ repeated fixed32 fixed32s = 7 [ packed = true ];
+ repeated fixed64 fixed64s = 8 [ packed = true ];
+ repeated sfixed32 sfixed32s = 9 [ packed = true ];
+ repeated sfixed64 sfixed64s = 10 [ packed = true ];
+ repeated float floats = 11 [ packed = true ];
+ repeated double doubles = 12 [ packed = true ];
+ repeated bool bools = 13 [ packed = true ];
+ repeated Enum enums = 14 [ packed = true ];
+
+ // Noise for testing merged deserialization.
+ optional int32 noise = 15;
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto
new file mode 100644
index 00000000..48333aba
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto
@@ -0,0 +1,54 @@
+// 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: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano";
+// Explicit outer classname to suppress legacy info.
+option java_outer_classname = "UnittestSimpleNano";
+
+message SimpleMessageNano {
+ message NestedMessage {
+ optional int32 bb = 1;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+
+ optional int32 d = 1 [default = 123];
+ optional NestedMessage nested_msg = 2;
+ optional NestedEnum default_nested_enum = 3 [default = BAZ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto
new file mode 100644
index 00000000..025428d8
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto
@@ -0,0 +1,38 @@
+// 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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano";
+
+message SingleMessageNano {
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto
new file mode 100644
index 00000000..21bd8c0c
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto
@@ -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.
+
+// Author: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano";
+// Explicit outer classname to suppress legacy info.
+option java_outer_classname = "UnittestStringutf8Nano";
+
+message StringUtf8 {
+ optional string id = 1;
+ repeated string rs = 2;
+}
diff --git a/m4/acx_check_suncc.m4 b/m4/acx_check_suncc.m4
index 4e8f9610..89185932 100644
--- a/m4/acx_check_suncc.m4
+++ b/m4/acx_check_suncc.m4
@@ -42,6 +42,7 @@ AC_DEFUN([ACX_CHECK_SUNCC],[
AS_IF([test "x$ac_enable_64bit" = "xyes"],[
+ AC_DEFINE([SOLARIS_64BIT_ENABLED], [1], [64bit enabled])
AS_IF([test "x$libdir" = "x\${exec_prefix}/lib"],[
dnl The user hasn't overridden the default libdir, so we'll
dnl the dir suffix to match solaris 32/64-bit policy
diff --git a/post_process_dist.sh b/post_process_dist.sh
index 7b2e599d..3c01ed8f 100755
--- a/post_process_dist.sh
+++ b/post_process_dist.sh
@@ -16,7 +16,7 @@
# 5) Cleans up after itself.
if [ "$1" == "" ]; then
- echo "USAGE: $1 DISTFILE" >&2
+ echo "USAGE: $0 DISTFILE" >&2
exit 1
fi
@@ -27,7 +27,9 @@ fi
set -ex
+LANGUAGES="cpp java javanano python ruby"
BASENAME=`basename $1 .tar.gz`
+VERSION=${BASENAME:9}
# Create a directory called "dist", copy the tarball there and unpack it.
mkdir dist
@@ -44,17 +46,23 @@ cd $BASENAME/vsprojects
./convert2008to2005.sh
cd ..
-# Build the dist again in .tar.gz and .tar.bz2 formats.
-./configure
-make dist-gzip
-make dist-bzip2
+for LANG in $LANGUAGES; do
+ # Build the dist again in .tar.gz
+ ./configure DIST_LANG=$LANG
+ make dist-gzip
+ mv $BASENAME.tar.gz ../protobuf-$LANG-$VERSION.tar.gz
+done
# Convert all text files to use DOS-style line endings, then build a .zip
# distribution.
todos *.txt */*.txt
-make dist-zip
-# Clean up.
-mv $BASENAME.tar.gz $BASENAME.tar.bz2 $BASENAME.zip ..
+for LANG in $LANGUAGES; do
+ # Build the dist again in .zip
+ ./configure DIST_LANG=$LANG
+ make dist-zip
+ mv $BASENAME.zip ../protobuf-$LANG-$VERSION.zip
+done
+
cd ..
rm -rf $BASENAME
diff --git a/protobuf.pc.in b/protobuf.pc.in
index 8a53a431..29f24877 100644
--- a/protobuf.pc.in
+++ b/protobuf.pc.in
@@ -6,7 +6,8 @@ includedir=@includedir@
Name: Protocol Buffers
Description: Google's Data Interchange Format
Version: @VERSION@
-Libs: -L${libdir} -lprotobuf @LIBS@ @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
+Libs: -L${libdir} -lprotobuf @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
+Libs.private: @LIBS@
Cflags: -I${includedir} @PTHREAD_CFLAGS@
# Commented out because it crashes pkg-config *sigh*:
# http://bugs.freedesktop.org/show_bug.cgi?id=13265
diff --git a/python/README.txt b/python/README.md
index 6dc144e9..ee7e7213 100644
--- a/python/README.txt
+++ b/python/README.md
@@ -1,4 +1,8 @@
Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
Copyright 2008 Google Inc.
This directory contains the Python Protocol Buffers runtime library.
@@ -6,7 +10,7 @@ This directory contains the Python Protocol Buffers runtime library.
Normally, this directory comes as part of the protobuf package, available
from:
- http://code.google.com/p/protobuf
+ https://developers.google.com/protocol-buffers/
The complete package includes the C++ source code, which includes the
Protocol Compiler (protoc). If you downloaded this package from PyPI
@@ -26,7 +30,7 @@ join the Protocol Buffers discussion list and let us know!
Installation
============
-1) Make sure you have Python 2.4 or newer. If in doubt, run:
+1) Make sure you have Python 2.6 or newer. If in doubt, run:
$ python -V
@@ -35,7 +39,7 @@ Installation
If you would rather install it manually, you may do so by following
the instructions on this page:
- http://peak.telecommunity.com/DevCenter/EasyInstall#installation-instructions
+ https://packaging.python.org/en/latest/installing.html#setup-for-installing-packages
3) Build the C++ code, or install a binary distribution of protoc. If
you install a binary distribution, make sure that it is the same
@@ -43,9 +47,14 @@ Installation
$ protoc --version
-4) Run the tests:
+4) Build and run the tests:
- $ python setup.py test
+ $ python setup.py build
+ $ python setup.py google_test
+
+ If you want to build/test c++ implementation, run:
+ $ python setup.py build --cpp_implementation
+ $ python setup.py google_test --cpp_implementation
If some tests fail, this library may not work correctly on your
system. Continue at your own risk.
@@ -60,7 +69,11 @@ Installation
5) Install:
- $ python setup.py install
+ $ python setup.py install
+
+ or:
+
+ $ python setup.py install --cpp_implementation
This step may require superuser privileges.
NOTE: To use C++ implementation, you need to install C++ protobuf runtime
@@ -73,13 +86,11 @@ Usage
The complete documentation for Protocol Buffers is available via the
web at:
- http://code.google.com/apis/protocolbuffers/
+ https://developers.google.com/protocol-buffers/
C++ Implementation
==================
-WARNING: This is EXPERIMENTAL and only available for CPython platforms.
-
The C++ implementation for Python messages is built as a Python extension to
improve the overall protobuf Python performance.
@@ -88,7 +99,8 @@ To use the C++ implementation, you need to:
parent directory.
2) Export an environment variable:
- $ export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+ $ export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+ $ export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2
You need to export this variable before running setup.py script to build and
install the extension. You must also set the variable at runtime, otherwise
@@ -97,4 +109,3 @@ change the default so that C++ implementation is used whenever it is available.
It is strongly recommended to run `python setup.py test` after setting the
variable to "cpp", so the tests will be against C++ implemented Python
messages.
-
diff --git a/python/ez_setup.py b/python/ez_setup.py
index a2cf777d..3aec98e4 100755
--- a/python/ez_setup.py
+++ b/python/ez_setup.py
@@ -107,6 +107,7 @@ def use_setuptools(
except ImportError:
return do_download()
try:
+ return do_download()
pkg_resources.require("setuptools>="+version); return
except pkg_resources.VersionConflict, e:
if was_imported:
diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py
index e69de29b..1345bd5f 100755
--- a/python/google/protobuf/__init__.py
+++ b/python/google/protobuf/__init__.py
@@ -0,0 +1,35 @@
+# 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.
+
+# Needs to stay compatible with Python 2.5 due to GAE.
+#
+# Copyright 2007 Google Inc. All Rights Reserved.
+
+__version__ = '3.0.0a3.dev0'
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index cf609bee..f7a58ca0 100755
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -28,30 +28,59 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# Needs to stay compatible with Python 2.5 due to GAE.
+#
+# Copyright 2007 Google Inc. All Rights Reserved.
+
"""Descriptors essentially contain exactly the information found in a .proto
file, in types that make this information accessible in Python.
"""
__author__ = 'robinson@google.com (Will Robinson)'
-
from google.protobuf.internal import api_implementation
+_USE_C_DESCRIPTORS = False
if api_implementation.Type() == 'cpp':
- from google.protobuf.internal import cpp_message
+ # Used by MakeDescriptor in cpp mode
+ import os
+ import uuid
+ from google.protobuf.pyext import _message
+ _USE_C_DESCRIPTORS = getattr(_message, '_USE_C_DESCRIPTORS', False)
class Error(Exception):
"""Base error for this module."""
+class TypeTransformationError(Error):
+ """Error transforming between python proto type and corresponding C++ type."""
+
+
+if _USE_C_DESCRIPTORS:
+ # This metaclass allows to override the behavior of code like
+ # isinstance(my_descriptor, FieldDescriptor)
+ # and make it return True when the descriptor is an instance of the extension
+ # type written in C++.
+ class DescriptorMetaclass(type):
+ def __instancecheck__(cls, obj):
+ if super(DescriptorMetaclass, cls).__instancecheck__(obj):
+ return True
+ if isinstance(obj, cls._C_DESCRIPTOR_CLASS):
+ return True
+ return False
+else:
+ # The standard metaclass; nothing changes.
+ DescriptorMetaclass = type
+
+
class DescriptorBase(object):
"""Descriptors base class.
This class is the base of all descriptor classes. It provides common options
- related functionaility.
+ related functionality.
Attributes:
has_options: True if the descriptor has non-default options. Usually it
@@ -61,6 +90,12 @@ class DescriptorBase(object):
avoid some bootstrapping issues.
"""
+ __metaclass__ = DescriptorMetaclass
+ if _USE_C_DESCRIPTORS:
+ # The class, or tuple of classes, that are considered as "virtual
+ # subclasses" of this descriptor class.
+ _C_DESCRIPTOR_CLASS = ()
+
def __init__(self, options, options_class_name):
"""Initialize the descriptor given its options message and the name of the
class of the options message. The name of the class is required in case
@@ -72,6 +107,18 @@ class DescriptorBase(object):
# Does this descriptor have non-default options?
self.has_options = options is not None
+ def _SetOptions(self, options, options_class_name):
+ """Sets the descriptor's options
+
+ This function is used in generated proto2 files to update descriptor
+ options. It must not be used outside proto2.
+ """
+ self._options = options
+ self._options_class_name = options_class_name
+
+ # Does this descriptor have non-default options?
+ self.has_options = options is not None
+
def GetOptions(self):
"""Retrieves descriptor options.
@@ -201,13 +248,33 @@ class Descriptor(_NestedDescriptorBase):
options: (descriptor_pb2.MessageOptions) Protocol message options or None
to use default message options.
+ oneofs: (list of OneofDescriptor) The list of descriptors for oneof fields
+ in this message.
+ oneofs_by_name: (dict str -> OneofDescriptor) Same objects as in |oneofs|,
+ but indexed by "name" attribute.
+
file: (FileDescriptor) Reference to file descriptor.
"""
+ if _USE_C_DESCRIPTORS:
+ _C_DESCRIPTOR_CLASS = _message.Descriptor
+
+ def __new__(cls, name, full_name, filename, containing_type, fields,
+ nested_types, enum_types, extensions, options=None,
+ is_extendable=True, extension_ranges=None, oneofs=None,
+ file=None, serialized_start=None, serialized_end=None,
+ syntax=None):
+ _message.Message._CheckCalledFromGeneratedFile()
+ return _message.Message._GetMessageDescriptor(full_name)
+
+ # NOTE(tmarek): The file argument redefining a builtin is nothing we can
+ # fix right now since we don't know how many clients already rely on the
+ # name of the argument.
def __init__(self, name, full_name, filename, containing_type, fields,
nested_types, enum_types, extensions, options=None,
- is_extendable=True, extension_ranges=None, file=None,
- serialized_start=None, serialized_end=None):
+ is_extendable=True, extension_ranges=None, oneofs=None,
+ file=None, serialized_start=None, serialized_end=None,
+ syntax=None): # pylint:disable=redefined-builtin
"""Arguments to __init__() are as described in the description
of Descriptor fields above.
@@ -217,7 +284,7 @@ class Descriptor(_NestedDescriptorBase):
super(Descriptor, self).__init__(
options, 'MessageOptions', name, full_name, file,
containing_type, serialized_start=serialized_start,
- serialized_end=serialized_start)
+ serialized_end=serialized_end)
# We have fields in addition to fields_by_name and fields_by_number,
# so that:
@@ -231,6 +298,8 @@ class Descriptor(_NestedDescriptorBase):
self.fields_by_name = dict((f.name, f) for f in fields)
self.nested_types = nested_types
+ for nested_type in nested_types:
+ nested_type.containing_type = self
self.nested_types_by_name = dict((t.name, t) for t in nested_types)
self.enum_types = enum_types
@@ -246,9 +315,29 @@ class Descriptor(_NestedDescriptorBase):
self.extensions_by_name = dict((f.name, f) for f in extensions)
self.is_extendable = is_extendable
self.extension_ranges = extension_ranges
+ self.oneofs = oneofs if oneofs is not None else []
+ self.oneofs_by_name = dict((o.name, o) for o in self.oneofs)
+ for oneof in self.oneofs:
+ oneof.containing_type = self
+ self.syntax = syntax or "proto2"
- self._serialized_start = serialized_start
- self._serialized_end = serialized_end
+ def EnumValueName(self, enum, value):
+ """Returns the string name of an enum value.
+
+ This is just a small helper method to simplify a common operation.
+
+ Args:
+ enum: string name of the Enum.
+ value: int, value of the enum.
+
+ Returns:
+ string name of the enum value.
+
+ Raises:
+ KeyError if either the Enum doesn't exist or the value is not a valid
+ value for the enum.
+ """
+ return self.enum_types_by_name[enum].values_by_number[value].name
def CopyToProto(self, proto):
"""Copies this to a descriptor_pb2.DescriptorProto.
@@ -275,7 +364,7 @@ class FieldDescriptor(DescriptorBase):
"""Descriptor for a single field in a .proto file.
- A FieldDescriptor instance has the following attriubtes:
+ A FieldDescriptor instance has the following attributes:
name: (str) Name of this field, exactly as it appears in .proto.
full_name: (str) Name of this field, including containing scope. This is
@@ -316,6 +405,9 @@ class FieldDescriptor(DescriptorBase):
options: (descriptor_pb2.FieldOptions) Protocol message field options or
None to use default field options.
+
+ containing_oneof: (OneofDescriptor) If the field is a member of a oneof
+ union, contains its descriptor. Otherwise, None.
"""
# Must be consistent with C++ FieldDescriptor::Type enum in
@@ -358,6 +450,27 @@ class FieldDescriptor(DescriptorBase):
CPPTYPE_MESSAGE = 10
MAX_CPPTYPE = 10
+ _PYTHON_TO_CPP_PROTO_TYPE_MAP = {
+ TYPE_DOUBLE: CPPTYPE_DOUBLE,
+ TYPE_FLOAT: CPPTYPE_FLOAT,
+ TYPE_ENUM: CPPTYPE_ENUM,
+ TYPE_INT64: CPPTYPE_INT64,
+ TYPE_SINT64: CPPTYPE_INT64,
+ TYPE_SFIXED64: CPPTYPE_INT64,
+ TYPE_UINT64: CPPTYPE_UINT64,
+ TYPE_FIXED64: CPPTYPE_UINT64,
+ TYPE_INT32: CPPTYPE_INT32,
+ TYPE_SFIXED32: CPPTYPE_INT32,
+ TYPE_SINT32: CPPTYPE_INT32,
+ TYPE_UINT32: CPPTYPE_UINT32,
+ TYPE_FIXED32: CPPTYPE_UINT32,
+ TYPE_BYTES: CPPTYPE_STRING,
+ TYPE_STRING: CPPTYPE_STRING,
+ TYPE_BOOL: CPPTYPE_BOOL,
+ TYPE_MESSAGE: CPPTYPE_MESSAGE,
+ TYPE_GROUP: CPPTYPE_MESSAGE
+ }
+
# Must be consistent with C++ FieldDescriptor::Label enum in
# descriptor.h.
#
@@ -367,10 +480,29 @@ class FieldDescriptor(DescriptorBase):
LABEL_REPEATED = 3
MAX_LABEL = 3
+ # Must be consistent with C++ constants kMaxNumber, kFirstReservedNumber,
+ # and kLastReservedNumber in descriptor.h
+ MAX_FIELD_NUMBER = (1 << 29) - 1
+ FIRST_RESERVED_FIELD_NUMBER = 19000
+ LAST_RESERVED_FIELD_NUMBER = 19999
+
+ if _USE_C_DESCRIPTORS:
+ _C_DESCRIPTOR_CLASS = _message.FieldDescriptor
+
+ def __new__(cls, name, full_name, index, number, type, cpp_type, label,
+ default_value, message_type, enum_type, containing_type,
+ is_extension, extension_scope, options=None,
+ has_default_value=True, containing_oneof=None):
+ _message.Message._CheckCalledFromGeneratedFile()
+ if is_extension:
+ return _message.Message._GetExtensionDescriptor(full_name)
+ else:
+ return _message.Message._GetFieldDescriptor(full_name)
+
def __init__(self, name, full_name, index, number, type, cpp_type, label,
default_value, message_type, enum_type, containing_type,
is_extension, extension_scope, options=None,
- has_default_value=True):
+ has_default_value=True, containing_oneof=None):
"""The arguments are as described in the description of FieldDescriptor
attributes above.
@@ -393,14 +525,40 @@ class FieldDescriptor(DescriptorBase):
self.enum_type = enum_type
self.is_extension = is_extension
self.extension_scope = extension_scope
+ self.containing_oneof = containing_oneof
if api_implementation.Type() == 'cpp':
if is_extension:
- self._cdescriptor = cpp_message.GetExtensionDescriptor(full_name)
+ # pylint: disable=protected-access
+ self._cdescriptor = (
+ _message.Message._GetExtensionDescriptor(full_name))
+ # pylint: enable=protected-access
else:
- self._cdescriptor = cpp_message.GetFieldDescriptor(full_name)
+ # pylint: disable=protected-access
+ self._cdescriptor = _message.Message._GetFieldDescriptor(full_name)
+ # pylint: enable=protected-access
else:
self._cdescriptor = None
+ @staticmethod
+ def ProtoTypeToCppProtoType(proto_type):
+ """Converts from a Python proto type to a C++ Proto Type.
+
+ The Python ProtocolBuffer classes specify both the 'Python' datatype and the
+ 'C++' datatype - and they're not the same. This helper method should
+ translate from one to another.
+
+ Args:
+ proto_type: the Python proto type (descriptor.FieldDescriptor.TYPE_*)
+ Returns:
+ descriptor.FieldDescriptor.CPPTYPE_*, the C++ type.
+ Raises:
+ TypeTransformationError: when the Python proto type isn't known.
+ """
+ try:
+ return FieldDescriptor._PYTHON_TO_CPP_PROTO_TYPE_MAP[proto_type]
+ except KeyError:
+ raise TypeTransformationError('Unknown proto_type: %s' % proto_type)
+
class EnumDescriptor(_NestedDescriptorBase):
@@ -427,6 +585,15 @@ class EnumDescriptor(_NestedDescriptorBase):
None to use default enum options.
"""
+ if _USE_C_DESCRIPTORS:
+ _C_DESCRIPTOR_CLASS = _message.EnumDescriptor
+
+ def __new__(cls, name, full_name, filename, values,
+ containing_type=None, options=None, file=None,
+ serialized_start=None, serialized_end=None):
+ _message.Message._CheckCalledFromGeneratedFile()
+ return _message.Message._GetEnumDescriptor(full_name)
+
def __init__(self, name, full_name, filename, values,
containing_type=None, options=None, file=None,
serialized_start=None, serialized_end=None):
@@ -438,7 +605,7 @@ class EnumDescriptor(_NestedDescriptorBase):
super(EnumDescriptor, self).__init__(
options, 'EnumOptions', name, full_name, file,
containing_type, serialized_start=serialized_start,
- serialized_end=serialized_start)
+ serialized_end=serialized_end)
self.values = values
for value in self.values:
@@ -446,9 +613,6 @@ class EnumDescriptor(_NestedDescriptorBase):
self.values_by_name = dict((v.name, v) for v in values)
self.values_by_number = dict((v.number, v) for v in values)
- self._serialized_start = serialized_start
- self._serialized_end = serialized_end
-
def CopyToProto(self, proto):
"""Copies this to a descriptor_pb2.EnumDescriptorProto.
@@ -474,6 +638,17 @@ class EnumValueDescriptor(DescriptorBase):
None to use default enum value options options.
"""
+ if _USE_C_DESCRIPTORS:
+ _C_DESCRIPTOR_CLASS = _message.EnumValueDescriptor
+
+ def __new__(cls, name, index, number, type=None, options=None):
+ _message.Message._CheckCalledFromGeneratedFile()
+ # There is no way we can build a complete EnumValueDescriptor with the
+ # given parameters (the name of the Enum is not known, for example).
+ # Fortunately generated files just pass it to the EnumDescriptor()
+ # constructor, which will ignore it, so returning None is good enough.
+ return None
+
def __init__(self, name, index, number, type=None, options=None):
"""Arguments are as described in the attribute description above."""
super(EnumValueDescriptor, self).__init__(options, 'EnumValueOptions')
@@ -483,6 +658,36 @@ class EnumValueDescriptor(DescriptorBase):
self.type = type
+class OneofDescriptor(object):
+ """Descriptor for a oneof field.
+
+ name: (str) Name of the oneof field.
+ full_name: (str) Full name of the oneof field, including package name.
+ index: (int) 0-based index giving the order of the oneof field inside
+ its containing type.
+ containing_type: (Descriptor) Descriptor of the protocol message
+ type that contains this field. Set by the Descriptor constructor
+ if we're passed into one.
+ fields: (list of FieldDescriptor) The list of field descriptors this
+ oneof can contain.
+ """
+
+ if _USE_C_DESCRIPTORS:
+ _C_DESCRIPTOR_CLASS = _message.OneofDescriptor
+
+ def __new__(cls, name, full_name, index, containing_type, fields):
+ _message.Message._CheckCalledFromGeneratedFile()
+ return _message.Message._GetOneofDescriptor(full_name)
+
+ def __init__(self, name, full_name, index, containing_type, fields):
+ """Arguments are as described in the attribute description above."""
+ self.name = name
+ self.full_name = full_name
+ self.index = index
+ self.containing_type = containing_type
+ self.fields = fields
+
+
class ServiceDescriptor(_NestedDescriptorBase):
"""Descriptor for a service.
@@ -561,23 +766,57 @@ class MethodDescriptor(DescriptorBase):
class FileDescriptor(DescriptorBase):
"""Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto.
+ Note that enum_types_by_name, extensions_by_name, and dependencies
+ fields are only set by the message_factory module, and not by the
+ generated proto code.
+
name: name of file, relative to root of source tree.
package: name of the package
+ syntax: string indicating syntax of the file (can be "proto2" or "proto3")
serialized_pb: (str) Byte string of serialized
descriptor_pb2.FileDescriptorProto.
+ dependencies: List of other FileDescriptors this FileDescriptor depends on.
+ message_types_by_name: Dict of message names of their descriptors.
+ enum_types_by_name: Dict of enum names and their descriptors.
+ extensions_by_name: Dict of extension names and their descriptors.
"""
- def __init__(self, name, package, options=None, serialized_pb=None):
+ if _USE_C_DESCRIPTORS:
+ _C_DESCRIPTOR_CLASS = _message.FileDescriptor
+
+ def __new__(cls, name, package, options=None, serialized_pb=None,
+ dependencies=None, syntax=None):
+ # FileDescriptor() is called from various places, not only from generated
+ # files, to register dynamic proto files and messages.
+ # TODO(amauryfa): Expose BuildFile() as a public function and make this
+ # constructor an implementation detail.
+ if serialized_pb:
+ # pylint: disable=protected-access2
+ return _message.Message._BuildFile(serialized_pb)
+ # pylint: enable=protected-access
+ else:
+ return super(FileDescriptor, cls).__new__(cls)
+
+ def __init__(self, name, package, options=None, serialized_pb=None,
+ dependencies=None, syntax=None):
"""Constructor."""
super(FileDescriptor, self).__init__(options, 'FileOptions')
self.message_types_by_name = {}
self.name = name
self.package = package
+ self.syntax = syntax or "proto2"
self.serialized_pb = serialized_pb
+
+ self.enum_types_by_name = {}
+ self.extensions_by_name = {}
+ self.dependencies = (dependencies or [])
+
if (api_implementation.Type() == 'cpp' and
self.serialized_pb is not None):
- cpp_message.BuildFile(self.serialized_pb)
+ # pylint: disable=protected-access
+ _message.Message._BuildFile(self.serialized_pb)
+ # pylint: enable=protected-access
def CopyToProto(self, proto):
"""Copies this to a descriptor_pb2.FileDescriptorProto.
@@ -596,3 +835,104 @@ def _ParseOptions(message, string):
"""
message.ParseFromString(string)
return message
+
+
+def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
+ syntax=None):
+ """Make a protobuf Descriptor given a DescriptorProto protobuf.
+
+ Handles nested descriptors. Note that this is limited to the scope of defining
+ a message inside of another message. Composite fields can currently only be
+ resolved if the message is defined in the same scope as the field.
+
+ Args:
+ desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
+ package: Optional package name for the new message Descriptor (string).
+ build_file_if_cpp: Update the C++ descriptor pool if api matches.
+ Set to False on recursion, so no duplicates are created.
+ syntax: The syntax/semantics that should be used. Set to "proto3" to get
+ proto3 field presence semantics.
+ Returns:
+ A Descriptor for protobuf messages.
+ """
+ if api_implementation.Type() == 'cpp' and build_file_if_cpp:
+ # The C++ implementation requires all descriptors to be backed by the same
+ # definition in the C++ descriptor pool. To do this, we build a
+ # FileDescriptorProto with the same definition as this descriptor and build
+ # it into the pool.
+ from google.protobuf import descriptor_pb2
+ file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
+ file_descriptor_proto.message_type.add().MergeFrom(desc_proto)
+
+ # Generate a random name for this proto file to prevent conflicts with
+ # any imported ones. We need to specify a file name so BuildFile accepts
+ # our FileDescriptorProto, but it is not important what that file name
+ # is actually set to.
+ proto_name = str(uuid.uuid4())
+
+ if package:
+ file_descriptor_proto.name = os.path.join(package.replace('.', '/'),
+ proto_name + '.proto')
+ file_descriptor_proto.package = package
+ else:
+ file_descriptor_proto.name = proto_name + '.proto'
+
+ # pylint: disable=protected-access
+ result = _message.Message._BuildFile(
+ file_descriptor_proto.SerializeToString())
+ # pylint: enable=protected-access
+
+ if _USE_C_DESCRIPTORS:
+ return result.message_types_by_name[desc_proto.name]
+
+ full_message_name = [desc_proto.name]
+ if package: full_message_name.insert(0, package)
+
+ # Create Descriptors for enum types
+ enum_types = {}
+ for enum_proto in desc_proto.enum_type:
+ full_name = '.'.join(full_message_name + [enum_proto.name])
+ enum_desc = EnumDescriptor(
+ enum_proto.name, full_name, None, [
+ EnumValueDescriptor(enum_val.name, ii, enum_val.number)
+ for ii, enum_val in enumerate(enum_proto.value)])
+ enum_types[full_name] = enum_desc
+
+ # Create Descriptors for nested types
+ nested_types = {}
+ for nested_proto in desc_proto.nested_type:
+ full_name = '.'.join(full_message_name + [nested_proto.name])
+ # Nested types are just those defined inside of the message, not all types
+ # used by fields in the message, so no loops are possible here.
+ nested_desc = MakeDescriptor(nested_proto,
+ package='.'.join(full_message_name),
+ build_file_if_cpp=False,
+ syntax=syntax)
+ nested_types[full_name] = nested_desc
+
+ fields = []
+ for field_proto in desc_proto.field:
+ full_name = '.'.join(full_message_name + [field_proto.name])
+ enum_desc = None
+ nested_desc = None
+ if field_proto.HasField('type_name'):
+ type_name = field_proto.type_name
+ full_type_name = '.'.join(full_message_name +
+ [type_name[type_name.rfind('.')+1:]])
+ if full_type_name in nested_types:
+ nested_desc = nested_types[full_type_name]
+ elif full_type_name in enum_types:
+ enum_desc = enum_types[full_type_name]
+ # Else type_name references a non-local type, which isn't implemented
+ field = FieldDescriptor(
+ field_proto.name, full_name, field_proto.number - 1,
+ field_proto.number, field_proto.type,
+ FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type),
+ field_proto.label, None, nested_desc, enum_desc, None, False, None,
+ 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(), [],
+ options=desc_proto.options)
diff --git a/python/google/protobuf/descriptor_database.py b/python/google/protobuf/descriptor_database.py
new file mode 100644
index 00000000..b10021e9
--- /dev/null
+++ b/python/google/protobuf/descriptor_database.py
@@ -0,0 +1,137 @@
+# 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.
+
+"""Provides a container for DescriptorProtos."""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+
+class Error(Exception):
+ pass
+
+
+class DescriptorDatabaseConflictingDefinitionError(Error):
+ """Raised when a proto is added with the same name & different descriptor."""
+
+
+class DescriptorDatabase(object):
+ """A container accepting FileDescriptorProtos and maps DescriptorProtos."""
+
+ def __init__(self):
+ self._file_desc_protos_by_file = {}
+ self._file_desc_protos_by_symbol = {}
+
+ def Add(self, file_desc_proto):
+ """Adds the FileDescriptorProto and its types to this database.
+
+ Args:
+ file_desc_proto: The FileDescriptorProto to add.
+ Raises:
+ DescriptorDatabaseException: if an attempt is made to add a proto
+ with the same name but different definition than an exisiting
+ proto in the database.
+ """
+ proto_name = file_desc_proto.name
+ if proto_name not in self._file_desc_protos_by_file:
+ self._file_desc_protos_by_file[proto_name] = file_desc_proto
+ elif self._file_desc_protos_by_file[proto_name] != file_desc_proto:
+ raise DescriptorDatabaseConflictingDefinitionError(
+ '%s already added, but with different descriptor.' % proto_name)
+
+ package = file_desc_proto.package
+ for message in file_desc_proto.message_type:
+ self._file_desc_protos_by_symbol.update(
+ (name, file_desc_proto) for name in _ExtractSymbols(message, package))
+ for enum in file_desc_proto.enum_type:
+ self._file_desc_protos_by_symbol[
+ '.'.join((package, enum.name))] = file_desc_proto
+
+ def FindFileByName(self, name):
+ """Finds the file descriptor proto by file name.
+
+ Typically the file name is a relative path ending to a .proto file. The
+ proto with the given name will have to have been added to this database
+ using the Add method or else an error will be raised.
+
+ Args:
+ name: The file name to find.
+
+ Returns:
+ The file descriptor proto matching the name.
+
+ Raises:
+ KeyError if no file by the given name was added.
+ """
+
+ return self._file_desc_protos_by_file[name]
+
+ def FindFileContainingSymbol(self, symbol):
+ """Finds the file descriptor proto containing the specified symbol.
+
+ The symbol should be a fully qualified name including the file descriptor's
+ package and any containing messages. Some examples:
+
+ 'some.package.name.Message'
+ 'some.package.name.Message.NestedEnum'
+
+ The file descriptor proto containing the specified symbol must be added to
+ this database using the Add method or else an error will be raised.
+
+ Args:
+ symbol: The fully qualified symbol name.
+
+ Returns:
+ The file descriptor proto containing the symbol.
+
+ Raises:
+ KeyError if no file contains the specified symbol.
+ """
+
+ return self._file_desc_protos_by_symbol[symbol]
+
+
+def _ExtractSymbols(desc_proto, package):
+ """Pulls out all the symbols from a descriptor proto.
+
+ Args:
+ desc_proto: The proto to extract symbols from.
+ package: The package containing the descriptor type.
+
+ Yields:
+ The fully qualified name found in the descriptor.
+ """
+
+ message_name = '.'.join((package, desc_proto.name))
+ yield message_name
+ 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))
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
new file mode 100644
index 00000000..7e7701f8
--- /dev/null
+++ b/python/google/protobuf/descriptor_pool.py
@@ -0,0 +1,671 @@
+# 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.
+
+"""Provides DescriptorPool to use as a container for proto2 descriptors.
+
+The DescriptorPool is used in conjection with a DescriptorDatabase to maintain
+a collection of protocol buffer descriptors for use when dynamically creating
+message types at runtime.
+
+For most applications protocol buffers should be used via modules generated by
+the protocol buffer compiler tool. This should only be used when the type of
+protocol buffers used in an application or library cannot be predetermined.
+
+Below is a straightforward example on how to use this class:
+
+ pool = DescriptorPool()
+ file_descriptor_protos = [ ... ]
+ for file_descriptor_proto in file_descriptor_protos:
+ pool.Add(file_descriptor_proto)
+ my_message_descriptor = pool.FindMessageTypeByName('some.package.MessageType')
+
+The message descriptor can be used in conjunction with the message_factory
+module in order to create a protocol buffer class that can be encoded and
+decoded.
+
+If you want to get a Python class for the specified proto, use the
+helper functions inside google.protobuf.message_factory
+directly instead of this class.
+"""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+import sys
+
+from google.protobuf import descriptor
+from google.protobuf import descriptor_database
+from google.protobuf import text_encoding
+
+
+_USE_C_DESCRIPTORS = descriptor._USE_C_DESCRIPTORS
+
+
+def _NormalizeFullyQualifiedName(name):
+ """Remove leading period from fully-qualified type name.
+
+ Due to b/13860351 in descriptor_database.py, types in the root namespace are
+ generated with a leading period. This function removes that prefix.
+
+ Args:
+ name: A str, the fully-qualified symbol name.
+
+ Returns:
+ A str, the normalized fully-qualified symbol name.
+ """
+ return name.lstrip('.')
+
+
+class DescriptorPool(object):
+ """A collection of protobufs dynamically constructed by descriptor protos."""
+
+ def __init__(self, descriptor_db=None):
+ """Initializes a Pool of proto buffs.
+
+ The descriptor_db argument to the constructor is provided to allow
+ specialized file descriptor proto lookup code to be triggered on demand. An
+ example would be an implementation which will read and compile a file
+ specified in a call to FindFileByName() and not require the call to Add()
+ at all. Results from this database will be cached internally here as well.
+
+ Args:
+ descriptor_db: A secondary source of file descriptors.
+ """
+
+ self._internal_db = descriptor_database.DescriptorDatabase()
+ self._descriptor_db = descriptor_db
+ self._descriptors = {}
+ self._enum_descriptors = {}
+ self._file_descriptors = {}
+
+ def Add(self, file_desc_proto):
+ """Adds the FileDescriptorProto and its types to this pool.
+
+ Args:
+ file_desc_proto: The FileDescriptorProto to add.
+ """
+
+ self._internal_db.Add(file_desc_proto)
+
+ def AddDescriptor(self, desc):
+ """Adds a Descriptor to the pool, non-recursively.
+
+ If the Descriptor contains nested messages or enums, the caller must
+ explicitly register them. This method also registers the FileDescriptor
+ associated with the message.
+
+ Args:
+ desc: A Descriptor.
+ """
+ if not isinstance(desc, descriptor.Descriptor):
+ raise TypeError('Expected instance of descriptor.Descriptor.')
+
+ self._descriptors[desc.full_name] = desc
+ self.AddFileDescriptor(desc.file)
+
+ def AddEnumDescriptor(self, enum_desc):
+ """Adds an EnumDescriptor to the pool.
+
+ This method also registers the FileDescriptor associated with the message.
+
+ Args:
+ enum_desc: An EnumDescriptor.
+ """
+
+ if not isinstance(enum_desc, descriptor.EnumDescriptor):
+ raise TypeError('Expected instance of descriptor.EnumDescriptor.')
+
+ self._enum_descriptors[enum_desc.full_name] = enum_desc
+ self.AddFileDescriptor(enum_desc.file)
+
+ def AddFileDescriptor(self, file_desc):
+ """Adds a FileDescriptor to the pool, non-recursively.
+
+ If the FileDescriptor contains messages or enums, the caller must explicitly
+ register them.
+
+ Args:
+ file_desc: A FileDescriptor.
+ """
+
+ if not isinstance(file_desc, descriptor.FileDescriptor):
+ raise TypeError('Expected instance of descriptor.FileDescriptor.')
+ self._file_descriptors[file_desc.name] = file_desc
+
+ def FindFileByName(self, file_name):
+ """Gets a FileDescriptor by file name.
+
+ Args:
+ file_name: The path to the file to get a descriptor for.
+
+ Returns:
+ A FileDescriptor for the named file.
+
+ Raises:
+ KeyError: if the file can not be found in the pool.
+ """
+
+ try:
+ return self._file_descriptors[file_name]
+ except KeyError:
+ pass
+
+ try:
+ file_proto = self._internal_db.FindFileByName(file_name)
+ except KeyError:
+ _, error, _ = sys.exc_info() #PY25 compatible for GAE.
+ if self._descriptor_db:
+ file_proto = self._descriptor_db.FindFileByName(file_name)
+ else:
+ raise error
+ if not file_proto:
+ raise KeyError('Cannot find a file named %s' % file_name)
+ return self._ConvertFileProtoToFileDescriptor(file_proto)
+
+ def FindFileContainingSymbol(self, symbol):
+ """Gets the FileDescriptor for the file containing the specified symbol.
+
+ Args:
+ symbol: The name of the symbol to search for.
+
+ Returns:
+ A FileDescriptor that contains the specified symbol.
+
+ Raises:
+ KeyError: if the file can not be found in the pool.
+ """
+
+ symbol = _NormalizeFullyQualifiedName(symbol)
+ try:
+ return self._descriptors[symbol].file
+ except KeyError:
+ pass
+
+ try:
+ return self._enum_descriptors[symbol].file
+ except KeyError:
+ pass
+
+ try:
+ file_proto = self._internal_db.FindFileContainingSymbol(symbol)
+ except KeyError:
+ _, error, _ = sys.exc_info() #PY25 compatible for GAE.
+ if self._descriptor_db:
+ file_proto = self._descriptor_db.FindFileContainingSymbol(symbol)
+ else:
+ raise error
+ if not file_proto:
+ raise KeyError('Cannot find a file containing %s' % symbol)
+ return self._ConvertFileProtoToFileDescriptor(file_proto)
+
+ def FindMessageTypeByName(self, full_name):
+ """Loads the named descriptor from the pool.
+
+ Args:
+ full_name: The full name of the descriptor to load.
+
+ Returns:
+ The descriptor for the named type.
+ """
+
+ full_name = _NormalizeFullyQualifiedName(full_name)
+ if full_name not in self._descriptors:
+ self.FindFileContainingSymbol(full_name)
+ return self._descriptors[full_name]
+
+ def FindEnumTypeByName(self, full_name):
+ """Loads the named enum descriptor from the pool.
+
+ Args:
+ full_name: The full name of the enum descriptor to load.
+
+ Returns:
+ The enum descriptor for the named type.
+ """
+
+ full_name = _NormalizeFullyQualifiedName(full_name)
+ if full_name not in self._enum_descriptors:
+ self.FindFileContainingSymbol(full_name)
+ return self._enum_descriptors[full_name]
+
+ def _ConvertFileProtoToFileDescriptor(self, file_proto):
+ """Creates a FileDescriptor from a proto or returns a cached copy.
+
+ This method also has the side effect of loading all the symbols found in
+ the file into the appropriate dictionaries in the pool.
+
+ Args:
+ file_proto: The proto to convert.
+
+ Returns:
+ A FileDescriptor matching the passed in proto.
+ """
+
+ if file_proto.name not in self._file_descriptors:
+ built_deps = list(self._GetDeps(file_proto.dependency))
+ direct_deps = [self.FindFileByName(n) for n in file_proto.dependency]
+
+ file_descriptor = descriptor.FileDescriptor(
+ name=file_proto.name,
+ package=file_proto.package,
+ syntax=file_proto.syntax,
+ options=file_proto.options,
+ serialized_pb=file_proto.SerializeToString(),
+ dependencies=direct_deps)
+ if _USE_C_DESCRIPTORS:
+ # When using C++ descriptors, all objects defined in the file were added
+ # to the C++ database when the FileDescriptor was built above.
+ # Just add them to this descriptor pool.
+ def _AddMessageDescriptor(message_desc):
+ self._descriptors[message_desc.full_name] = message_desc
+ for nested in message_desc.nested_types:
+ _AddMessageDescriptor(nested)
+ for enum_type in message_desc.enum_types:
+ _AddEnumDescriptor(enum_type)
+ def _AddEnumDescriptor(enum_desc):
+ self._enum_descriptors[enum_desc.full_name] = enum_desc
+ for message_type in file_descriptor.message_types_by_name.values():
+ _AddMessageDescriptor(message_type)
+ for enum_type in file_descriptor.enum_types_by_name.values():
+ _AddEnumDescriptor(enum_type)
+ else:
+ scope = {}
+
+ # This loop extracts all the message and enum types from all the
+ # dependencies of the file_proto. This is necessary to create the
+ # scope of available message types when defining the passed in
+ # file proto.
+ for dependency in built_deps:
+ scope.update(self._ExtractSymbols(
+ dependency.message_types_by_name.values()))
+ scope.update((_PrefixWithDot(enum.full_name), enum)
+ for enum in dependency.enum_types_by_name.values())
+
+ for message_type in file_proto.message_type:
+ message_desc = self._ConvertMessageDescriptor(
+ message_type, file_proto.package, file_descriptor, scope,
+ file_proto.syntax)
+ file_descriptor.message_types_by_name[message_desc.name] = (
+ message_desc)
+
+ for enum_type in file_proto.enum_type:
+ file_descriptor.enum_types_by_name[enum_type.name] = (
+ self._ConvertEnumDescriptor(enum_type, file_proto.package,
+ file_descriptor, None, scope))
+
+ for index, extension_proto in enumerate(file_proto.extension):
+ extension_desc = self.MakeFieldDescriptor(
+ extension_proto, file_proto.package, index, is_extension=True)
+ extension_desc.containing_type = self._GetTypeFromScope(
+ file_descriptor.package, extension_proto.extendee, scope)
+ self.SetFieldType(extension_proto, extension_desc,
+ file_descriptor.package, scope)
+ file_descriptor.extensions_by_name[extension_desc.name] = (
+ extension_desc)
+
+ for desc_proto in file_proto.message_type:
+ self.SetAllFieldTypes(file_proto.package, desc_proto, scope)
+
+ if file_proto.package:
+ desc_proto_prefix = _PrefixWithDot(file_proto.package)
+ else:
+ desc_proto_prefix = ''
+
+ for desc_proto in file_proto.message_type:
+ desc = self._GetTypeFromScope(
+ desc_proto_prefix, desc_proto.name, scope)
+ file_descriptor.message_types_by_name[desc_proto.name] = desc
+
+ self.Add(file_proto)
+ self._file_descriptors[file_proto.name] = file_descriptor
+
+ return self._file_descriptors[file_proto.name]
+
+ def _ConvertMessageDescriptor(self, desc_proto, package=None, file_desc=None,
+ scope=None, syntax=None):
+ """Adds the proto to the pool in the specified package.
+
+ Args:
+ desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
+ package: The package the proto should be located in.
+ file_desc: The file containing this message.
+ scope: Dict mapping short and full symbols to message and enum types.
+
+ Returns:
+ The added descriptor.
+ """
+
+ if package:
+ desc_name = '.'.join((package, desc_proto.name))
+ else:
+ desc_name = desc_proto.name
+
+ if file_desc is None:
+ file_name = None
+ else:
+ file_name = file_desc.name
+
+ if scope is None:
+ scope = {}
+
+ nested = [
+ self._ConvertMessageDescriptor(
+ nested, desc_name, file_desc, scope, syntax)
+ for nested in desc_proto.nested_type]
+ enums = [
+ self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope)
+ for enum in desc_proto.enum_type]
+ fields = [self.MakeFieldDescriptor(field, desc_name, index)
+ for index, field in enumerate(desc_proto.field)]
+ extensions = [
+ self.MakeFieldDescriptor(extension, desc_name, index, is_extension=True)
+ for index, extension in enumerate(desc_proto.extension)]
+ oneofs = [
+ descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)),
+ index, None, [])
+ for index, desc in enumerate(desc_proto.oneof_decl)]
+ extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range]
+ if extension_ranges:
+ is_extendable = True
+ else:
+ is_extendable = False
+ desc = descriptor.Descriptor(
+ name=desc_proto.name,
+ full_name=desc_name,
+ filename=file_name,
+ containing_type=None,
+ fields=fields,
+ oneofs=oneofs,
+ nested_types=nested,
+ enum_types=enums,
+ extensions=extensions,
+ options=desc_proto.options,
+ is_extendable=is_extendable,
+ extension_ranges=extension_ranges,
+ file=file_desc,
+ serialized_start=None,
+ serialized_end=None,
+ syntax=syntax)
+ for nested in desc.nested_types:
+ nested.containing_type = desc
+ for enum in desc.enum_types:
+ enum.containing_type = desc
+ for field_index, field_desc in enumerate(desc_proto.field):
+ if field_desc.HasField('oneof_index'):
+ oneof_index = field_desc.oneof_index
+ oneofs[oneof_index].fields.append(fields[field_index])
+ fields[field_index].containing_oneof = oneofs[oneof_index]
+
+ scope[_PrefixWithDot(desc_name)] = desc
+ self._descriptors[desc_name] = desc
+ return desc
+
+ def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None,
+ containing_type=None, scope=None):
+ """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf.
+
+ Args:
+ enum_proto: The descriptor_pb2.EnumDescriptorProto protobuf message.
+ package: Optional package name for the new message EnumDescriptor.
+ file_desc: The file containing the enum descriptor.
+ containing_type: The type containing this enum.
+ scope: Scope containing available types.
+
+ Returns:
+ The added descriptor
+ """
+
+ if package:
+ enum_name = '.'.join((package, enum_proto.name))
+ else:
+ enum_name = enum_proto.name
+
+ if file_desc is None:
+ file_name = None
+ else:
+ file_name = file_desc.name
+
+ values = [self._MakeEnumValueDescriptor(value, index)
+ for index, value in enumerate(enum_proto.value)]
+ desc = descriptor.EnumDescriptor(name=enum_proto.name,
+ full_name=enum_name,
+ filename=file_name,
+ file=file_desc,
+ values=values,
+ containing_type=containing_type,
+ options=enum_proto.options)
+ scope['.%s' % enum_name] = desc
+ self._enum_descriptors[enum_name] = desc
+ return desc
+
+ def MakeFieldDescriptor(self, field_proto, message_name, index,
+ is_extension=False):
+ """Creates a field descriptor from a FieldDescriptorProto.
+
+ For message and enum type fields, this method will do a look up
+ in the pool for the appropriate descriptor for that type. If it
+ is unavailable, it will fall back to the _source function to
+ create it. If this type is still unavailable, construction will
+ fail.
+
+ Args:
+ field_proto: The proto describing the field.
+ message_name: The name of the containing message.
+ index: Index of the field
+ is_extension: Indication that this field is for an extension.
+
+ Returns:
+ An initialized FieldDescriptor object
+ """
+
+ if message_name:
+ full_name = '.'.join((message_name, field_proto.name))
+ else:
+ full_name = field_proto.name
+
+ return descriptor.FieldDescriptor(
+ name=field_proto.name,
+ full_name=full_name,
+ index=index,
+ number=field_proto.number,
+ type=field_proto.type,
+ cpp_type=None,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ label=field_proto.label,
+ has_default_value=False,
+ default_value=None,
+ is_extension=is_extension,
+ extension_scope=None,
+ options=field_proto.options)
+
+ def SetAllFieldTypes(self, package, desc_proto, scope):
+ """Sets all the descriptor's fields's types.
+
+ This method also sets the containing types on any extensions.
+
+ Args:
+ package: The current package of desc_proto.
+ desc_proto: The message descriptor to update.
+ scope: Enclosing scope of available types.
+ """
+
+ package = _PrefixWithDot(package)
+
+ main_desc = self._GetTypeFromScope(package, desc_proto.name, scope)
+
+ if package == '.':
+ nested_package = _PrefixWithDot(desc_proto.name)
+ else:
+ nested_package = '.'.join([package, desc_proto.name])
+
+ for field_proto, field_desc in zip(desc_proto.field, main_desc.fields):
+ self.SetFieldType(field_proto, field_desc, nested_package, scope)
+
+ for extension_proto, extension_desc in (
+ zip(desc_proto.extension, main_desc.extensions)):
+ extension_desc.containing_type = self._GetTypeFromScope(
+ nested_package, extension_proto.extendee, scope)
+ self.SetFieldType(extension_proto, extension_desc, nested_package, scope)
+
+ for nested_type in desc_proto.nested_type:
+ self.SetAllFieldTypes(nested_package, nested_type, scope)
+
+ def SetFieldType(self, field_proto, field_desc, package, scope):
+ """Sets the field's type, cpp_type, message_type and enum_type.
+
+ Args:
+ field_proto: Data about the field in proto format.
+ field_desc: The descriptor to modiy.
+ package: The package the field's container is in.
+ scope: Enclosing scope of available types.
+ """
+ if field_proto.type_name:
+ desc = self._GetTypeFromScope(package, field_proto.type_name, scope)
+ else:
+ desc = None
+
+ if not field_proto.HasField('type'):
+ if isinstance(desc, descriptor.Descriptor):
+ field_proto.type = descriptor.FieldDescriptor.TYPE_MESSAGE
+ else:
+ field_proto.type = descriptor.FieldDescriptor.TYPE_ENUM
+
+ field_desc.cpp_type = descriptor.FieldDescriptor.ProtoTypeToCppProtoType(
+ field_proto.type)
+
+ if (field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE
+ or field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP):
+ field_desc.message_type = desc
+
+ if field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
+ field_desc.enum_type = desc
+
+ if field_proto.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ field_desc.has_default_value = False
+ field_desc.default_value = []
+ elif field_proto.HasField('default_value'):
+ field_desc.has_default_value = True
+ if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
+ field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
+ field_desc.default_value = float(field_proto.default_value)
+ elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
+ field_desc.default_value = field_proto.default_value
+ elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
+ 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].number
+ elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
+ field_desc.default_value = text_encoding.CUnescape(
+ field_proto.default_value)
+ else:
+ field_desc.default_value = int(field_proto.default_value)
+ else:
+ field_desc.has_default_value = False
+ field_desc.default_value = None
+
+ field_desc.type = field_proto.type
+
+ def _MakeEnumValueDescriptor(self, value_proto, index):
+ """Creates a enum value descriptor object from a enum value proto.
+
+ Args:
+ value_proto: The proto describing the enum value.
+ index: The index of the enum value.
+
+ Returns:
+ An initialized EnumValueDescriptor object.
+ """
+
+ return descriptor.EnumValueDescriptor(
+ name=value_proto.name,
+ index=index,
+ number=value_proto.number,
+ options=value_proto.options,
+ type=None)
+
+ def _ExtractSymbols(self, descriptors):
+ """Pulls out all the symbols from descriptor protos.
+
+ Args:
+ descriptors: The messages to extract descriptors from.
+ Yields:
+ A two element tuple of the type name and descriptor object.
+ """
+
+ for desc in descriptors:
+ yield (_PrefixWithDot(desc.full_name), desc)
+ for symbol in self._ExtractSymbols(desc.nested_types):
+ yield symbol
+ for enum in desc.enum_types:
+ yield (_PrefixWithDot(enum.full_name), enum)
+
+ def _GetDeps(self, dependencies):
+ """Recursively finds dependencies for file protos.
+
+ Args:
+ dependencies: The names of the files being depended on.
+
+ Yields:
+ Each direct and indirect dependency.
+ """
+
+ for dependency in dependencies:
+ dep_desc = self.FindFileByName(dependency)
+ yield dep_desc
+ for parent_dep in dep_desc.dependencies:
+ yield parent_dep
+
+ def _GetTypeFromScope(self, package, type_name, scope):
+ """Finds a given type name in the current scope.
+
+ Args:
+ package: The package the proto should be located in.
+ type_name: The name of the type to be found in the scope.
+ scope: Dict mapping short and full symbols to message and enum types.
+
+ Returns:
+ The descriptor for the requested type.
+ """
+ if type_name not in scope:
+ components = _PrefixWithDot(package).split('.')
+ while components:
+ possible_match = '.'.join(components + [type_name])
+ if possible_match in scope:
+ type_name = possible_match
+ break
+ else:
+ components.pop(-1)
+ return scope[type_name]
+
+
+def _PrefixWithDot(name):
+ return name if name.startswith('.') else '.%s' % name
diff --git a/python/google/protobuf/internal/_parameterized.py b/python/google/protobuf/internal/_parameterized.py
new file mode 100755
index 00000000..6ed23308
--- /dev/null
+++ b/python/google/protobuf/internal/_parameterized.py
@@ -0,0 +1,438 @@
+#! /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.
+
+"""Adds support for parameterized tests to Python's unittest TestCase class.
+
+A parameterized test is a method in a test case that is invoked with different
+argument tuples.
+
+A simple example:
+
+ class AdditionExample(parameterized.ParameterizedTestCase):
+ @parameterized.Parameters(
+ (1, 2, 3),
+ (4, 5, 9),
+ (1, 1, 3))
+ def testAddition(self, op1, op2, result):
+ self.assertEquals(result, op1 + op2)
+
+
+Each invocation is a separate test case and properly isolated just
+like a normal test method, with its own setUp/tearDown cycle. In the
+example above, there are three separate testcases, one of which will
+fail due to an assertion error (1 + 1 != 3).
+
+Parameters for invididual test cases can be tuples (with positional parameters)
+or dictionaries (with named parameters):
+
+ class AdditionExample(parameterized.ParameterizedTestCase):
+ @parameterized.Parameters(
+ {'op1': 1, 'op2': 2, 'result': 3},
+ {'op1': 4, 'op2': 5, 'result': 9},
+ )
+ def testAddition(self, op1, op2, result):
+ self.assertEquals(result, op1 + op2)
+
+If a parameterized test fails, the error message will show the
+original test name (which is modified internally) and the arguments
+for the specific invocation, which are part of the string returned by
+the shortDescription() method on test cases.
+
+The id method of the test, used internally by the unittest framework,
+is also modified to show the arguments. To make sure that test names
+stay the same across several invocations, object representations like
+
+ >>> class Foo(object):
+ ... pass
+ >>> repr(Foo())
+ '<__main__.Foo object at 0x23d8610>'
+
+are turned into '<__main__.Foo>'. For even more descriptive names,
+especially in test logs, you can use the NamedParameters decorator. In
+this case, only tuples are supported, and the first parameters has to
+be a string (or an object that returns an apt name when converted via
+str()):
+
+ class NamedExample(parameterized.ParameterizedTestCase):
+ @parameterized.NamedParameters(
+ ('Normal', 'aa', 'aaa', True),
+ ('EmptyPrefix', '', 'abc', True),
+ ('BothEmpty', '', '', True))
+ def testStartsWith(self, prefix, string, result):
+ self.assertEquals(result, strings.startswith(prefix))
+
+Named tests also have the benefit that they can be run individually
+from the command line:
+
+ $ testmodule.py NamedExample.testStartsWithNormal
+ .
+ --------------------------------------------------------------------
+ Ran 1 test in 0.000s
+
+ OK
+
+Parameterized Classes
+=====================
+If invocation arguments are shared across test methods in a single
+ParameterizedTestCase class, instead of decorating all test methods
+individually, the class itself can be decorated:
+
+ @parameterized.Parameters(
+ (1, 2, 3)
+ (4, 5, 9))
+ class ArithmeticTest(parameterized.ParameterizedTestCase):
+ def testAdd(self, arg1, arg2, result):
+ self.assertEqual(arg1 + arg2, result)
+
+ def testSubtract(self, arg2, arg2, result):
+ self.assertEqual(result - arg1, arg2)
+
+Inputs from Iterables
+=====================
+If parameters should be shared across several test cases, or are dynamically
+created from other sources, a single non-tuple iterable can be passed into
+the decorator. This iterable will be used to obtain the test cases:
+
+ class AdditionExample(parameterized.ParameterizedTestCase):
+ @parameterized.Parameters(
+ c.op1, c.op2, c.result for c in testcases
+ )
+ def testAddition(self, op1, op2, result):
+ self.assertEquals(result, op1 + op2)
+
+
+Single-Argument Test Methods
+============================
+If a test method takes only one argument, the single argument does not need to
+be wrapped into a tuple:
+
+ class NegativeNumberExample(parameterized.ParameterizedTestCase):
+ @parameterized.Parameters(
+ -1, -3, -4, -5
+ )
+ def testIsNegative(self, arg):
+ self.assertTrue(IsNegative(arg))
+"""
+
+__author__ = 'tmarek@google.com (Torsten Marek)'
+
+import collections
+import functools
+import re
+import types
+import unittest
+import uuid
+
+from google.apputils import basetest
+
+ADDR_RE = re.compile(r'\<([a-zA-Z0-9_\-\.]+) object at 0x[a-fA-F0-9]+\>')
+_SEPARATOR = uuid.uuid1().hex
+_FIRST_ARG = object()
+_ARGUMENT_REPR = object()
+
+
+def _CleanRepr(obj):
+ return ADDR_RE.sub(r'<\1>', repr(obj))
+
+
+# Helper function formerly from the unittest module, removed from it in
+# Python 2.7.
+def _StrClass(cls):
+ return '%s.%s' % (cls.__module__, cls.__name__)
+
+
+def _NonStringIterable(obj):
+ return (isinstance(obj, collections.Iterable) and not
+ isinstance(obj, basestring))
+
+
+def _FormatParameterList(testcase_params):
+ if isinstance(testcase_params, collections.Mapping):
+ return ', '.join('%s=%s' % (argname, _CleanRepr(value))
+ for argname, value in testcase_params.iteritems())
+ elif _NonStringIterable(testcase_params):
+ return ', '.join(map(_CleanRepr, testcase_params))
+ else:
+ return _FormatParameterList((testcase_params,))
+
+
+class _ParameterizedTestIter(object):
+ """Callable and iterable class for producing new test cases."""
+
+ def __init__(self, test_method, testcases, naming_type):
+ """Returns concrete test functions for a test and a list of parameters.
+
+ The naming_type is used to determine the name of the concrete
+ functions as reported by the unittest framework. If naming_type is
+ _FIRST_ARG, the testcases must be tuples, and the first element must
+ have a string representation that is a valid Python identifier.
+
+ Args:
+ test_method: The decorated test method.
+ testcases: (list of tuple/dict) A list of parameter
+ tuples/dicts for individual test invocations.
+ naming_type: The test naming type, either _NAMED or _ARGUMENT_REPR.
+ """
+ self._test_method = test_method
+ self.testcases = testcases
+ self._naming_type = naming_type
+
+ def __call__(self, *args, **kwargs):
+ raise RuntimeError('You appear to be running a parameterized test case '
+ 'without having inherited from parameterized.'
+ 'ParameterizedTestCase. This is bad because none of '
+ 'your test cases are actually being run.')
+
+ def __iter__(self):
+ test_method = self._test_method
+ naming_type = self._naming_type
+
+ def MakeBoundParamTest(testcase_params):
+ @functools.wraps(test_method)
+ def BoundParamTest(self):
+ if isinstance(testcase_params, collections.Mapping):
+ test_method(self, **testcase_params)
+ elif _NonStringIterable(testcase_params):
+ test_method(self, *testcase_params)
+ else:
+ test_method(self, testcase_params)
+
+ if naming_type is _FIRST_ARG:
+ # Signal the metaclass that the name of the test function is unique
+ # and descriptive.
+ BoundParamTest.__x_use_name__ = True
+ BoundParamTest.__name__ += str(testcase_params[0])
+ testcase_params = testcase_params[1:]
+ elif naming_type is _ARGUMENT_REPR:
+ # __x_extra_id__ is used to pass naming information to the __new__
+ # method of TestGeneratorMetaclass.
+ # The metaclass will make sure to create a unique, but nondescriptive
+ # name for this test.
+ BoundParamTest.__x_extra_id__ = '(%s)' % (
+ _FormatParameterList(testcase_params),)
+ else:
+ raise RuntimeError('%s is not a valid naming type.' % (naming_type,))
+
+ BoundParamTest.__doc__ = '%s(%s)' % (
+ BoundParamTest.__name__, _FormatParameterList(testcase_params))
+ if test_method.__doc__:
+ BoundParamTest.__doc__ += '\n%s' % (test_method.__doc__,)
+ return BoundParamTest
+ return (MakeBoundParamTest(c) for c in self.testcases)
+
+
+def _IsSingletonList(testcases):
+ """True iff testcases contains only a single non-tuple element."""
+ return len(testcases) == 1 and not isinstance(testcases[0], tuple)
+
+
+def _ModifyClass(class_object, testcases, naming_type):
+ assert not getattr(class_object, '_id_suffix', None), (
+ 'Cannot add parameters to %s,'
+ ' which already has parameterized methods.' % (class_object,))
+ class_object._id_suffix = id_suffix = {}
+ for name, obj in class_object.__dict__.items():
+ if (name.startswith(unittest.TestLoader.testMethodPrefix)
+ and isinstance(obj, types.FunctionType)):
+ delattr(class_object, name)
+ methods = {}
+ _UpdateClassDictForParamTestCase(
+ methods, id_suffix, name,
+ _ParameterizedTestIter(obj, testcases, naming_type))
+ for name, meth in methods.iteritems():
+ setattr(class_object, name, meth)
+
+
+def _ParameterDecorator(naming_type, testcases):
+ """Implementation of the parameterization decorators.
+
+ Args:
+ naming_type: The naming type.
+ testcases: Testcase parameters.
+
+ Returns:
+ A function for modifying the decorated object.
+ """
+ def _Apply(obj):
+ if isinstance(obj, type):
+ _ModifyClass(
+ obj,
+ list(testcases) if not isinstance(testcases, collections.Sequence)
+ else testcases,
+ naming_type)
+ return obj
+ else:
+ return _ParameterizedTestIter(obj, testcases, naming_type)
+
+ if _IsSingletonList(testcases):
+ assert _NonStringIterable(testcases[0]), (
+ 'Single parameter argument must be a non-string iterable')
+ testcases = testcases[0]
+
+ return _Apply
+
+
+def Parameters(*testcases):
+ """A decorator for creating parameterized tests.
+
+ See the module docstring for a usage example.
+ Args:
+ *testcases: Parameters for the decorated method, either a single
+ iterable, or a list of tuples/dicts/objects (for tests
+ with only one argument).
+
+ Returns:
+ A test generator to be handled by TestGeneratorMetaclass.
+ """
+ return _ParameterDecorator(_ARGUMENT_REPR, testcases)
+
+
+def NamedParameters(*testcases):
+ """A decorator for creating parameterized tests.
+
+ See the module docstring for a usage example. The first element of
+ each parameter tuple should be a string and will be appended to the
+ name of the test method.
+
+ Args:
+ *testcases: Parameters for the decorated method, either a single
+ iterable, or a list of tuples.
+
+ Returns:
+ A test generator to be handled by TestGeneratorMetaclass.
+ """
+ return _ParameterDecorator(_FIRST_ARG, testcases)
+
+
+class TestGeneratorMetaclass(type):
+ """Metaclass for test cases with test generators.
+
+ A test generator is an iterable in a testcase that produces callables. These
+ callables must be single-argument methods. These methods are injected into
+ the class namespace and the original iterable is removed. If the name of the
+ iterable conforms to the test pattern, the injected methods will be picked
+ up as tests by the unittest framework.
+
+ In general, it is supposed to be used in conjuction with the
+ Parameters decorator.
+ """
+
+ def __new__(mcs, class_name, bases, dct):
+ dct['_id_suffix'] = id_suffix = {}
+ for name, obj in dct.items():
+ if (name.startswith(unittest.TestLoader.testMethodPrefix) and
+ _NonStringIterable(obj)):
+ iterator = iter(obj)
+ dct.pop(name)
+ _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator)
+
+ return type.__new__(mcs, class_name, bases, dct)
+
+
+def _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator):
+ """Adds individual test cases to a dictionary.
+
+ Args:
+ dct: The target dictionary.
+ id_suffix: The dictionary for mapping names to test IDs.
+ name: The original name of the test case.
+ iterator: The iterator generating the individual test cases.
+ """
+ for idx, func in enumerate(iterator):
+ assert callable(func), 'Test generators must yield callables, got %r' % (
+ func,)
+ if getattr(func, '__x_use_name__', False):
+ new_name = func.__name__
+ else:
+ new_name = '%s%s%d' % (name, _SEPARATOR, idx)
+ assert new_name not in dct, (
+ 'Name of parameterized test case "%s" not unique' % (new_name,))
+ dct[new_name] = func
+ id_suffix[new_name] = getattr(func, '__x_extra_id__', '')
+
+
+class ParameterizedTestCase(basetest.TestCase):
+ """Base class for test cases using the Parameters decorator."""
+ __metaclass__ = TestGeneratorMetaclass
+
+ def _OriginalName(self):
+ return self._testMethodName.split(_SEPARATOR)[0]
+
+ def __str__(self):
+ return '%s (%s)' % (self._OriginalName(), _StrClass(self.__class__))
+
+ def id(self): # pylint: disable=invalid-name
+ """Returns the descriptive ID of the test.
+
+ This is used internally by the unittesting framework to get a name
+ for the test to be used in reports.
+
+ Returns:
+ The test id.
+ """
+ return '%s.%s%s' % (_StrClass(self.__class__),
+ self._OriginalName(),
+ self._id_suffix.get(self._testMethodName, ''))
+
+
+def CoopParameterizedTestCase(other_base_class):
+ """Returns a new base class with a cooperative metaclass base.
+
+ This enables the ParameterizedTestCase to be used in combination
+ with other base classes that have custom metaclasses, such as
+ mox.MoxTestBase.
+
+ Only works with metaclasses that do not override type.__new__.
+
+ Example:
+
+ import google3
+ import mox
+
+ from google3.testing.pybase import parameterized
+
+ class ExampleTest(parameterized.CoopParameterizedTestCase(mox.MoxTestBase)):
+ ...
+
+ Args:
+ other_base_class: (class) A test case base class.
+
+ Returns:
+ A new class object.
+ """
+ metaclass = type(
+ 'CoopMetaclass',
+ (other_base_class.__metaclass__,
+ TestGeneratorMetaclass), {})
+ return metaclass(
+ 'CoopParameterizedTestCase',
+ (other_base_class, ParameterizedTestCase), {})
diff --git a/python/google/protobuf/internal/api_implementation.cc b/python/google/protobuf/internal/api_implementation.cc
new file mode 100644
index 00000000..6db12e8d
--- /dev/null
+++ b/python/google/protobuf/internal/api_implementation.cc
@@ -0,0 +1,129 @@
+// 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 <Python.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// Version constant.
+// This is either 0 for python, 1 for CPP V1, 2 for CPP V2.
+//
+// 0 is default and is equivalent to
+// PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
+//
+// 1 is set with -DPYTHON_PROTO2_CPP_IMPL_V1 and is equivalent to
+// PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+// and
+// PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=1
+//
+// 2 is set with -DPYTHON_PROTO2_CPP_IMPL_V2 and is equivalent to
+// PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+// and
+// PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2
+#ifdef PYTHON_PROTO2_CPP_IMPL_V1
+#error "PYTHON_PROTO2_CPP_IMPL_V1 is no longer supported."
+#else
+#ifdef PYTHON_PROTO2_CPP_IMPL_V2
+static int kImplVersion = 2;
+#else
+#ifdef PYTHON_PROTO2_PYTHON_IMPL
+static int kImplVersion = 0;
+#else
+
+static int kImplVersion = -1; // -1 means "Unspecified by compiler flags".
+
+#endif // PYTHON_PROTO2_PYTHON_IMPL
+#endif // PYTHON_PROTO2_CPP_IMPL_V2
+#endif // PYTHON_PROTO2_CPP_IMPL_V1
+
+static const char* kImplVersionName = "api_version";
+
+static const char* kModuleName = "_api_implementation";
+static const char kModuleDocstring[] =
+"_api_implementation is a module that exposes compile-time constants that\n"
+"determine the default API implementation to use for Python proto2.\n"
+"\n"
+"It complements api_implementation.py by setting defaults using compile-time\n"
+"constants defined in C, such that one can set defaults at compilation\n"
+"(e.g. with blaze flag --copt=-DPYTHON_PROTO2_CPP_IMPL_V2).";
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef _module = {
+ PyModuleDef_HEAD_INIT,
+ kModuleName,
+ kModuleDocstring,
+ -1,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#define INITFUNC PyInit__api_implementation
+#define INITFUNC_ERRORVAL NULL
+#else
+#define INITFUNC init_api_implementation
+#define INITFUNC_ERRORVAL
+#endif
+
+extern "C" {
+ PyMODINIT_FUNC INITFUNC() {
+#if PY_MAJOR_VERSION >= 3
+ PyObject *module = PyModule_Create(&_module);
+#else
+ PyObject *module = Py_InitModule3(
+ const_cast<char*>(kModuleName),
+ NULL,
+ const_cast<char*>(kModuleDocstring));
+#endif
+ if (module == NULL) {
+ return INITFUNC_ERRORVAL;
+ }
+
+ // Adds the module variable "api_version".
+ if (PyModule_AddIntConstant(
+ module,
+ const_cast<char*>(kImplVersionName),
+ kImplVersion))
+#if PY_MAJOR_VERSION < 3
+ return;
+#else
+ { Py_DECREF(module); return NULL; }
+
+ return module;
+#endif
+ }
+}
+
+} // namespace python
+} // namespace protobuf
+} // namespace google
diff --git a/python/google/protobuf/internal/api_implementation.py b/python/google/protobuf/internal/api_implementation.py
index b3e412e2..8ba4357c 100755
--- a/python/google/protobuf/internal/api_implementation.py
+++ b/python/google/protobuf/internal/api_implementation.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -28,32 +28,70 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Determine which implementation of the protobuf API is used in this process.
"""
-This module is the central entity that determines which implementation of the
-API is used.
-"""
-
-__author__ = 'petar@google.com (Petar Petrov)'
import os
+import sys
+
+try:
+ # pylint: disable=g-import-not-at-top
+ from google.protobuf.internal import _api_implementation
+ # The compile-time constants in the _api_implementation module can be used to
+ # switch to a certain implementation of the Python API at build time.
+ _api_version = _api_implementation.api_version
+ _proto_extension_modules_exist_in_build = True
+except ImportError:
+ _api_version = -1 # Unspecified by compiler flags.
+ _proto_extension_modules_exist_in_build = False
+
+if _api_version == 1:
+ raise ValueError('api_version=1 is no longer supported.')
+if _api_version < 0: # Still unspecified?
+ try:
+ # The presence of this module in a build allows the proto implementation to
+ # be upgraded merely via build deps rather than a compiler flag or the
+ # runtime environment variable.
+ # pylint: disable=g-import-not-at-top
+ from google.protobuf import _use_fast_cpp_protos
+ # Work around a known issue in the classic bootstrap .par import hook.
+ if not _use_fast_cpp_protos:
+ raise ImportError('_use_fast_cpp_protos import succeeded but was None')
+ del _use_fast_cpp_protos
+ _api_version = 2
+ except ImportError:
+ if _proto_extension_modules_exist_in_build:
+ if sys.version_info[0] >= 3: # Python 3 defaults to C++ impl v2.
+ _api_version = 2
+ # TODO(b/17427486): Make Python 2 default to C++ impl v2.
+
+_default_implementation_type = (
+ 'python' if _api_version <= 0 else 'cpp')
+
# This environment variable can be used to switch to a certain implementation
-# of the Python API. Right now only 'python' and 'cpp' are valid values. Any
-# other value will be ignored.
+# of the Python API, overriding the compile-time constants in the
+# _api_implementation module. Right now only 'python' and 'cpp' are valid
+# values. Any other value will be ignored.
_implementation_type = os.getenv('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION',
- 'python')
-
+ _default_implementation_type)
if _implementation_type != 'python':
- # For now, by default use the pure-Python implementation.
- # The code below checks if the C extension is available and
- # uses it if it is available.
_implementation_type = 'cpp'
- ## Determine automatically which implementation to use.
- #try:
- # from google.protobuf.internal import cpp_message
- # _implementation_type = 'cpp'
- #except ImportError, e:
- # _implementation_type = 'python'
+
+# This environment variable can be used to switch between the two
+# 'cpp' implementations, overriding the compile-time constants in the
+# _api_implementation module. Right now only 1 and 2 are valid values. Any other
+# value will be ignored.
+_implementation_version_str = os.getenv(
+ 'PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION', '2')
+
+if _implementation_version_str != '2':
+ raise ValueError(
+ 'unsupported PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION: "' +
+ _implementation_version_str + '" (supported versions: 2)'
+ )
+
+_implementation_version = int(_implementation_version_str)
# Usage of this function is discouraged. Clients shouldn't care which
@@ -62,3 +100,8 @@ if _implementation_type != 'python':
# Please don't use this function if possible.
def Type():
return _implementation_type
+
+
+# See comment on 'Type' above.
+def Version():
+ return _implementation_version
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index 097a3c26..d976f9e1 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -41,7 +41,6 @@ are:
__author__ = 'petar@google.com (Petar Petrov)'
-
class BaseContainer(object):
"""Base container class."""
@@ -78,8 +77,13 @@ class BaseContainer(object):
def __repr__(self):
return repr(self._values)
- def sort(self, sort_function=cmp):
- self._values.sort(sort_function)
+ def sort(self, *args, **kwargs):
+ # Continue to support the old sort_function keyword argument.
+ # This is expected to be a rare occurrence, so use LBYL to avoid
+ # the overhead of actually catching KeyError.
+ if 'sort_function' in kwargs:
+ kwargs['cmp'] = kwargs.pop('sort_function')
+ self._values.sort(*args, **kwargs)
class RepeatedScalarFieldContainer(BaseContainer):
@@ -103,29 +107,34 @@ class RepeatedScalarFieldContainer(BaseContainer):
def append(self, value):
"""Appends an item to the list. Similar to list.append()."""
- self._type_checker.CheckValue(value)
- self._values.append(value)
+ self._values.append(self._type_checker.CheckValue(value))
if not self._message_listener.dirty:
self._message_listener.Modified()
def insert(self, key, value):
"""Inserts the item at the specified position. Similar to list.insert()."""
- self._type_checker.CheckValue(value)
- self._values.insert(key, value)
+ self._values.insert(key, self._type_checker.CheckValue(value))
if not self._message_listener.dirty:
self._message_listener.Modified()
def extend(self, elem_seq):
- """Extends by appending the given sequence. Similar to list.extend()."""
- if not elem_seq:
- return
+ """Extends by appending the given iterable. Similar to list.extend()."""
- new_values = []
- for elem in elem_seq:
- self._type_checker.CheckValue(elem)
- new_values.append(elem)
- self._values.extend(new_values)
- self._message_listener.Modified()
+ if elem_seq is None:
+ return
+ try:
+ elem_seq_iter = iter(elem_seq)
+ except TypeError:
+ if not elem_seq:
+ # silently ignore falsy inputs :-/.
+ # TODO(ptucker): Deprecate this behavior. b/18413862
+ return
+ raise
+
+ new_values = [self._type_checker.CheckValue(elem) for elem in elem_seq_iter]
+ if new_values:
+ self._values.extend(new_values)
+ self._message_listener.Modified()
def MergeFrom(self, other):
"""Appends the contents of another repeated field of the same type to this
@@ -139,11 +148,21 @@ class RepeatedScalarFieldContainer(BaseContainer):
self._values.remove(elem)
self._message_listener.Modified()
+ def pop(self, key=-1):
+ """Removes and returns an item at a given index. Similar to list.pop()."""
+ value = self._values[key]
+ self.__delitem__(key)
+ return value
+
def __setitem__(self, key, value):
"""Sets the item on the specified position."""
- self._type_checker.CheckValue(value)
- self._values[key] = value
- self._message_listener.Modified()
+ if isinstance(key, slice): # PY3
+ if key.step is not None:
+ raise ValueError('Extended slices not supported')
+ self.__setslice__(key.start, key.stop, value)
+ else:
+ self._values[key] = self._type_checker.CheckValue(value)
+ self._message_listener.Modified()
def __getslice__(self, start, stop):
"""Retrieves the subset of items from between the specified indices."""
@@ -153,8 +172,7 @@ class RepeatedScalarFieldContainer(BaseContainer):
"""Sets the subset of items from between the specified indices."""
new_values = []
for value in values:
- self._type_checker.CheckValue(value)
- new_values.append(value)
+ new_values.append(self._type_checker.CheckValue(value))
self._values[start:stop] = new_values
self._message_listener.Modified()
@@ -235,6 +253,17 @@ class RepeatedCompositeFieldContainer(BaseContainer):
"""
self.extend(other._values)
+ def remove(self, elem):
+ """Removes an item from the list. Similar to list.remove()."""
+ self._values.remove(elem)
+ self._message_listener.Modified()
+
+ def pop(self, key=-1):
+ """Removes and returns an item at a given index. Similar to list.pop()."""
+ value = self._values[key]
+ self.__delitem__(key)
+ return value
+
def __getslice__(self, start, stop):
"""Retrieves the subset of items from between the specified indices."""
return self._values[start:stop]
diff --git a/python/google/protobuf/internal/cpp_message.py b/python/google/protobuf/internal/cpp_message.py
index 3f426502..0313cb0b 100755
--- a/python/google/protobuf/internal/cpp_message.py
+++ b/python/google/protobuf/internal/cpp_message.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -34,8 +34,10 @@ Descriptor objects at runtime backed by the protocol buffer C++ API.
__author__ = 'petar@google.com (Petar Petrov)'
+import copy_reg
import operator
from google.protobuf.internal import _net_proto2___python
+from google.protobuf.internal import enum_type_wrapper
from google.protobuf import message
@@ -156,10 +158,12 @@ class RepeatedScalarContainer(object):
def __hash__(self):
raise TypeError('unhashable object')
- def sort(self, sort_function=cmp):
- values = self[slice(None, None, None)]
- values.sort(sort_function)
- self._cmsg.AssignRepeatedScalar(self._cfield_descriptor, values)
+ def sort(self, *args, **kwargs):
+ # Maintain compatibility with the previous interface.
+ if 'sort_function' in kwargs:
+ kwargs['cmp'] = kwargs.pop('sort_function')
+ self._cmsg.AssignRepeatedScalar(self._cfield_descriptor,
+ sorted(self, *args, **kwargs))
def RepeatedScalarProperty(cdescriptor):
@@ -202,6 +206,12 @@ class RepeatedCompositeContainer(object):
for message in elem_seq:
self.add().MergeFrom(message)
+ def remove(self, value):
+ # TODO(protocol-devel): This is inefficient as it needs to generate a
+ # message pointer for each message only to do index(). Move this to a C++
+ # extension function.
+ self.__delitem__(self[slice(None, None, None)].index(value))
+
def MergeFrom(self, other):
for message in other[:]:
self.add().MergeFrom(message)
@@ -236,27 +246,29 @@ class RepeatedCompositeContainer(object):
def __hash__(self):
raise TypeError('unhashable object')
- def sort(self, sort_function=cmp):
- messages = []
- for index in range(len(self)):
- # messages[i][0] is where the i-th element of the new array has to come
- # from.
- # messages[i][1] is where the i-th element of the old array has to go.
- messages.append([index, 0, self[index]])
- messages.sort(lambda x,y: sort_function(x[2], y[2]))
+ def sort(self, cmp=None, key=None, reverse=False, **kwargs):
+ # Maintain compatibility with the old interface.
+ if cmp is None and 'sort_function' in kwargs:
+ cmp = kwargs.pop('sort_function')
- # Remember which position each elements has to move to.
- for i in range(len(messages)):
- messages[messages[i][0]][1] = i
+ # The cmp function, if provided, is passed the results of the key function,
+ # so we only need to wrap one of them.
+ if key is None:
+ index_key = self.__getitem__
+ else:
+ index_key = lambda i: key(self[i])
+
+ # Sort the list of current indexes by the underlying object.
+ indexes = range(len(self))
+ indexes.sort(cmp=cmp, key=index_key, reverse=reverse)
# Apply the transposition.
- for i in range(len(messages)):
- from_position = messages[i][0]
- if i == from_position:
+ for dest, src in enumerate(indexes):
+ if dest == src:
continue
- self._cmsg.SwapRepeatedFieldElements(
- self._cfield_descriptor, i, from_position)
- messages[messages[i][1]][0] = from_position
+ self._cmsg.SwapRepeatedFieldElements(self._cfield_descriptor, dest, src)
+ # Don't swap the same value twice.
+ indexes[src] = src
def RepeatedCompositeProperty(cdescriptor, message_type):
@@ -359,11 +371,12 @@ class ExtensionDict(object):
return None
-def NewMessage(message_descriptor, dictionary):
+def NewMessage(bases, message_descriptor, dictionary):
"""Creates a new protocol message *class*."""
_AddClassAttributesForNestedExtensions(message_descriptor, dictionary)
_AddEnumValues(message_descriptor, dictionary)
_AddDescriptors(message_descriptor, dictionary)
+ return bases
def InitMessage(message_descriptor, cls):
@@ -372,6 +385,7 @@ def InitMessage(message_descriptor, cls):
_AddInitMethod(message_descriptor, cls)
_AddMessageMethods(message_descriptor, cls)
_AddPropertiesForExtensions(message_descriptor, cls)
+ copy_reg.pickle(cls, lambda obj: (cls, (), obj.__getstate__()))
def _AddDescriptors(message_descriptor, dictionary):
@@ -387,7 +401,7 @@ def _AddDescriptors(message_descriptor, dictionary):
field.full_name)
dictionary['__slots__'] = list(dictionary['__descriptors'].iterkeys()) + [
- '_cmsg', '_owner', '_composite_fields', 'Extensions']
+ '_cmsg', '_owner', '_composite_fields', 'Extensions', '_HACK_REFCOUNTS']
def _AddEnumValues(message_descriptor, dictionary):
@@ -398,6 +412,7 @@ def _AddEnumValues(message_descriptor, dictionary):
dictionary: Class dictionary that should be populated.
"""
for enum_type in message_descriptor.enum_types:
+ dictionary[enum_type.name] = enum_type_wrapper.EnumTypeWrapper(enum_type)
for enum_value in enum_type.values:
dictionary[enum_value.name] = enum_value.number
@@ -439,28 +454,35 @@ def _AddInitMethod(message_descriptor, cls):
def Init(self, **kwargs):
"""Message constructor."""
cmessage = kwargs.pop('__cmessage', None)
- if cmessage is None:
- self._cmsg = NewCMessage(message_descriptor.full_name)
- else:
+ if cmessage:
self._cmsg = cmessage
+ else:
+ self._cmsg = NewCMessage(message_descriptor.full_name)
# Keep a reference to the owner, as the owner keeps a reference to the
# underlying protocol buffer message.
owner = kwargs.pop('__owner', None)
- if owner is not None:
+ if owner:
self._owner = owner
- self.Extensions = ExtensionDict(self)
+ if message_descriptor.is_extendable:
+ self.Extensions = ExtensionDict(self)
+ else:
+ # Reference counting in the C++ code is broken and depends on
+ # the Extensions reference to keep this object alive during unit
+ # tests (see b/4856052). Remove this once b/4945904 is fixed.
+ self._HACK_REFCOUNTS = self
self._composite_fields = {}
for field_name, field_value in kwargs.iteritems():
field_cdescriptor = self.__descriptors.get(field_name, None)
- if field_cdescriptor is None:
+ if not field_cdescriptor:
raise ValueError('Protocol message has no "%s" field.' % field_name)
if field_cdescriptor.label == _LABEL_REPEATED:
if field_cdescriptor.cpp_type == _CPPTYPE_MESSAGE:
+ field_name = getattr(self, field_name)
for val in field_value:
- getattr(self, field_name).add().MergeFrom(val)
+ field_name.add().MergeFrom(val)
else:
getattr(self, field_name).extend(field_value)
elif field_cdescriptor.cpp_type == _CPPTYPE_MESSAGE:
@@ -497,12 +519,34 @@ def _AddMessageMethods(message_descriptor, cls):
return self._cmsg.HasField(field_name)
def ClearField(self, field_name):
+ child_cmessage = None
if field_name in self._composite_fields:
+ child_field = self._composite_fields[field_name]
del self._composite_fields[field_name]
- self._cmsg.ClearField(field_name)
+
+ child_cdescriptor = self.__descriptors[field_name]
+ # TODO(anuraag): Support clearing repeated message fields as well.
+ if (child_cdescriptor.label != _LABEL_REPEATED and
+ child_cdescriptor.cpp_type == _CPPTYPE_MESSAGE):
+ child_field._owner = None
+ child_cmessage = child_field._cmsg
+
+ if child_cmessage is not None:
+ self._cmsg.ClearField(field_name, child_cmessage)
+ else:
+ self._cmsg.ClearField(field_name)
def Clear(self):
- return self._cmsg.Clear()
+ cmessages_to_release = []
+ for field_name, child_field in self._composite_fields.iteritems():
+ child_cdescriptor = self.__descriptors[field_name]
+ # TODO(anuraag): Support clearing repeated message fields as well.
+ if (child_cdescriptor.label != _LABEL_REPEATED and
+ child_cdescriptor.cpp_type == _CPPTYPE_MESSAGE):
+ child_field._owner = None
+ cmessages_to_release.append((child_cdescriptor, child_field._cmsg))
+ self._composite_fields.clear()
+ self._cmsg.Clear(cmessages_to_release)
def IsInitialized(self, errors=None):
if self._cmsg.IsInitialized():
@@ -514,8 +558,8 @@ def _AddMessageMethods(message_descriptor, cls):
def SerializeToString(self):
if not self.IsInitialized():
raise message.EncodeError(
- 'Message is missing required fields: ' +
- ','.join(self.FindInitializationErrors()))
+ 'Message %s is missing required fields: %s' % (
+ self._cmsg.full_name, ','.join(self.FindInitializationErrors())))
return self._cmsg.SerializeToString()
def SerializePartialToString(self):
@@ -534,7 +578,8 @@ def _AddMessageMethods(message_descriptor, cls):
def MergeFrom(self, msg):
if not isinstance(msg, cls):
raise TypeError(
- "Parameter to MergeFrom() must be instance of same class.")
+ "Parameter to MergeFrom() must be instance of same class: "
+ "expected %s got %s." % (cls.__name__, type(msg).__name__))
self._cmsg.MergeFrom(msg._cmsg)
def CopyFrom(self, msg):
@@ -565,7 +610,7 @@ def _AddMessageMethods(message_descriptor, cls):
return self._cmsg.FindInitializationErrors()
def __str__(self):
- return self._cmsg.DebugString()
+ return str(self._cmsg)
def __eq__(self, other):
if self is other:
@@ -581,6 +626,8 @@ def _AddMessageMethods(message_descriptor, cls):
raise TypeError('unhashable object')
def __unicode__(self):
+ # Lazy import to prevent circular import when text_format imports this file.
+ from google.protobuf import text_format
return text_format.MessageToString(self, as_utf8=True).decode('utf-8')
# Attach the local methods to the message class.
diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py
index 55f746f5..0f500606 100755
--- a/python/google/protobuf/internal/decoder.py
+++ b/python/google/protobuf/internal/decoder.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -28,6 +28,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#PY25 compatible for GAE.
+#
+# Copyright 2009 Google Inc. All Rights Reserved.
+
"""Code for decoding protocol buffer primitives.
This code is very similar to encoder.py -- read the docs for that module first.
@@ -81,6 +85,8 @@ we repeatedly read a tag, look up the corresponding decoder, and invoke it.
__author__ = 'kenton@google.com (Kenton Varda)'
import struct
+import sys ##PY25
+_PY2 = sys.version_info[0] < 3 ##PY25
from google.protobuf.internal import encoder
from google.protobuf.internal import wire_format
from google.protobuf import message
@@ -98,7 +104,7 @@ _NAN = _POS_INF * 0
_DecodeError = message.DecodeError
-def _VarintDecoder(mask):
+def _VarintDecoder(mask, result_type):
"""Return an encoder for a basic varint value (does not include tag).
Decoded values will be bitwise-anded with the given mask before being
@@ -109,15 +115,18 @@ def _VarintDecoder(mask):
"""
local_ord = ord
+ py2 = _PY2 ##PY25
+##!PY25 py2 = str is bytes
def DecodeVarint(buffer, pos):
result = 0
shift = 0
while 1:
- b = local_ord(buffer[pos])
+ b = local_ord(buffer[pos]) if py2 else buffer[pos]
result |= ((b & 0x7f) << shift)
pos += 1
if not (b & 0x80):
result &= mask
+ result = result_type(result)
return (result, pos)
shift += 7
if shift >= 64:
@@ -125,15 +134,17 @@ def _VarintDecoder(mask):
return DecodeVarint
-def _SignedVarintDecoder(mask):
+def _SignedVarintDecoder(mask, result_type):
"""Like _VarintDecoder() but decodes signed values."""
local_ord = ord
+ py2 = _PY2 ##PY25
+##!PY25 py2 = str is bytes
def DecodeVarint(buffer, pos):
result = 0
shift = 0
while 1:
- b = local_ord(buffer[pos])
+ b = local_ord(buffer[pos]) if py2 else buffer[pos]
result |= ((b & 0x7f) << shift)
pos += 1
if not (b & 0x80):
@@ -142,19 +153,23 @@ def _SignedVarintDecoder(mask):
result |= ~mask
else:
result &= mask
+ result = result_type(result)
return (result, pos)
shift += 7
if shift >= 64:
raise _DecodeError('Too many bytes when decoding varint.')
return DecodeVarint
+# We force 32-bit values to int and 64-bit values to long to make
+# alternate implementations where the distinction is more significant
+# (e.g. the C++ implementation) simpler.
-_DecodeVarint = _VarintDecoder((1 << 64) - 1)
-_DecodeSignedVarint = _SignedVarintDecoder((1 << 64) - 1)
+_DecodeVarint = _VarintDecoder((1 << 64) - 1, long)
+_DecodeSignedVarint = _SignedVarintDecoder((1 << 64) - 1, long)
# Use these versions for values which must be limited to 32 bits.
-_DecodeVarint32 = _VarintDecoder((1 << 32) - 1)
-_DecodeSignedVarint32 = _SignedVarintDecoder((1 << 32) - 1)
+_DecodeVarint32 = _VarintDecoder((1 << 32) - 1, int)
+_DecodeSignedVarint32 = _SignedVarintDecoder((1 << 32) - 1, int)
def ReadTag(buffer, pos):
@@ -168,8 +183,10 @@ def ReadTag(buffer, pos):
use that, but not in Python.
"""
+ py2 = _PY2 ##PY25
+##!PY25 py2 = str is bytes
start = pos
- while ord(buffer[pos]) & 0x80:
+ while (ord(buffer[pos]) if py2 else buffer[pos]) & 0x80:
pos += 1
pos += 1
return (buffer[start:pos], pos)
@@ -284,6 +301,7 @@ def _FloatDecoder():
"""
local_unpack = struct.unpack
+ b = (lambda x:x) if _PY2 else lambda x:x.encode('latin1') ##PY25
def InnerDecode(buffer, pos):
# We expect a 32-bit value in little-endian byte order. Bit 1 is the sign
@@ -294,13 +312,17 @@ def _FloatDecoder():
# If this value has all its exponent bits set, then it's non-finite.
# In Python 2.4, struct.unpack will convert it to a finite 64-bit value.
# To avoid that, we parse it specially.
- if ((float_bytes[3] in '\x7F\xFF')
- and (float_bytes[2] >= '\x80')):
+ if ((float_bytes[3:4] in b('\x7F\xFF')) ##PY25
+##!PY25 if ((float_bytes[3:4] in b'\x7F\xFF')
+ and (float_bytes[2:3] >= b('\x80'))): ##PY25
+##!PY25 and (float_bytes[2:3] >= b'\x80')):
# If at least one significand bit is set...
- if float_bytes[0:3] != '\x00\x00\x80':
+ if float_bytes[0:3] != b('\x00\x00\x80'): ##PY25
+##!PY25 if float_bytes[0:3] != b'\x00\x00\x80':
return (_NAN, new_pos)
# If sign bit is set...
- if float_bytes[3] == '\xFF':
+ if float_bytes[3:4] == b('\xFF'): ##PY25
+##!PY25 if float_bytes[3:4] == b'\xFF':
return (_NEG_INF, new_pos)
return (_POS_INF, new_pos)
@@ -319,6 +341,7 @@ def _DoubleDecoder():
"""
local_unpack = struct.unpack
+ b = (lambda x:x) if _PY2 else lambda x:x.encode('latin1') ##PY25
def InnerDecode(buffer, pos):
# We expect a 64-bit value in little-endian byte order. Bit 1 is the sign
@@ -329,9 +352,12 @@ def _DoubleDecoder():
# If this value has all its exponent bits set and at least one significand
# bit set, it's not a number. In Python 2.4, struct.unpack will treat it
# as inf or -inf. To avoid that, we treat it specially.
- if ((double_bytes[7] in '\x7F\xFF')
- and (double_bytes[6] >= '\xF0')
- and (double_bytes[0:7] != '\x00\x00\x00\x00\x00\x00\xF0')):
+##!PY25 if ((double_bytes[7:8] in b'\x7F\xFF')
+##!PY25 and (double_bytes[6:7] >= b'\xF0')
+##!PY25 and (double_bytes[0:7] != b'\x00\x00\x00\x00\x00\x00\xF0')):
+ if ((double_bytes[7:8] in b('\x7F\xFF')) ##PY25
+ and (double_bytes[6:7] >= b('\xF0')) ##PY25
+ and (double_bytes[0:7] != b('\x00\x00\x00\x00\x00\x00\xF0'))): ##PY25
return (_NAN, new_pos)
# Note that we expect someone up-stack to catch struct.error and convert
@@ -342,10 +368,86 @@ def _DoubleDecoder():
return _SimpleDecoder(wire_format.WIRETYPE_FIXED64, InnerDecode)
+def EnumDecoder(field_number, is_repeated, is_packed, key, new_default):
+ enum_type = key.enum_type
+ if is_packed:
+ local_DecodeVarint = _DecodeVarint
+ def DecodePackedField(buffer, pos, end, message, field_dict):
+ value = field_dict.get(key)
+ if value is None:
+ value = field_dict.setdefault(key, new_default(message))
+ (endpoint, pos) = local_DecodeVarint(buffer, pos)
+ endpoint += pos
+ if endpoint > end:
+ raise _DecodeError('Truncated message.')
+ while pos < endpoint:
+ value_start_pos = pos
+ (element, pos) = _DecodeSignedVarint32(buffer, pos)
+ if element in enum_type.values_by_number:
+ value.append(element)
+ else:
+ if not message._unknown_fields:
+ message._unknown_fields = []
+ tag_bytes = encoder.TagBytes(field_number,
+ wire_format.WIRETYPE_VARINT)
+ message._unknown_fields.append(
+ (tag_bytes, buffer[value_start_pos:pos]))
+ if pos > endpoint:
+ if element in enum_type.values_by_number:
+ del value[-1] # Discard corrupt value.
+ else:
+ del message._unknown_fields[-1]
+ raise _DecodeError('Packed element was truncated.')
+ return pos
+ return DecodePackedField
+ elif is_repeated:
+ tag_bytes = encoder.TagBytes(field_number, wire_format.WIRETYPE_VARINT)
+ tag_len = len(tag_bytes)
+ def DecodeRepeatedField(buffer, pos, end, message, field_dict):
+ value = field_dict.get(key)
+ if value is None:
+ value = field_dict.setdefault(key, new_default(message))
+ while 1:
+ (element, new_pos) = _DecodeSignedVarint32(buffer, pos)
+ if element in enum_type.values_by_number:
+ value.append(element)
+ else:
+ if not message._unknown_fields:
+ message._unknown_fields = []
+ message._unknown_fields.append(
+ (tag_bytes, buffer[pos:new_pos]))
+ # Predict that the next tag is another copy of the same repeated
+ # field.
+ pos = new_pos + tag_len
+ if buffer[new_pos:pos] != tag_bytes or new_pos >= end:
+ # Prediction failed. Return.
+ if new_pos > end:
+ raise _DecodeError('Truncated message.')
+ return new_pos
+ return DecodeRepeatedField
+ else:
+ def DecodeField(buffer, pos, end, message, field_dict):
+ value_start_pos = pos
+ (enum_value, pos) = _DecodeSignedVarint32(buffer, pos)
+ if pos > end:
+ raise _DecodeError('Truncated message.')
+ if enum_value in enum_type.values_by_number:
+ field_dict[key] = enum_value
+ else:
+ if not message._unknown_fields:
+ message._unknown_fields = []
+ tag_bytes = encoder.TagBytes(field_number,
+ wire_format.WIRETYPE_VARINT)
+ message._unknown_fields.append(
+ (tag_bytes, buffer[value_start_pos:pos]))
+ return pos
+ return DecodeField
+
+
# --------------------------------------------------------------------
-Int32Decoder = EnumDecoder = _SimpleDecoder(
+Int32Decoder = _SimpleDecoder(
wire_format.WIRETYPE_VARINT, _DecodeSignedVarint32)
Int64Decoder = _SimpleDecoder(
@@ -380,6 +482,14 @@ def StringDecoder(field_number, is_repeated, is_packed, key, new_default):
local_DecodeVarint = _DecodeVarint
local_unicode = unicode
+ def _ConvertToUnicode(byte_str):
+ try:
+ return local_unicode(byte_str, 'utf-8')
+ except UnicodeDecodeError, e:
+ # add more information to the error message and re-raise it.
+ e.reason = '%s in field: %s' % (e, key.full_name)
+ raise
+
assert not is_packed
if is_repeated:
tag_bytes = encoder.TagBytes(field_number,
@@ -394,7 +504,7 @@ def StringDecoder(field_number, is_repeated, is_packed, key, new_default):
new_pos = pos + size
if new_pos > end:
raise _DecodeError('Truncated string.')
- value.append(local_unicode(buffer[pos:new_pos], 'utf-8'))
+ value.append(_ConvertToUnicode(buffer[pos:new_pos]))
# Predict that the next tag is another copy of the same repeated field.
pos = new_pos + tag_len
if buffer[new_pos:pos] != tag_bytes or new_pos == end:
@@ -407,7 +517,7 @@ def StringDecoder(field_number, is_repeated, is_packed, key, new_default):
new_pos = pos + size
if new_pos > end:
raise _DecodeError('Truncated string.')
- field_dict[key] = local_unicode(buffer[pos:new_pos], 'utf-8')
+ field_dict[key] = _ConvertToUnicode(buffer[pos:new_pos])
return new_pos
return DecodeField
@@ -511,9 +621,6 @@ def MessageDecoder(field_number, is_repeated, is_packed, key, new_default):
if value is None:
value = field_dict.setdefault(key, new_default(message))
while 1:
- value = field_dict.get(key)
- if value is None:
- value = field_dict.setdefault(key, new_default(message))
# Read length.
(size, pos) = local_DecodeVarint(buffer, pos)
new_pos = pos + size
@@ -576,6 +683,7 @@ def MessageSetItemDecoder(extensions_by_number):
local_SkipField = SkipField
def DecodeItem(buffer, pos, end, message, field_dict):
+ message_set_item_start = pos
type_id = -1
message_start = -1
message_end = -1
@@ -614,6 +722,11 @@ def MessageSetItemDecoder(extensions_by_number):
# The only reason _InternalParse would return early is if it encountered
# an end-group tag.
raise _DecodeError('Unexpected end-group tag.')
+ else:
+ if not message._unknown_fields:
+ message._unknown_fields = []
+ message._unknown_fields.append((MESSAGE_SET_ITEM_TAG,
+ buffer[message_set_item_start:pos]))
return pos
@@ -625,8 +738,10 @@ def MessageSetItemDecoder(extensions_by_number):
def _SkipVarint(buffer, pos, end):
"""Skip a varint value. Returns the new position."""
-
- while ord(buffer[pos]) & 0x80:
+ # Previously ord(buffer[pos]) raised IndexError when pos is out of range.
+ # With this code, ord(b'') raises TypeError. Both are handled in
+ # python_message.py to generate a 'Truncated message' error.
+ while ord(buffer[pos:pos+1]) & 0x80:
pos += 1
pos += 1
if pos > end:
@@ -693,7 +808,6 @@ def _FieldSkipper():
]
wiretype_mask = wire_format.TAG_TYPE_MASK
- local_ord = ord
def SkipField(buffer, pos, end, tag_bytes):
"""Skips a field with the specified tag.
@@ -706,7 +820,7 @@ def _FieldSkipper():
"""
# The wire type is always in the first byte since varints are little-endian.
- wire_type = local_ord(tag_bytes[0]) & wiretype_mask
+ wire_type = ord(tag_bytes[0:1]) & wiretype_mask
return WIRETYPE_TO_SKIPPER[wire_type](buffer, pos, end)
return SkipField
diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py
new file mode 100644
index 00000000..8970f5c2
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_database_test.py
@@ -0,0 +1,65 @@
+#! /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.descriptor_database."""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+from google.apputils import basetest
+from google.protobuf import descriptor_pb2
+from google.protobuf.internal import factory_test2_pb2
+from google.protobuf import descriptor_database
+
+
+class DescriptorDatabaseTest(basetest.TestCase):
+
+ def testAdd(self):
+ db = descriptor_database.DescriptorDatabase()
+ file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString(
+ factory_test2_pb2.DESCRIPTOR.serialized_pb)
+ db.Add(file_desc_proto)
+
+ self.assertEquals(file_desc_proto, db.FindFileByName(
+ 'google/protobuf/internal/factory_test2.proto'))
+ self.assertEquals(file_desc_proto, db.FindFileContainingSymbol(
+ 'google.protobuf.python.internal.Factory2Message'))
+ self.assertEquals(file_desc_proto, db.FindFileContainingSymbol(
+ 'google.protobuf.python.internal.Factory2Message.NestedFactory2Message'))
+ self.assertEquals(file_desc_proto, db.FindFileContainingSymbol(
+ '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
new file mode 100644
index 00000000..11ef61c5
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -0,0 +1,591 @@
+#! /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.descriptor_pool."""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+import os
+import unittest
+
+from google.apputils import basetest
+from google.protobuf import unittest_pb2
+from google.protobuf import descriptor_pb2
+from google.protobuf.internal import api_implementation
+from google.protobuf.internal import descriptor_pool_test1_pb2
+from google.protobuf.internal import descriptor_pool_test2_pb2
+from google.protobuf.internal import factory_test1_pb2
+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):
+
+ def setUp(self):
+ self.pool = descriptor_pool.DescriptorPool()
+ self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
+ factory_test1_pb2.DESCRIPTOR.serialized_pb)
+ self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
+ factory_test2_pb2.DESCRIPTOR.serialized_pb)
+ self.pool.Add(self.factory_test1_fd)
+ self.pool.Add(self.factory_test2_fd)
+
+ def testFindFileByName(self):
+ name1 = 'google/protobuf/internal/factory_test1.proto'
+ file_desc1 = self.pool.FindFileByName(name1)
+ self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
+ self.assertEquals(name1, file_desc1.name)
+ self.assertEquals('google.protobuf.python.internal', file_desc1.package)
+ self.assertIn('Factory1Message', file_desc1.message_types_by_name)
+
+ name2 = 'google/protobuf/internal/factory_test2.proto'
+ file_desc2 = self.pool.FindFileByName(name2)
+ self.assertIsInstance(file_desc2, descriptor.FileDescriptor)
+ self.assertEquals(name2, file_desc2.name)
+ self.assertEquals('google.protobuf.python.internal', file_desc2.package)
+ self.assertIn('Factory2Message', file_desc2.message_types_by_name)
+
+ def testFindFileByNameFailure(self):
+ with self.assertRaises(KeyError):
+ self.pool.FindFileByName('Does not exist')
+
+ def testFindFileContainingSymbol(self):
+ file_desc1 = self.pool.FindFileContainingSymbol(
+ 'google.protobuf.python.internal.Factory1Message')
+ self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
+ self.assertEquals('google/protobuf/internal/factory_test1.proto',
+ file_desc1.name)
+ self.assertEquals('google.protobuf.python.internal', file_desc1.package)
+ self.assertIn('Factory1Message', file_desc1.message_types_by_name)
+
+ file_desc2 = self.pool.FindFileContainingSymbol(
+ 'google.protobuf.python.internal.Factory2Message')
+ self.assertIsInstance(file_desc2, descriptor.FileDescriptor)
+ self.assertEquals('google/protobuf/internal/factory_test2.proto',
+ file_desc2.name)
+ self.assertEquals('google.protobuf.python.internal', file_desc2.package)
+ self.assertIn('Factory2Message', file_desc2.message_types_by_name)
+
+ def testFindFileContainingSymbolFailure(self):
+ with self.assertRaises(KeyError):
+ self.pool.FindFileContainingSymbol('Does not exist')
+
+ def testFindMessageTypeByName(self):
+ msg1 = self.pool.FindMessageTypeByName(
+ 'google.protobuf.python.internal.Factory1Message')
+ self.assertIsInstance(msg1, descriptor.Descriptor)
+ self.assertEquals('Factory1Message', msg1.name)
+ self.assertEquals('google.protobuf.python.internal.Factory1Message',
+ msg1.full_name)
+ self.assertEquals(None, msg1.containing_type)
+
+ nested_msg1 = msg1.nested_types[0]
+ self.assertEquals('NestedFactory1Message', nested_msg1.name)
+ self.assertEquals(msg1, nested_msg1.containing_type)
+
+ nested_enum1 = msg1.enum_types[0]
+ self.assertEquals('NestedFactory1Enum', nested_enum1.name)
+ self.assertEquals(msg1, nested_enum1.containing_type)
+
+ self.assertEquals(nested_msg1, msg1.fields_by_name[
+ 'nested_factory_1_message'].message_type)
+ self.assertEquals(nested_enum1, msg1.fields_by_name[
+ 'nested_factory_1_enum'].enum_type)
+
+ msg2 = self.pool.FindMessageTypeByName(
+ 'google.protobuf.python.internal.Factory2Message')
+ self.assertIsInstance(msg2, descriptor.Descriptor)
+ self.assertEquals('Factory2Message', msg2.name)
+ self.assertEquals('google.protobuf.python.internal.Factory2Message',
+ msg2.full_name)
+ self.assertIsNone(msg2.containing_type)
+
+ nested_msg2 = msg2.nested_types[0]
+ self.assertEquals('NestedFactory2Message', nested_msg2.name)
+ self.assertEquals(msg2, nested_msg2.containing_type)
+
+ nested_enum2 = msg2.enum_types[0]
+ self.assertEquals('NestedFactory2Enum', nested_enum2.name)
+ self.assertEquals(msg2, nested_enum2.containing_type)
+
+ self.assertEquals(nested_msg2, msg2.fields_by_name[
+ 'nested_factory_2_message'].message_type)
+ self.assertEquals(nested_enum2, msg2.fields_by_name[
+ 'nested_factory_2_enum'].enum_type)
+
+ self.assertTrue(msg2.fields_by_name['int_with_default'].has_default_value)
+ self.assertEquals(
+ 1776, msg2.fields_by_name['int_with_default'].default_value)
+
+ self.assertTrue(
+ msg2.fields_by_name['double_with_default'].has_default_value)
+ self.assertEquals(
+ 9.99, msg2.fields_by_name['double_with_default'].default_value)
+
+ self.assertTrue(
+ msg2.fields_by_name['string_with_default'].has_default_value)
+ self.assertEquals(
+ 'hello world', msg2.fields_by_name['string_with_default'].default_value)
+
+ self.assertTrue(msg2.fields_by_name['bool_with_default'].has_default_value)
+ self.assertFalse(msg2.fields_by_name['bool_with_default'].default_value)
+
+ self.assertTrue(msg2.fields_by_name['enum_with_default'].has_default_value)
+ self.assertEquals(
+ 1, msg2.fields_by_name['enum_with_default'].default_value)
+
+ msg3 = self.pool.FindMessageTypeByName(
+ 'google.protobuf.python.internal.Factory2Message.NestedFactory2Message')
+ self.assertEquals(nested_msg2, msg3)
+
+ self.assertTrue(msg2.fields_by_name['bytes_with_default'].has_default_value)
+ self.assertEquals(
+ b'a\xfb\x00c',
+ msg2.fields_by_name['bytes_with_default'].default_value)
+
+ self.assertEqual(1, len(msg2.oneofs))
+ self.assertEqual(1, len(msg2.oneofs_by_name))
+ self.assertEqual(2, len(msg2.oneofs[0].fields))
+ for name in ['oneof_int', 'oneof_string']:
+ self.assertEqual(msg2.oneofs[0],
+ msg2.fields_by_name[name].containing_oneof)
+ self.assertIn(msg2.fields_by_name[name], msg2.oneofs[0].fields)
+
+ def testFindMessageTypeByNameFailure(self):
+ with self.assertRaises(KeyError):
+ self.pool.FindMessageTypeByName('Does not exist')
+
+ def testFindEnumTypeByName(self):
+ enum1 = self.pool.FindEnumTypeByName(
+ 'google.protobuf.python.internal.Factory1Enum')
+ self.assertIsInstance(enum1, descriptor.EnumDescriptor)
+ self.assertEquals(0, enum1.values_by_name['FACTORY_1_VALUE_0'].number)
+ self.assertEquals(1, enum1.values_by_name['FACTORY_1_VALUE_1'].number)
+
+ nested_enum1 = self.pool.FindEnumTypeByName(
+ 'google.protobuf.python.internal.Factory1Message.NestedFactory1Enum')
+ self.assertIsInstance(nested_enum1, descriptor.EnumDescriptor)
+ self.assertEquals(
+ 0, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_0'].number)
+ self.assertEquals(
+ 1, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_1'].number)
+
+ enum2 = self.pool.FindEnumTypeByName(
+ 'google.protobuf.python.internal.Factory2Enum')
+ self.assertIsInstance(enum2, descriptor.EnumDescriptor)
+ self.assertEquals(0, enum2.values_by_name['FACTORY_2_VALUE_0'].number)
+ self.assertEquals(1, enum2.values_by_name['FACTORY_2_VALUE_1'].number)
+
+ nested_enum2 = self.pool.FindEnumTypeByName(
+ 'google.protobuf.python.internal.Factory2Message.NestedFactory2Enum')
+ self.assertIsInstance(nested_enum2, descriptor.EnumDescriptor)
+ self.assertEquals(
+ 0, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_0'].number)
+ self.assertEquals(
+ 1, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_1'].number)
+
+ def testFindEnumTypeByNameFailure(self):
+ with self.assertRaises(KeyError):
+ self.pool.FindEnumTypeByName('Does not exist')
+
+ def testUserDefinedDB(self):
+ db = descriptor_database.DescriptorDatabase()
+ self.pool = descriptor_pool.DescriptorPool(db)
+ db.Add(self.factory_test1_fd)
+ db.Add(self.factory_test2_fd)
+ self.testFindMessageTypeByName()
+
+ def testComplexNesting(self):
+ test1_desc = descriptor_pb2.FileDescriptorProto.FromString(
+ descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
+ test2_desc = descriptor_pb2.FileDescriptorProto.FromString(
+ descriptor_pool_test2_pb2.DESCRIPTOR.serialized_pb)
+ self.pool.Add(test1_desc)
+ self.pool.Add(test2_desc)
+ TEST1_FILE.CheckFile(self, self.pool)
+ 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):
+
+ def __init__(self, name, package, messages, dependencies=None):
+ self.name = name
+ self.package = package
+ self.messages = messages
+ self.dependencies = dependencies or []
+
+ def CheckFile(self, test, pool):
+ file_desc = pool.FindFileByName(self.name)
+ test.assertEquals(self.name, file_desc.name)
+ test.assertEquals(self.package, file_desc.package)
+ dependencies_names = [f.name for f in file_desc.dependencies]
+ test.assertEqual(self.dependencies, dependencies_names)
+ for name, msg_type in self.messages.items():
+ msg_type.CheckType(test, None, name, file_desc)
+
+
+class EnumType(object):
+
+ def __init__(self, values):
+ self.values = values
+
+ def CheckType(self, test, msg_desc, name, file_desc):
+ enum_desc = msg_desc.enum_types_by_name[name]
+ test.assertEqual(name, enum_desc.name)
+ expected_enum_full_name = '.'.join([msg_desc.full_name, name])
+ test.assertEqual(expected_enum_full_name, enum_desc.full_name)
+ test.assertEqual(msg_desc, enum_desc.containing_type)
+ test.assertEqual(file_desc, enum_desc.file)
+ for index, (value, number) in enumerate(self.values):
+ value_desc = enum_desc.values_by_name[value]
+ test.assertEqual(value, value_desc.name)
+ test.assertEqual(index, value_desc.index)
+ test.assertEqual(number, value_desc.number)
+ test.assertEqual(enum_desc, value_desc.type)
+ test.assertIn(value, msg_desc.enum_values_by_name)
+
+
+class MessageType(object):
+
+ def __init__(self, type_dict, field_list, is_extendable=False,
+ extensions=None):
+ self.type_dict = type_dict
+ self.field_list = field_list
+ self.is_extendable = is_extendable
+ self.extensions = extensions or []
+
+ def CheckType(self, test, containing_type_desc, name, file_desc):
+ if containing_type_desc is None:
+ desc = file_desc.message_types_by_name[name]
+ expected_full_name = '.'.join([file_desc.package, name])
+ else:
+ desc = containing_type_desc.nested_types_by_name[name]
+ expected_full_name = '.'.join([containing_type_desc.full_name, name])
+
+ test.assertEqual(name, desc.name)
+ test.assertEqual(expected_full_name, desc.full_name)
+ test.assertEqual(containing_type_desc, desc.containing_type)
+ test.assertEqual(desc.file, file_desc)
+ test.assertEqual(self.is_extendable, desc.is_extendable)
+ for name, subtype in self.type_dict.items():
+ subtype.CheckType(test, desc, name, file_desc)
+
+ for index, (name, field) in enumerate(self.field_list):
+ field.CheckField(test, desc, name, index)
+
+ for index, (name, field) in enumerate(self.extensions):
+ field.CheckField(test, desc, name, index)
+
+
+class EnumField(object):
+
+ def __init__(self, number, type_name, default_value):
+ self.number = number
+ self.type_name = type_name
+ self.default_value = default_value
+
+ def CheckField(self, test, msg_desc, name, index):
+ field_desc = msg_desc.fields_by_name[name]
+ enum_desc = msg_desc.enum_types_by_name[self.type_name]
+ test.assertEqual(name, field_desc.name)
+ expected_field_full_name = '.'.join([msg_desc.full_name, name])
+ test.assertEqual(expected_field_full_name, field_desc.full_name)
+ test.assertEqual(index, field_desc.index)
+ test.assertEqual(self.number, field_desc.number)
+ test.assertEqual(descriptor.FieldDescriptor.TYPE_ENUM, field_desc.type)
+ 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].number,
+ field_desc.default_value)
+ test.assertEqual(msg_desc, field_desc.containing_type)
+ test.assertEqual(enum_desc, field_desc.enum_type)
+
+
+class MessageField(object):
+
+ def __init__(self, number, type_name):
+ self.number = number
+ self.type_name = type_name
+
+ def CheckField(self, test, msg_desc, name, index):
+ field_desc = msg_desc.fields_by_name[name]
+ field_type_desc = msg_desc.nested_types_by_name[self.type_name]
+ test.assertEqual(name, field_desc.name)
+ expected_field_full_name = '.'.join([msg_desc.full_name, name])
+ test.assertEqual(expected_field_full_name, field_desc.full_name)
+ test.assertEqual(index, field_desc.index)
+ test.assertEqual(self.number, field_desc.number)
+ test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
+ test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
+ field_desc.cpp_type)
+ test.assertFalse(field_desc.has_default_value)
+ test.assertEqual(msg_desc, field_desc.containing_type)
+ test.assertEqual(field_type_desc, field_desc.message_type)
+
+
+class StringField(object):
+
+ def __init__(self, number, default_value):
+ self.number = number
+ self.default_value = default_value
+
+ def CheckField(self, test, msg_desc, name, index):
+ field_desc = msg_desc.fields_by_name[name]
+ test.assertEqual(name, field_desc.name)
+ expected_field_full_name = '.'.join([msg_desc.full_name, name])
+ test.assertEqual(expected_field_full_name, field_desc.full_name)
+ test.assertEqual(index, field_desc.index)
+ test.assertEqual(self.number, field_desc.number)
+ test.assertEqual(descriptor.FieldDescriptor.TYPE_STRING, field_desc.type)
+ test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_STRING,
+ field_desc.cpp_type)
+ test.assertTrue(field_desc.has_default_value)
+ test.assertEqual(self.default_value, field_desc.default_value)
+
+
+class ExtensionField(object):
+
+ def __init__(self, number, extended_type):
+ self.number = number
+ self.extended_type = extended_type
+
+ def CheckField(self, test, msg_desc, name, index):
+ field_desc = msg_desc.extensions_by_name[name]
+ test.assertEqual(name, field_desc.name)
+ expected_field_full_name = '.'.join([msg_desc.full_name, name])
+ test.assertEqual(expected_field_full_name, field_desc.full_name)
+ test.assertEqual(self.number, field_desc.number)
+ test.assertEqual(index, field_desc.index)
+ test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
+ test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
+ field_desc.cpp_type)
+ test.assertFalse(field_desc.has_default_value)
+ test.assertTrue(field_desc.is_extension)
+ test.assertEqual(msg_desc, field_desc.extension_scope)
+ test.assertEqual(msg_desc, field_desc.message_type)
+ test.assertEqual(self.extended_type, field_desc.containing_type.name)
+
+
+class AddDescriptorTest(basetest.TestCase):
+
+ def _TestMessage(self, prefix):
+ pool = descriptor_pool.DescriptorPool()
+ pool.AddDescriptor(unittest_pb2.TestAllTypes.DESCRIPTOR)
+ self.assertEquals(
+ 'protobuf_unittest.TestAllTypes',
+ pool.FindMessageTypeByName(
+ prefix + 'protobuf_unittest.TestAllTypes').full_name)
+
+ # AddDescriptor is not recursive.
+ with self.assertRaises(KeyError):
+ pool.FindMessageTypeByName(
+ prefix + 'protobuf_unittest.TestAllTypes.NestedMessage')
+
+ pool.AddDescriptor(unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR)
+ self.assertEquals(
+ 'protobuf_unittest.TestAllTypes.NestedMessage',
+ pool.FindMessageTypeByName(
+ prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').full_name)
+
+ # Files are implicitly also indexed when messages are added.
+ self.assertEquals(
+ 'google/protobuf/unittest.proto',
+ pool.FindFileByName(
+ 'google/protobuf/unittest.proto').name)
+
+ self.assertEquals(
+ 'google/protobuf/unittest.proto',
+ pool.FindFileContainingSymbol(
+ prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name)
+
+ def testMessage(self):
+ self._TestMessage('')
+ self._TestMessage('.')
+
+ def _TestEnum(self, prefix):
+ pool = descriptor_pool.DescriptorPool()
+ pool.AddEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
+ self.assertEquals(
+ 'protobuf_unittest.ForeignEnum',
+ pool.FindEnumTypeByName(
+ prefix + 'protobuf_unittest.ForeignEnum').full_name)
+
+ # AddEnumDescriptor is not recursive.
+ with self.assertRaises(KeyError):
+ pool.FindEnumTypeByName(
+ prefix + 'protobuf_unittest.ForeignEnum.NestedEnum')
+
+ pool.AddEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
+ self.assertEquals(
+ 'protobuf_unittest.TestAllTypes.NestedEnum',
+ pool.FindEnumTypeByName(
+ prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
+
+ # Files are implicitly also indexed when enums are added.
+ self.assertEquals(
+ 'google/protobuf/unittest.proto',
+ pool.FindFileByName(
+ 'google/protobuf/unittest.proto').name)
+
+ self.assertEquals(
+ 'google/protobuf/unittest.proto',
+ pool.FindFileContainingSymbol(
+ prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name)
+
+ def testEnum(self):
+ self._TestEnum('')
+ self._TestEnum('.')
+
+ def testFile(self):
+ pool = descriptor_pool.DescriptorPool()
+ pool.AddFileDescriptor(unittest_pb2.DESCRIPTOR)
+ self.assertEquals(
+ 'google/protobuf/unittest.proto',
+ pool.FindFileByName(
+ 'google/protobuf/unittest.proto').name)
+
+ # AddFileDescriptor is not recursive; messages and enums within files must
+ # be explicitly registered.
+ with self.assertRaises(KeyError):
+ pool.FindFileContainingSymbol(
+ 'protobuf_unittest.TestAllTypes')
+
+
+TEST1_FILE = ProtoFile(
+ 'google/protobuf/internal/descriptor_pool_test1.proto',
+ 'google.protobuf.python.internal',
+ {
+ 'DescriptorPoolTest1': MessageType({
+ 'NestedEnum': EnumType([('ALPHA', 1), ('BETA', 2)]),
+ 'NestedMessage': MessageType({
+ 'NestedEnum': EnumType([('EPSILON', 5), ('ZETA', 6)]),
+ 'DeepNestedMessage': MessageType({
+ 'NestedEnum': EnumType([('ETA', 7), ('THETA', 8)]),
+ }, [
+ ('nested_enum', EnumField(1, 'NestedEnum', 'ETA')),
+ ('nested_field', StringField(2, 'theta')),
+ ]),
+ }, [
+ ('nested_enum', EnumField(1, 'NestedEnum', 'ZETA')),
+ ('nested_field', StringField(2, 'beta')),
+ ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
+ ])
+ }, [
+ ('nested_enum', EnumField(1, 'NestedEnum', 'BETA')),
+ ('nested_message', MessageField(2, 'NestedMessage')),
+ ], is_extendable=True),
+
+ 'DescriptorPoolTest2': MessageType({
+ 'NestedEnum': EnumType([('GAMMA', 3), ('DELTA', 4)]),
+ 'NestedMessage': MessageType({
+ 'NestedEnum': EnumType([('IOTA', 9), ('KAPPA', 10)]),
+ 'DeepNestedMessage': MessageType({
+ 'NestedEnum': EnumType([('LAMBDA', 11), ('MU', 12)]),
+ }, [
+ ('nested_enum', EnumField(1, 'NestedEnum', 'MU')),
+ ('nested_field', StringField(2, 'lambda')),
+ ]),
+ }, [
+ ('nested_enum', EnumField(1, 'NestedEnum', 'IOTA')),
+ ('nested_field', StringField(2, 'delta')),
+ ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
+ ])
+ }, [
+ ('nested_enum', EnumField(1, 'NestedEnum', 'GAMMA')),
+ ('nested_message', MessageField(2, 'NestedMessage')),
+ ]),
+ })
+
+
+TEST2_FILE = ProtoFile(
+ 'google/protobuf/internal/descriptor_pool_test2.proto',
+ 'google.protobuf.python.internal',
+ {
+ 'DescriptorPoolTest3': MessageType({
+ 'NestedEnum': EnumType([('NU', 13), ('XI', 14)]),
+ 'NestedMessage': MessageType({
+ 'NestedEnum': EnumType([('OMICRON', 15), ('PI', 16)]),
+ 'DeepNestedMessage': MessageType({
+ 'NestedEnum': EnumType([('RHO', 17), ('SIGMA', 18)]),
+ }, [
+ ('nested_enum', EnumField(1, 'NestedEnum', 'RHO')),
+ ('nested_field', StringField(2, 'sigma')),
+ ]),
+ }, [
+ ('nested_enum', EnumField(1, 'NestedEnum', 'PI')),
+ ('nested_field', StringField(2, 'nu')),
+ ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
+ ])
+ }, [
+ ('nested_enum', EnumField(1, 'NestedEnum', 'XI')),
+ ('nested_message', MessageField(2, 'NestedMessage')),
+ ], extensions=[
+ ('descriptor_pool_test',
+ ExtensionField(1001, 'DescriptorPoolTest1')),
+ ]),
+ },
+ dependencies=['google/protobuf/internal/descriptor_pool_test1.proto'])
+
+
+if __name__ == '__main__':
+ basetest.main()
diff --git a/python/google/protobuf/internal/descriptor_pool_test1.proto b/python/google/protobuf/internal/descriptor_pool_test1.proto
new file mode 100644
index 00000000..00816b78
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_pool_test1.proto
@@ -0,0 +1,96 @@
+// 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;
+
+
+message DescriptorPoolTest1 {
+ extensions 1000 to max;
+
+ enum NestedEnum {
+ ALPHA = 1;
+ BETA = 2;
+ }
+
+ optional NestedEnum nested_enum = 1 [default = BETA];
+
+ message NestedMessage {
+ enum NestedEnum {
+ EPSILON = 5;
+ ZETA = 6;
+ }
+ optional NestedEnum nested_enum = 1 [default = ZETA];
+ optional string nested_field = 2 [default = "beta"];
+ optional DeepNestedMessage deep_nested_message = 3;
+
+ message DeepNestedMessage {
+ enum NestedEnum {
+ ETA = 7;
+ THETA = 8;
+ }
+ optional NestedEnum nested_enum = 1 [default = ETA];
+ optional string nested_field = 2 [default = "theta"];
+ }
+ }
+
+ optional NestedMessage nested_message = 2;
+}
+
+message DescriptorPoolTest2 {
+ enum NestedEnum {
+ GAMMA = 3;
+ DELTA = 4;
+ }
+
+ optional NestedEnum nested_enum = 1 [default = GAMMA];
+
+ message NestedMessage {
+ enum NestedEnum {
+ IOTA = 9;
+ KAPPA = 10;
+ }
+ optional NestedEnum nested_enum = 1 [default = IOTA];
+ optional string nested_field = 2 [default = "delta"];
+ optional DeepNestedMessage deep_nested_message = 3;
+
+ message DeepNestedMessage {
+ enum NestedEnum {
+ LAMBDA = 11;
+ MU = 12;
+ }
+ optional NestedEnum nested_enum = 1 [default = MU];
+ optional string nested_field = 2 [default = "lambda"];
+ }
+ }
+
+ optional NestedMessage nested_message = 2;
+}
diff --git a/python/google/protobuf/internal/descriptor_pool_test2.proto b/python/google/protobuf/internal/descriptor_pool_test2.proto
new file mode 100644
index 00000000..e3fa660c
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_pool_test2.proto
@@ -0,0 +1,72 @@
+// 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 "google/protobuf/internal/descriptor_pool_test1.proto";
+
+
+message DescriptorPoolTest3 {
+
+ extend DescriptorPoolTest1 {
+ optional DescriptorPoolTest3 descriptor_pool_test = 1001;
+ }
+
+ enum NestedEnum {
+ NU = 13;
+ XI = 14;
+ }
+
+ optional NestedEnum nested_enum = 1 [default = XI];
+
+ message NestedMessage {
+ enum NestedEnum {
+ OMICRON = 15;
+ PI = 16;
+ }
+ optional NestedEnum nested_enum = 1 [default = PI];
+ optional string nested_field = 2 [default = "nu"];
+ optional DeepNestedMessage deep_nested_message = 3;
+
+ message DeepNestedMessage {
+ enum NestedEnum {
+ RHO = 17;
+ SIGMA = 18;
+ }
+ optional NestedEnum nested_enum = 1 [default = RHO];
+ optional string nested_field = 2 [default = "sigma"];
+ }
+ }
+
+ optional NestedMessage nested_message = 2;
+}
+
diff --git a/python/google/protobuf/internal/descriptor_python_test.py b/python/google/protobuf/internal/descriptor_python_test.py
new file mode 100644
index 00000000..5471ae02
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_python_test.py
@@ -0,0 +1,54 @@
+#! /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.
+
+"""Unittest for descriptor.py for the pure Python implementation."""
+
+import os
+os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'python'
+
+# We must set the implementation version above before the google3 imports.
+# pylint: disable=g-import-not-at-top
+from google.apputils import basetest
+from google.protobuf.internal import api_implementation
+# Run all tests from the original module by putting them in our namespace.
+# pylint: disable=wildcard-import
+from google.protobuf.internal.descriptor_test import *
+
+
+class ConfirmPurePythonTest(basetest.TestCase):
+
+ def testImplementationSetting(self):
+ self.assertEqual('python', api_implementation.Type())
+
+
+if __name__ == '__main__':
+ basetest.main()
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index 05c27452..50c4dbba 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -2,7 +2,7 @@
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -34,11 +34,16 @@
__author__ = 'robinson@google.com (Will Robinson)'
-import unittest
+import sys
+
+from google.apputils import basetest
+from google.protobuf import unittest_custom_options_pb2
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_pb2
from google.protobuf import descriptor_pb2
+from google.protobuf.internal import api_implementation
from google.protobuf import descriptor
+from google.protobuf import symbol_database
from google.protobuf import text_format
@@ -47,44 +52,31 @@ name: 'TestEmptyMessage'
"""
-class DescriptorTest(unittest.TestCase):
+class DescriptorTest(basetest.TestCase):
def setUp(self):
- self.my_file = descriptor.FileDescriptor(
+ file_proto = descriptor_pb2.FileDescriptorProto(
name='some/filename/some.proto',
- package='protobuf_unittest'
- )
- self.my_enum = descriptor.EnumDescriptor(
- name='ForeignEnum',
- full_name='protobuf_unittest.ForeignEnum',
- filename=None,
- file=self.my_file,
- values=[
- descriptor.EnumValueDescriptor(name='FOREIGN_FOO', index=0, number=4),
- descriptor.EnumValueDescriptor(name='FOREIGN_BAR', index=1, number=5),
- descriptor.EnumValueDescriptor(name='FOREIGN_BAZ', index=2, number=6),
- ])
- self.my_message = descriptor.Descriptor(
- name='NestedMessage',
- full_name='protobuf_unittest.TestAllTypes.NestedMessage',
- filename=None,
- file=self.my_file,
- containing_type=None,
- fields=[
- descriptor.FieldDescriptor(
- name='bb',
- full_name='protobuf_unittest.TestAllTypes.NestedMessage.bb',
- index=0, number=1,
- type=5, cpp_type=1, label=1,
- has_default_value=False, default_value=0,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None),
- ],
- nested_types=[],
- enum_types=[
- self.my_enum,
- ],
- extensions=[])
+ package='protobuf_unittest')
+ message_proto = file_proto.message_type.add(
+ name='NestedMessage')
+ message_proto.field.add(
+ name='bb',
+ number=1,
+ type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32,
+ label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL)
+ enum_proto = message_proto.enum_type.add(
+ name='ForeignEnum')
+ enum_proto.value.add(name='FOREIGN_FOO', number=4)
+ enum_proto.value.add(name='FOREIGN_BAR', number=5)
+ enum_proto.value.add(name='FOREIGN_BAZ', number=6)
+
+ descriptor_pool = symbol_database.Default().pool
+ descriptor_pool.Add(file_proto)
+ self.my_file = descriptor_pool.FindFileByName(file_proto.name)
+ self.my_message = self.my_file.message_types_by_name[message_proto.name]
+ self.my_enum = self.my_message.enum_types_by_name[enum_proto.name]
+
self.my_method = descriptor.MethodDescriptor(
name='Bar',
full_name='protobuf_unittest.TestService.Bar',
@@ -101,6 +93,15 @@ class DescriptorTest(unittest.TestCase):
self.my_method
])
+ def testEnumValueName(self):
+ self.assertEqual(self.my_message.EnumValueName('ForeignEnum', 4),
+ 'FOREIGN_FOO')
+
+ self.assertEqual(
+ self.my_message.enum_types_by_name[
+ 'ForeignEnum'].values_by_number[4].name,
+ self.my_message.EnumValueName('ForeignEnum', 4))
+
def testEnumFixups(self):
self.assertEqual(self.my_enum, self.my_enum.values[0].type)
@@ -125,6 +126,262 @@ class DescriptorTest(unittest.TestCase):
self.assertEqual(self.my_service.GetOptions(),
descriptor_pb2.ServiceOptions())
+ def testSimpleCustomOptions(self):
+ file_descriptor = unittest_custom_options_pb2.DESCRIPTOR
+ message_descriptor =\
+ unittest_custom_options_pb2.TestMessageWithCustomOptions.DESCRIPTOR
+ field_descriptor = message_descriptor.fields_by_name["field1"]
+ enum_descriptor = message_descriptor.enum_types_by_name["AnEnum"]
+ enum_value_descriptor =\
+ message_descriptor.enum_values_by_name["ANENUM_VAL2"]
+ service_descriptor =\
+ unittest_custom_options_pb2.TestServiceWithCustomOptions.DESCRIPTOR
+ method_descriptor = service_descriptor.FindMethodByName("Foo")
+
+ file_options = file_descriptor.GetOptions()
+ file_opt1 = unittest_custom_options_pb2.file_opt1
+ self.assertEqual(9876543210, file_options.Extensions[file_opt1])
+ message_options = message_descriptor.GetOptions()
+ message_opt1 = unittest_custom_options_pb2.message_opt1
+ self.assertEqual(-56, message_options.Extensions[message_opt1])
+ field_options = field_descriptor.GetOptions()
+ field_opt1 = unittest_custom_options_pb2.field_opt1
+ self.assertEqual(8765432109, field_options.Extensions[field_opt1])
+ field_opt2 = unittest_custom_options_pb2.field_opt2
+ self.assertEqual(42, field_options.Extensions[field_opt2])
+ enum_options = enum_descriptor.GetOptions()
+ enum_opt1 = unittest_custom_options_pb2.enum_opt1
+ self.assertEqual(-789, enum_options.Extensions[enum_opt1])
+ enum_value_options = enum_value_descriptor.GetOptions()
+ enum_value_opt1 = unittest_custom_options_pb2.enum_value_opt1
+ self.assertEqual(123, enum_value_options.Extensions[enum_value_opt1])
+
+ service_options = service_descriptor.GetOptions()
+ service_opt1 = unittest_custom_options_pb2.service_opt1
+ self.assertEqual(-9876543210, service_options.Extensions[service_opt1])
+ method_options = method_descriptor.GetOptions()
+ method_opt1 = unittest_custom_options_pb2.method_opt1
+ self.assertEqual(unittest_custom_options_pb2.METHODOPT1_VAL2,
+ method_options.Extensions[method_opt1])
+
+ message_descriptor = (
+ unittest_custom_options_pb2.DummyMessageContainingEnum.DESCRIPTOR)
+ self.assertTrue(file_descriptor.has_options)
+ self.assertFalse(message_descriptor.has_options)
+
+ def testDifferentCustomOptionTypes(self):
+ kint32min = -2**31
+ kint64min = -2**63
+ kint32max = 2**31 - 1
+ kint64max = 2**63 - 1
+ kuint32max = 2**32 - 1
+ kuint64max = 2**64 - 1
+
+ message_descriptor =\
+ unittest_custom_options_pb2.CustomOptionMinIntegerValues.DESCRIPTOR
+ message_options = message_descriptor.GetOptions()
+ self.assertEqual(False, message_options.Extensions[
+ unittest_custom_options_pb2.bool_opt])
+ self.assertEqual(kint32min, message_options.Extensions[
+ unittest_custom_options_pb2.int32_opt])
+ self.assertEqual(kint64min, message_options.Extensions[
+ unittest_custom_options_pb2.int64_opt])
+ self.assertEqual(0, message_options.Extensions[
+ unittest_custom_options_pb2.uint32_opt])
+ self.assertEqual(0, message_options.Extensions[
+ unittest_custom_options_pb2.uint64_opt])
+ self.assertEqual(kint32min, message_options.Extensions[
+ unittest_custom_options_pb2.sint32_opt])
+ self.assertEqual(kint64min, message_options.Extensions[
+ unittest_custom_options_pb2.sint64_opt])
+ self.assertEqual(0, message_options.Extensions[
+ unittest_custom_options_pb2.fixed32_opt])
+ self.assertEqual(0, message_options.Extensions[
+ unittest_custom_options_pb2.fixed64_opt])
+ self.assertEqual(kint32min, message_options.Extensions[
+ unittest_custom_options_pb2.sfixed32_opt])
+ self.assertEqual(kint64min, message_options.Extensions[
+ unittest_custom_options_pb2.sfixed64_opt])
+
+ message_descriptor =\
+ unittest_custom_options_pb2.CustomOptionMaxIntegerValues.DESCRIPTOR
+ message_options = message_descriptor.GetOptions()
+ self.assertEqual(True, message_options.Extensions[
+ unittest_custom_options_pb2.bool_opt])
+ self.assertEqual(kint32max, message_options.Extensions[
+ unittest_custom_options_pb2.int32_opt])
+ self.assertEqual(kint64max, message_options.Extensions[
+ unittest_custom_options_pb2.int64_opt])
+ self.assertEqual(kuint32max, message_options.Extensions[
+ unittest_custom_options_pb2.uint32_opt])
+ self.assertEqual(kuint64max, message_options.Extensions[
+ unittest_custom_options_pb2.uint64_opt])
+ self.assertEqual(kint32max, message_options.Extensions[
+ unittest_custom_options_pb2.sint32_opt])
+ self.assertEqual(kint64max, message_options.Extensions[
+ unittest_custom_options_pb2.sint64_opt])
+ self.assertEqual(kuint32max, message_options.Extensions[
+ unittest_custom_options_pb2.fixed32_opt])
+ self.assertEqual(kuint64max, message_options.Extensions[
+ unittest_custom_options_pb2.fixed64_opt])
+ self.assertEqual(kint32max, message_options.Extensions[
+ unittest_custom_options_pb2.sfixed32_opt])
+ self.assertEqual(kint64max, message_options.Extensions[
+ unittest_custom_options_pb2.sfixed64_opt])
+
+ message_descriptor =\
+ unittest_custom_options_pb2.CustomOptionOtherValues.DESCRIPTOR
+ message_options = message_descriptor.GetOptions()
+ self.assertEqual(-100, message_options.Extensions[
+ unittest_custom_options_pb2.int32_opt])
+ self.assertAlmostEqual(12.3456789, message_options.Extensions[
+ unittest_custom_options_pb2.float_opt], 6)
+ self.assertAlmostEqual(1.234567890123456789, message_options.Extensions[
+ unittest_custom_options_pb2.double_opt])
+ self.assertEqual("Hello, \"World\"", message_options.Extensions[
+ unittest_custom_options_pb2.string_opt])
+ self.assertEqual(b"Hello\0World", message_options.Extensions[
+ unittest_custom_options_pb2.bytes_opt])
+ dummy_enum = unittest_custom_options_pb2.DummyMessageContainingEnum
+ self.assertEqual(
+ dummy_enum.TEST_OPTION_ENUM_TYPE2,
+ message_options.Extensions[unittest_custom_options_pb2.enum_opt])
+
+ message_descriptor =\
+ unittest_custom_options_pb2.SettingRealsFromPositiveInts.DESCRIPTOR
+ message_options = message_descriptor.GetOptions()
+ self.assertAlmostEqual(12, message_options.Extensions[
+ unittest_custom_options_pb2.float_opt], 6)
+ self.assertAlmostEqual(154, message_options.Extensions[
+ unittest_custom_options_pb2.double_opt])
+
+ message_descriptor =\
+ unittest_custom_options_pb2.SettingRealsFromNegativeInts.DESCRIPTOR
+ message_options = message_descriptor.GetOptions()
+ self.assertAlmostEqual(-12, message_options.Extensions[
+ unittest_custom_options_pb2.float_opt], 6)
+ self.assertAlmostEqual(-154, message_options.Extensions[
+ unittest_custom_options_pb2.double_opt])
+
+ def testComplexExtensionOptions(self):
+ descriptor =\
+ unittest_custom_options_pb2.VariousComplexOptions.DESCRIPTOR
+ options = descriptor.GetOptions()
+ self.assertEqual(42, options.Extensions[
+ unittest_custom_options_pb2.complex_opt1].foo)
+ self.assertEqual(324, options.Extensions[
+ unittest_custom_options_pb2.complex_opt1].Extensions[
+ unittest_custom_options_pb2.quux])
+ self.assertEqual(876, options.Extensions[
+ unittest_custom_options_pb2.complex_opt1].Extensions[
+ unittest_custom_options_pb2.corge].qux)
+ self.assertEqual(987, options.Extensions[
+ unittest_custom_options_pb2.complex_opt2].baz)
+ self.assertEqual(654, options.Extensions[
+ unittest_custom_options_pb2.complex_opt2].Extensions[
+ unittest_custom_options_pb2.grault])
+ self.assertEqual(743, options.Extensions[
+ unittest_custom_options_pb2.complex_opt2].bar.foo)
+ self.assertEqual(1999, options.Extensions[
+ unittest_custom_options_pb2.complex_opt2].bar.Extensions[
+ unittest_custom_options_pb2.quux])
+ self.assertEqual(2008, options.Extensions[
+ unittest_custom_options_pb2.complex_opt2].bar.Extensions[
+ unittest_custom_options_pb2.corge].qux)
+ self.assertEqual(741, options.Extensions[
+ unittest_custom_options_pb2.complex_opt2].Extensions[
+ unittest_custom_options_pb2.garply].foo)
+ self.assertEqual(1998, options.Extensions[
+ unittest_custom_options_pb2.complex_opt2].Extensions[
+ unittest_custom_options_pb2.garply].Extensions[
+ unittest_custom_options_pb2.quux])
+ self.assertEqual(2121, options.Extensions[
+ unittest_custom_options_pb2.complex_opt2].Extensions[
+ unittest_custom_options_pb2.garply].Extensions[
+ unittest_custom_options_pb2.corge].qux)
+ self.assertEqual(1971, options.Extensions[
+ unittest_custom_options_pb2.ComplexOptionType2
+ .ComplexOptionType4.complex_opt4].waldo)
+ self.assertEqual(321, options.Extensions[
+ unittest_custom_options_pb2.complex_opt2].fred.waldo)
+ self.assertEqual(9, options.Extensions[
+ unittest_custom_options_pb2.complex_opt3].qux)
+ self.assertEqual(22, options.Extensions[
+ unittest_custom_options_pb2.complex_opt3].complexoptiontype5.plugh)
+ self.assertEqual(24, options.Extensions[
+ unittest_custom_options_pb2.complexopt6].xyzzy)
+
+ # Check that aggregate options were parsed and saved correctly in
+ # the appropriate descriptors.
+ def testAggregateOptions(self):
+ file_descriptor = unittest_custom_options_pb2.DESCRIPTOR
+ message_descriptor =\
+ unittest_custom_options_pb2.AggregateMessage.DESCRIPTOR
+ field_descriptor = message_descriptor.fields_by_name["fieldname"]
+ enum_descriptor = unittest_custom_options_pb2.AggregateEnum.DESCRIPTOR
+ enum_value_descriptor = enum_descriptor.values_by_name["VALUE"]
+ service_descriptor =\
+ unittest_custom_options_pb2.AggregateService.DESCRIPTOR
+ method_descriptor = service_descriptor.FindMethodByName("Method")
+
+ # Tests for the different types of data embedded in fileopt
+ file_options = file_descriptor.GetOptions().Extensions[
+ unittest_custom_options_pb2.fileopt]
+ self.assertEqual(100, file_options.i)
+ self.assertEqual("FileAnnotation", file_options.s)
+ self.assertEqual("NestedFileAnnotation", file_options.sub.s)
+ self.assertEqual("FileExtensionAnnotation", file_options.file.Extensions[
+ unittest_custom_options_pb2.fileopt].s)
+ self.assertEqual("EmbeddedMessageSetElement", file_options.mset.Extensions[
+ unittest_custom_options_pb2.AggregateMessageSetElement
+ .message_set_extension].s)
+
+ # Simple tests for all the other types of annotations
+ self.assertEqual(
+ "MessageAnnotation",
+ message_descriptor.GetOptions().Extensions[
+ unittest_custom_options_pb2.msgopt].s)
+ self.assertEqual(
+ "FieldAnnotation",
+ field_descriptor.GetOptions().Extensions[
+ unittest_custom_options_pb2.fieldopt].s)
+ self.assertEqual(
+ "EnumAnnotation",
+ enum_descriptor.GetOptions().Extensions[
+ unittest_custom_options_pb2.enumopt].s)
+ self.assertEqual(
+ "EnumValueAnnotation",
+ enum_value_descriptor.GetOptions().Extensions[
+ unittest_custom_options_pb2.enumvalopt].s)
+ self.assertEqual(
+ "ServiceAnnotation",
+ service_descriptor.GetOptions().Extensions[
+ unittest_custom_options_pb2.serviceopt].s)
+ self.assertEqual(
+ "MethodAnnotation",
+ method_descriptor.GetOptions().Extensions[
+ unittest_custom_options_pb2.methodopt].s)
+
+ def testNestedOptions(self):
+ nested_message =\
+ unittest_custom_options_pb2.NestedOptionType.NestedMessage.DESCRIPTOR
+ self.assertEqual(1001, nested_message.GetOptions().Extensions[
+ unittest_custom_options_pb2.message_opt1])
+ nested_field = nested_message.fields_by_name["nested_field"]
+ self.assertEqual(1002, nested_field.GetOptions().Extensions[
+ unittest_custom_options_pb2.field_opt1])
+ outer_message =\
+ unittest_custom_options_pb2.NestedOptionType.DESCRIPTOR
+ nested_enum = outer_message.enum_types_by_name["NestedEnum"]
+ self.assertEqual(1003, nested_enum.GetOptions().Extensions[
+ unittest_custom_options_pb2.enum_opt1])
+ nested_enum_value = outer_message.enum_values_by_name["NESTED_ENUM_VALUE"]
+ self.assertEqual(1004, nested_enum_value.GetOptions().Extensions[
+ unittest_custom_options_pb2.enum_value_opt1])
+ nested_extension = outer_message.extensions_by_name["nested_extension"]
+ self.assertEqual(1005, nested_extension.GetOptions().Extensions[
+ unittest_custom_options_pb2.field_opt2])
+
def testFileDescriptorReferences(self):
self.assertEqual(self.my_enum.file, self.my_file)
self.assertEqual(self.my_message.file, self.my_file)
@@ -133,8 +390,110 @@ class DescriptorTest(unittest.TestCase):
self.assertEqual(self.my_file.name, 'some/filename/some.proto')
self.assertEqual(self.my_file.package, 'protobuf_unittest')
-
-class DescriptorCopyToProtoTest(unittest.TestCase):
+ @basetest.unittest.skipIf(
+ api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
+ 'Immutability of descriptors is only enforced in v2 implementation')
+ def testImmutableCppDescriptor(self):
+ message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+ with self.assertRaises(AttributeError):
+ message_descriptor.fields_by_name = None
+ with self.assertRaises(TypeError):
+ message_descriptor.fields_by_name['Another'] = None
+ with self.assertRaises(TypeError):
+ message_descriptor.fields.append(None)
+
+
+class GeneratedDescriptorTest(basetest.TestCase):
+ """Tests for the properties of descriptors in generated code."""
+
+ def CheckMessageDescriptor(self, message_descriptor):
+ # Basic properties
+ self.assertEqual(message_descriptor.name, 'TestAllTypes')
+ self.assertEqual(message_descriptor.full_name,
+ 'protobuf_unittest.TestAllTypes')
+ # Test equality and hashability
+ self.assertEqual(message_descriptor, message_descriptor)
+ self.assertEqual(message_descriptor.fields[0].containing_type,
+ message_descriptor)
+ self.assertIn(message_descriptor, [message_descriptor])
+ self.assertIn(message_descriptor, {message_descriptor: None})
+ # Test field containers
+ self.CheckDescriptorSequence(message_descriptor.fields)
+ self.CheckDescriptorMapping(message_descriptor.fields_by_name)
+ self.CheckDescriptorMapping(message_descriptor.fields_by_number)
+
+ def CheckFieldDescriptor(self, field_descriptor):
+ # Basic properties
+ self.assertEqual(field_descriptor.name, 'optional_int32')
+ self.assertEqual(field_descriptor.full_name,
+ 'protobuf_unittest.TestAllTypes.optional_int32')
+ self.assertEqual(field_descriptor.containing_type.name, 'TestAllTypes')
+ # Test equality and hashability
+ self.assertEqual(field_descriptor, field_descriptor)
+ self.assertEqual(
+ field_descriptor.containing_type.fields_by_name['optional_int32'],
+ field_descriptor)
+ self.assertIn(field_descriptor, [field_descriptor])
+ self.assertIn(field_descriptor, {field_descriptor: None})
+
+ def CheckDescriptorSequence(self, sequence):
+ # Verifies that a property like 'messageDescriptor.fields' has all the
+ # properties of an immutable abc.Sequence.
+ self.assertGreater(len(sequence), 0) # Sized
+ self.assertEqual(len(sequence), len(list(sequence))) # Iterable
+ item = sequence[0]
+ self.assertEqual(item, sequence[0])
+ self.assertIn(item, sequence) # Container
+ self.assertEqual(sequence.index(item), 0)
+ self.assertEqual(sequence.count(item), 1)
+ reversed_iterator = reversed(sequence)
+ self.assertEqual(list(reversed_iterator), list(sequence)[::-1])
+ self.assertRaises(StopIteration, next, reversed_iterator)
+
+ def CheckDescriptorMapping(self, mapping):
+ # Verifies that a property like 'messageDescriptor.fields' has all the
+ # properties of an immutable abc.Mapping.
+ self.assertGreater(len(mapping), 0) # Sized
+ self.assertEqual(len(mapping), len(list(mapping))) # Iterable
+ if sys.version_info.major >= 3:
+ key, item = next(iter(mapping.items()))
+ else:
+ key, item = mapping.items()[0]
+ self.assertIn(key, mapping) # Container
+ self.assertEqual(mapping.get(key), item)
+ # keys(), iterkeys() &co
+ item = (next(iter(mapping.keys())), next(iter(mapping.values())))
+ self.assertEqual(item, next(iter(mapping.items())))
+ if sys.version_info.major < 3:
+ def CheckItems(seq, iterator):
+ self.assertEqual(next(iterator), seq[0])
+ self.assertEqual(list(iterator), seq[1:])
+ CheckItems(mapping.keys(), mapping.iterkeys())
+ CheckItems(mapping.values(), mapping.itervalues())
+ CheckItems(mapping.items(), mapping.iteritems())
+
+ def testDescriptor(self):
+ message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+ self.CheckMessageDescriptor(message_descriptor)
+ field_descriptor = message_descriptor.fields_by_name['optional_int32']
+ self.CheckFieldDescriptor(field_descriptor)
+
+ def testCppDescriptorContainer(self):
+ # Check that the collection is still valid even if the parent disappeared.
+ enum = unittest_pb2.TestAllTypes.DESCRIPTOR.enum_types_by_name['NestedEnum']
+ values = enum.values
+ del enum
+ self.assertEqual('FOO', values[0].name)
+
+ def testCppDescriptorContainer_Iterator(self):
+ # Same test with the iterator
+ enum = unittest_pb2.TestAllTypes.DESCRIPTOR.enum_types_by_name['NestedEnum']
+ values_iter = iter(enum.values)
+ del enum
+ self.assertEqual('FOO', next(values_iter).name)
+
+
+class DescriptorCopyToProtoTest(basetest.TestCase):
"""Tests for CopyTo functions of Descriptor."""
def _AssertProtoEqual(self, actual_proto, expected_class, expected_ascii):
@@ -269,45 +628,49 @@ class DescriptorCopyToProtoTest(unittest.TestCase):
descriptor_pb2.DescriptorProto,
TEST_MESSAGE_WITH_SEVERAL_EXTENSIONS_ASCII)
- def testCopyToProto_FileDescriptor(self):
- UNITTEST_IMPORT_FILE_DESCRIPTOR_ASCII = ("""
- name: 'google/protobuf/unittest_import.proto'
- package: 'protobuf_unittest_import'
- message_type: <
- name: 'ImportMessage'
- field: <
- name: 'd'
- number: 1
- label: 1 # Optional
- type: 5 # TYPE_INT32
- >
- >
- """ +
- """enum_type: <
- name: 'ImportEnum'
- value: <
- name: 'IMPORT_FOO'
- number: 7
- >
- value: <
- name: 'IMPORT_BAR'
- number: 8
- >
- value: <
- name: 'IMPORT_BAZ'
- number: 9
- >
- >
- options: <
- java_package: 'com.google.protobuf.test'
- optimize_for: 1 # SPEED
- >
- """)
-
- self._InternalTestCopyToProto(
- unittest_import_pb2.DESCRIPTOR,
- descriptor_pb2.FileDescriptorProto,
- UNITTEST_IMPORT_FILE_DESCRIPTOR_ASCII)
+ # Disable this test so we can make changes to the proto file.
+ # TODO(xiaofeng): Enable this test after cl/55530659 is submitted.
+ #
+ # def testCopyToProto_FileDescriptor(self):
+ # UNITTEST_IMPORT_FILE_DESCRIPTOR_ASCII = ("""
+ # name: 'google/protobuf/unittest_import.proto'
+ # package: 'protobuf_unittest_import'
+ # dependency: 'google/protobuf/unittest_import_public.proto'
+ # message_type: <
+ # name: 'ImportMessage'
+ # field: <
+ # name: 'd'
+ # number: 1
+ # label: 1 # Optional
+ # type: 5 # TYPE_INT32
+ # >
+ # >
+ # """ +
+ # """enum_type: <
+ # name: 'ImportEnum'
+ # value: <
+ # name: 'IMPORT_FOO'
+ # number: 7
+ # >
+ # value: <
+ # name: 'IMPORT_BAR'
+ # number: 8
+ # >
+ # value: <
+ # name: 'IMPORT_BAZ'
+ # number: 9
+ # >
+ # >
+ # options: <
+ # java_package: 'com.google.protobuf.test'
+ # optimize_for: 1 # SPEED
+ # >
+ # public_dependency: 0
+ # """)
+ # self._InternalTestCopyToProto(
+ # unittest_import_pb2.DESCRIPTOR,
+ # descriptor_pb2.FileDescriptorProto,
+ # UNITTEST_IMPORT_FILE_DESCRIPTOR_ASCII)
def testCopyToProto_ServiceDescriptor(self):
TEST_SERVICE_ASCII = """
@@ -323,12 +686,94 @@ class DescriptorCopyToProtoTest(unittest.TestCase):
output_type: '.protobuf_unittest.BarResponse'
>
"""
-
- self._InternalTestCopyToProto(
- unittest_pb2.TestService.DESCRIPTOR,
- descriptor_pb2.ServiceDescriptorProto,
- TEST_SERVICE_ASCII)
-
+ # TODO(rocking): enable this test after the proto descriptor change is
+ # checked in.
+ #self._InternalTestCopyToProto(
+ # unittest_pb2.TestService.DESCRIPTOR,
+ # descriptor_pb2.ServiceDescriptorProto,
+ # TEST_SERVICE_ASCII)
+
+
+class MakeDescriptorTest(basetest.TestCase):
+
+ def testMakeDescriptorWithNestedFields(self):
+ file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
+ file_descriptor_proto.name = 'Foo2'
+ message_type = file_descriptor_proto.message_type.add()
+ message_type.name = file_descriptor_proto.name
+ nested_type = message_type.nested_type.add()
+ nested_type.name = 'Sub'
+ enum_type = nested_type.enum_type.add()
+ enum_type.name = 'FOO'
+ enum_type_val = enum_type.value.add()
+ enum_type_val.name = 'BAR'
+ enum_type_val.number = 3
+ field = message_type.field.add()
+ field.number = 1
+ field.name = 'uint64_field'
+ field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+ field.type = descriptor.FieldDescriptor.TYPE_UINT64
+ field = message_type.field.add()
+ field.number = 2
+ field.name = 'nested_message_field'
+ field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+ field.type = descriptor.FieldDescriptor.TYPE_MESSAGE
+ field.type_name = 'Sub'
+ enum_field = nested_type.field.add()
+ enum_field.number = 2
+ enum_field.name = 'bar_field'
+ enum_field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+ enum_field.type = descriptor.FieldDescriptor.TYPE_ENUM
+ enum_field.type_name = 'Foo2.Sub.FOO'
+
+ result = descriptor.MakeDescriptor(message_type)
+ self.assertEqual(result.fields[0].cpp_type,
+ descriptor.FieldDescriptor.CPPTYPE_UINT64)
+ self.assertEqual(result.fields[1].cpp_type,
+ descriptor.FieldDescriptor.CPPTYPE_MESSAGE)
+ self.assertEqual(result.fields[1].message_type.containing_type,
+ result)
+ self.assertEqual(result.nested_types[0].fields[0].full_name,
+ 'Foo2.Sub.bar_field')
+ self.assertEqual(result.nested_types[0].fields[0].enum_type,
+ result.nested_types[0].enum_types[0])
+
+ def testMakeDescriptorWithUnsignedIntField(self):
+ file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
+ file_descriptor_proto.name = 'Foo'
+ message_type = file_descriptor_proto.message_type.add()
+ message_type.name = file_descriptor_proto.name
+ enum_type = message_type.enum_type.add()
+ enum_type.name = 'FOO'
+ enum_type_val = enum_type.value.add()
+ enum_type_val.name = 'BAR'
+ enum_type_val.number = 3
+ field = message_type.field.add()
+ field.number = 1
+ field.name = 'uint64_field'
+ field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+ field.type = descriptor.FieldDescriptor.TYPE_UINT64
+ enum_field = message_type.field.add()
+ enum_field.number = 2
+ enum_field.name = 'bar_field'
+ enum_field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+ enum_field.type = descriptor.FieldDescriptor.TYPE_ENUM
+ enum_field.type_name = 'Foo.FOO'
+
+ result = descriptor.MakeDescriptor(message_type)
+ self.assertEqual(result.fields[0].cpp_type,
+ 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__':
- unittest.main()
+ basetest.main()
diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py
index 777975e8..38a5138a 100755
--- a/python/google/protobuf/internal/encoder.py
+++ b/python/google/protobuf/internal/encoder.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -28,6 +28,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#PY25 compatible for GAE.
+#
+# Copyright 2009 Google Inc. All Rights Reserved.
+
"""Code for encoding protocol message primitives.
Contains the logic for encoding every logical protocol field type
@@ -67,6 +71,8 @@ sizer rather than when calling them. In particular:
__author__ = 'kenton@google.com (Kenton Varda)'
import struct
+import sys ##PY25
+_PY2 = sys.version_info[0] < 3 ##PY25
from google.protobuf.internal import wire_format
@@ -340,7 +346,8 @@ def MessageSetItemSizer(field_number):
def _VarintEncoder():
"""Return an encoder for a basic varint value (does not include tag)."""
- local_chr = chr
+ local_chr = _PY2 and chr or (lambda x: bytes((x,))) ##PY25
+##!PY25 local_chr = chr if bytes is str else lambda x: bytes((x,))
def EncodeVarint(write, value):
bits = value & 0x7f
value >>= 7
@@ -357,7 +364,8 @@ def _SignedVarintEncoder():
"""Return an encoder for a basic signed varint value (does not include
tag)."""
- local_chr = chr
+ local_chr = _PY2 and chr or (lambda x: bytes((x,))) ##PY25
+##!PY25 local_chr = chr if bytes is str else lambda x: bytes((x,))
def EncodeSignedVarint(write, value):
if value < 0:
value += (1 << 64)
@@ -382,7 +390,8 @@ def _VarintBytes(value):
pieces = []
_EncodeVarint(pieces.append, value)
- return "".join(pieces)
+ return "".encode("latin1").join(pieces) ##PY25
+##!PY25 return b"".join(pieces)
def TagBytes(field_number, wire_type):
@@ -520,26 +529,33 @@ def _FloatingPointEncoder(wire_type, format):
format: The format string to pass to struct.pack().
"""
+ b = _PY2 and (lambda x:x) or (lambda x:x.encode('latin1')) ##PY25
value_size = struct.calcsize(format)
if value_size == 4:
def EncodeNonFiniteOrRaise(write, value):
# Remember that the serialized form uses little-endian byte order.
if value == _POS_INF:
- write('\x00\x00\x80\x7F')
+ write(b('\x00\x00\x80\x7F')) ##PY25
+##!PY25 write(b'\x00\x00\x80\x7F')
elif value == _NEG_INF:
- write('\x00\x00\x80\xFF')
+ write(b('\x00\x00\x80\xFF')) ##PY25
+##!PY25 write(b'\x00\x00\x80\xFF')
elif value != value: # NaN
- write('\x00\x00\xC0\x7F')
+ write(b('\x00\x00\xC0\x7F')) ##PY25
+##!PY25 write(b'\x00\x00\xC0\x7F')
else:
raise
elif value_size == 8:
def EncodeNonFiniteOrRaise(write, value):
if value == _POS_INF:
- write('\x00\x00\x00\x00\x00\x00\xF0\x7F')
+ write(b('\x00\x00\x00\x00\x00\x00\xF0\x7F')) ##PY25
+##!PY25 write(b'\x00\x00\x00\x00\x00\x00\xF0\x7F')
elif value == _NEG_INF:
- write('\x00\x00\x00\x00\x00\x00\xF0\xFF')
+ write(b('\x00\x00\x00\x00\x00\x00\xF0\xFF')) ##PY25
+##!PY25 write(b'\x00\x00\x00\x00\x00\x00\xF0\xFF')
elif value != value: # NaN
- write('\x00\x00\x00\x00\x00\x00\xF8\x7F')
+ write(b('\x00\x00\x00\x00\x00\x00\xF8\x7F')) ##PY25
+##!PY25 write(b'\x00\x00\x00\x00\x00\x00\xF8\x7F')
else:
raise
else:
@@ -615,8 +631,10 @@ DoubleEncoder = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED64, '<d')
def BoolEncoder(field_number, is_repeated, is_packed):
"""Returns an encoder for a boolean field."""
- false_byte = chr(0)
- true_byte = chr(1)
+##!PY25 false_byte = b'\x00'
+##!PY25 true_byte = b'\x01'
+ false_byte = '\x00'.encode('latin1') ##PY25
+ true_byte = '\x01'.encode('latin1') ##PY25
if is_packed:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
local_EncodeVarint = _EncodeVarint
@@ -752,7 +770,8 @@ def MessageSetItemEncoder(field_number):
}
}
"""
- start_bytes = "".join([
+ start_bytes = "".encode("latin1").join([ ##PY25
+##!PY25 start_bytes = b"".join([
TagBytes(1, wire_format.WIRETYPE_START_GROUP),
TagBytes(2, wire_format.WIRETYPE_VARINT),
_VarintBytes(field_number),
diff --git a/python/google/protobuf/internal/enum_type_wrapper.py b/python/google/protobuf/internal/enum_type_wrapper.py
new file mode 100644
index 00000000..1cffe352
--- /dev/null
+++ b/python/google/protobuf/internal/enum_type_wrapper.py
@@ -0,0 +1,89 @@
+# 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 simple wrapper around enum types to expose utility functions.
+
+Instances are created as properties with the same name as the enum they wrap
+on proto classes. For usage, see:
+ reflection_test.py
+"""
+
+__author__ = 'rabsatt@google.com (Kevin Rabsatt)'
+
+
+class EnumTypeWrapper(object):
+ """A utility for finding the names of enum values."""
+
+ DESCRIPTOR = None
+
+ def __init__(self, enum_type):
+ """Inits EnumTypeWrapper with an EnumDescriptor."""
+ self._enum_type = enum_type
+ self.DESCRIPTOR = enum_type;
+
+ def Name(self, number):
+ """Returns a string containing the name of an enum value."""
+ if number in self._enum_type.values_by_number:
+ return self._enum_type.values_by_number[number].name
+ raise ValueError('Enum %s has no name defined for value %d' % (
+ self._enum_type.name, number))
+
+ def Value(self, name):
+ """Returns the value coresponding to the given enum name."""
+ if name in self._enum_type.values_by_name:
+ return self._enum_type.values_by_name[name].number
+ raise ValueError('Enum %s has no value defined for name %s' % (
+ self._enum_type.name, name))
+
+ def keys(self):
+ """Return a list of the string names in the enum.
+
+ These are returned in the order they were defined in the .proto file.
+ """
+
+ return [value_descriptor.name
+ for value_descriptor in self._enum_type.values]
+
+ def values(self):
+ """Return a list of the integer values in the enum.
+
+ These are returned in the order they were defined in the .proto file.
+ """
+
+ return [value_descriptor.number
+ for value_descriptor in self._enum_type.values]
+
+ def items(self):
+ """Return a list of the (name, value) pairs of the enum.
+
+ These are returned in the order they were defined in the .proto file.
+ """
+ return [(value_descriptor.name, value_descriptor.number)
+ for value_descriptor in self._enum_type.values]
diff --git a/python/google/protobuf/internal/factory_test1.proto b/python/google/protobuf/internal/factory_test1.proto
new file mode 100644
index 00000000..d2fbbeec
--- /dev/null
+++ b/python/google/protobuf/internal/factory_test1.proto
@@ -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.
+
+// Author: matthewtoia@google.com (Matt Toia)
+
+syntax = "proto2";
+
+package google.protobuf.python.internal;
+
+
+enum Factory1Enum {
+ FACTORY_1_VALUE_0 = 0;
+ FACTORY_1_VALUE_1 = 1;
+}
+
+message Factory1Message {
+ optional Factory1Enum factory_1_enum = 1;
+ enum NestedFactory1Enum {
+ NESTED_FACTORY_1_VALUE_0 = 0;
+ NESTED_FACTORY_1_VALUE_1 = 1;
+ }
+ optional NestedFactory1Enum nested_factory_1_enum = 2;
+ message NestedFactory1Message {
+ optional string value = 1;
+ }
+ optional NestedFactory1Message nested_factory_1_message = 3;
+ optional int32 scalar_value = 4;
+ repeated string list_value = 5;
+
+ extensions 1000 to max;
+}
diff --git a/python/google/protobuf/internal/factory_test2.proto b/python/google/protobuf/internal/factory_test2.proto
new file mode 100644
index 00000000..bb1b54ad
--- /dev/null
+++ b/python/google/protobuf/internal/factory_test2.proto
@@ -0,0 +1,99 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: matthewtoia@google.com (Matt Toia)
+
+syntax = "proto2";
+
+package google.protobuf.python.internal;
+
+import "google/protobuf/internal/factory_test1.proto";
+
+
+enum Factory2Enum {
+ FACTORY_2_VALUE_0 = 0;
+ FACTORY_2_VALUE_1 = 1;
+}
+
+message Factory2Message {
+ required int32 mandatory = 1;
+ optional Factory2Enum factory_2_enum = 2;
+ enum NestedFactory2Enum {
+ NESTED_FACTORY_2_VALUE_0 = 0;
+ NESTED_FACTORY_2_VALUE_1 = 1;
+ }
+ optional NestedFactory2Enum nested_factory_2_enum = 3;
+ message NestedFactory2Message {
+ optional string value = 1;
+ }
+ optional NestedFactory2Message nested_factory_2_message = 4;
+ optional Factory1Message factory_1_message = 5;
+ optional Factory1Enum factory_1_enum = 6;
+ optional Factory1Message.NestedFactory1Enum nested_factory_1_enum = 7;
+ optional Factory1Message.NestedFactory1Message nested_factory_1_message = 8;
+ optional Factory2Message circular_message = 9;
+ optional string scalar_value = 10;
+ repeated string list_value = 11;
+ repeated group Grouped = 12 {
+ optional string part_1 = 13;
+ optional string part_2 = 14;
+ }
+ optional LoopMessage loop = 15;
+ optional int32 int_with_default = 16 [default = 1776];
+ optional double double_with_default = 17 [default = 9.99];
+ optional string string_with_default = 18 [default = "hello world"];
+ optional bool bool_with_default = 19 [default = false];
+ optional Factory2Enum enum_with_default = 20 [default = FACTORY_2_VALUE_1];
+ optional bytes bytes_with_default = 21 [default = "a\373\000c"];
+
+
+ extend Factory1Message {
+ optional string one_more_field = 1001;
+ }
+
+ oneof oneof_field {
+ int32 oneof_int = 22;
+ string oneof_string = 23;
+ }
+}
+
+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 b3f7d9b1..03361e66 100755
--- a/python/google/protobuf/internal/generator_test.py
+++ b/python/google/protobuf/internal/generator_test.py
@@ -2,7 +2,7 @@
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -35,24 +35,27 @@
# 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.
"""
__author__ = 'robinson@google.com (Will Robinson)'
-import unittest
+from google.apputils import basetest
+from google.protobuf.internal import test_bad_identifiers_pb2
from google.protobuf import unittest_custom_options_pb2
from google.protobuf import unittest_import_pb2
+from google.protobuf import unittest_import_public_pb2
from google.protobuf import unittest_mset_pb2
-from google.protobuf import unittest_pb2
from google.protobuf import unittest_no_generic_services_pb2
+from google.protobuf import unittest_pb2
from google.protobuf import service
+from google.protobuf import symbol_database
MAX_EXTENSION = 536870912
-class GeneratorTest(unittest.TestCase):
+class GeneratorTest(basetest.TestCase):
def testNestedMessageDescriptor(self):
field_name = 'optional_nested_message'
@@ -146,7 +149,7 @@ class GeneratorTest(unittest.TestCase):
proto = unittest_custom_options_pb2.TestMessageWithCustomOptions()
enum_options = proto.DESCRIPTOR.enum_types_by_name['AnEnum'].GetOptions()
self.assertTrue(enum_options is not None)
- # TODO(gps): We really should test for the presense of the enum_opt1
+ # TODO(gps): We really should test for the presence of the enum_opt1
# extension and for its value to be set to -789.
def testNestedTypes(self):
@@ -215,6 +218,10 @@ class GeneratorTest(unittest.TestCase):
'google/protobuf/unittest.proto')
self.assertEqual(unittest_pb2.DESCRIPTOR.package, 'protobuf_unittest')
self.assertFalse(unittest_pb2.DESCRIPTOR.serialized_pb is None)
+ self.assertEqual(unittest_pb2.DESCRIPTOR.dependencies,
+ [unittest_import_pb2.DESCRIPTOR])
+ self.assertEqual(unittest_import_pb2.DESCRIPTOR.dependencies,
+ [unittest_import_public_pb2.DESCRIPTOR])
def testNoGenericServices(self):
self.assertTrue(hasattr(unittest_no_generic_services_pb2, "TestMessage"))
@@ -239,6 +246,98 @@ class GeneratorTest(unittest.TestCase):
unittest_pb2._TESTALLTYPES_NESTEDMESSAGE.name in
file_type.message_types_by_name)
+ def testEnumTypesByName(self):
+ file_type = unittest_pb2.DESCRIPTOR
+ self.assertEqual(
+ unittest_pb2._FOREIGNENUM,
+ file_type.enum_types_by_name[unittest_pb2._FOREIGNENUM.name])
+
+ def testExtensionsByName(self):
+ file_type = unittest_pb2.DESCRIPTOR
+ self.assertEqual(
+ unittest_pb2.my_extension_string,
+ file_type.extensions_by_name[unittest_pb2.my_extension_string.name])
+
+ def testPublicImports(self):
+ # Test public imports as embedded message.
+ all_type_proto = unittest_pb2.TestAllTypes()
+ self.assertEqual(0, all_type_proto.optional_public_import_message.e)
+
+ # PublicImportMessage is actually defined in unittest_import_public_pb2
+ # module, and is public imported by unittest_import_pb2 module.
+ public_import_proto = unittest_import_pb2.PublicImportMessage()
+ self.assertEqual(0, public_import_proto.e)
+ self.assertTrue(unittest_import_public_pb2.PublicImportMessage is
+ unittest_import_pb2.PublicImportMessage)
+
+ def testBadIdentifiers(self):
+ # We're just testing that the code was imported without problems.
+ message = test_bad_identifiers_pb2.TestBadIdentifiers()
+ self.assertEqual(message.Extensions[test_bad_identifiers_pb2.message],
+ "foo")
+ self.assertEqual(message.Extensions[test_bad_identifiers_pb2.descriptor],
+ "bar")
+ self.assertEqual(message.Extensions[test_bad_identifiers_pb2.reflection],
+ "baz")
+ self.assertEqual(message.Extensions[test_bad_identifiers_pb2.service],
+ "qux")
+
+ def testOneof(self):
+ desc = unittest_pb2.TestAllTypes.DESCRIPTOR
+ self.assertEqual(1, len(desc.oneofs))
+ self.assertEqual('oneof_field', desc.oneofs[0].name)
+ self.assertEqual(0, desc.oneofs[0].index)
+ self.assertIs(desc, desc.oneofs[0].containing_type)
+ self.assertIs(desc.oneofs[0], desc.oneofs_by_name['oneof_field'])
+ nested_names = set(['oneof_uint32', 'oneof_nested_message',
+ 'oneof_string', 'oneof_bytes'])
+ self.assertSameElements(
+ nested_names,
+ [field.name for field in desc.oneofs[0].fields])
+ for field_name, field_desc in desc.fields_by_name.iteritems():
+ if field_name in nested_names:
+ self.assertIs(desc.oneofs[0], field_desc.containing_oneof)
+ else:
+ self.assertIsNone(field_desc.containing_oneof)
+
+
+class SymbolDatabaseRegistrationTest(basetest.TestCase):
+ """Checks that messages, enums and files are correctly registered."""
+
+ def testGetSymbol(self):
+ self.assertEquals(
+ unittest_pb2.TestAllTypes, symbol_database.Default().GetSymbol(
+ 'protobuf_unittest.TestAllTypes'))
+ self.assertEquals(
+ unittest_pb2.TestAllTypes.NestedMessage,
+ symbol_database.Default().GetSymbol(
+ 'protobuf_unittest.TestAllTypes.NestedMessage'))
+ with self.assertRaises(KeyError):
+ symbol_database.Default().GetSymbol('protobuf_unittest.NestedMessage')
+ self.assertEquals(
+ unittest_pb2.TestAllTypes.OptionalGroup,
+ symbol_database.Default().GetSymbol(
+ 'protobuf_unittest.TestAllTypes.OptionalGroup'))
+ self.assertEquals(
+ unittest_pb2.TestAllTypes.RepeatedGroup,
+ symbol_database.Default().GetSymbol(
+ 'protobuf_unittest.TestAllTypes.RepeatedGroup'))
+
+ def testEnums(self):
+ self.assertEquals(
+ 'protobuf_unittest.ForeignEnum',
+ symbol_database.Default().pool.FindEnumTypeByName(
+ 'protobuf_unittest.ForeignEnum').full_name)
+ self.assertEquals(
+ 'protobuf_unittest.TestAllTypes.NestedEnum',
+ symbol_database.Default().pool.FindEnumTypeByName(
+ 'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
+
+ def testFindFileByName(self):
+ self.assertEquals(
+ 'google/protobuf/unittest.proto',
+ symbol_database.Default().pool.FindFileByName(
+ 'google/protobuf/unittest.proto').name)
if __name__ == '__main__':
- unittest.main()
+ basetest.main()
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_factory_python_test.py b/python/google/protobuf/internal/message_factory_python_test.py
new file mode 100644
index 00000000..85e02b25
--- /dev/null
+++ b/python/google/protobuf/internal/message_factory_python_test.py
@@ -0,0 +1,54 @@
+#! /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 ..public.message_factory for the pure Python implementation."""
+
+import os
+os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'python'
+
+# We must set the implementation version above before the google3 imports.
+# pylint: disable=g-import-not-at-top
+from google.apputils import basetest
+from google.protobuf.internal import api_implementation
+# Run all tests from the original module by putting them in our namespace.
+# pylint: disable=wildcard-import
+from google.protobuf.internal.message_factory_test import *
+
+
+class ConfirmPurePythonTest(basetest.TestCase):
+
+ def testImplementationSetting(self):
+ self.assertEqual('python', api_implementation.Type())
+
+
+if __name__ == '__main__':
+ basetest.main()
diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py
new file mode 100644
index 00000000..fcf13410
--- /dev/null
+++ b/python/google/protobuf/internal/message_factory_test.py
@@ -0,0 +1,131 @@
+#! /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.message_factory."""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+from google.apputils import basetest
+from google.protobuf import descriptor_pb2
+from google.protobuf.internal import factory_test1_pb2
+from google.protobuf.internal import factory_test2_pb2
+from google.protobuf import descriptor_database
+from google.protobuf import descriptor_pool
+from google.protobuf import message_factory
+
+
+class MessageFactoryTest(basetest.TestCase):
+
+ def setUp(self):
+ self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
+ factory_test1_pb2.DESCRIPTOR.serialized_pb)
+ self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
+ factory_test2_pb2.DESCRIPTOR.serialized_pb)
+
+ def _ExerciseDynamicClass(self, cls):
+ msg = cls()
+ msg.mandatory = 42
+ msg.nested_factory_2_enum = 0
+ msg.nested_factory_2_message.value = 'nested message value'
+ msg.factory_1_message.factory_1_enum = 1
+ msg.factory_1_message.nested_factory_1_enum = 0
+ msg.factory_1_message.nested_factory_1_message.value = (
+ 'nested message value')
+ msg.factory_1_message.scalar_value = 22
+ msg.factory_1_message.list_value.extend([u'one', u'two', u'three'])
+ msg.factory_1_message.list_value.append(u'four')
+ msg.factory_1_enum = 1
+ msg.nested_factory_1_enum = 0
+ msg.nested_factory_1_message.value = 'nested message value'
+ msg.circular_message.mandatory = 1
+ msg.circular_message.circular_message.mandatory = 2
+ msg.circular_message.scalar_value = 'one deep'
+ msg.scalar_value = 'zero deep'
+ msg.list_value.extend([u'four', u'three', u'two'])
+ msg.list_value.append(u'one')
+ msg.grouped.add()
+ msg.grouped[0].part_1 = 'hello'
+ msg.grouped[0].part_2 = 'world'
+ msg.grouped.add(part_1='testing', part_2='123')
+ msg.loop.loop.mandatory = 2
+ msg.loop.loop.loop.loop.mandatory = 4
+ serialized = msg.SerializeToString()
+ converted = factory_test2_pb2.Factory2Message.FromString(serialized)
+ reserialized = converted.SerializeToString()
+ self.assertEquals(serialized, reserialized)
+ result = cls.FromString(reserialized)
+ self.assertEquals(msg, result)
+
+ def testGetPrototype(self):
+ db = descriptor_database.DescriptorDatabase()
+ pool = descriptor_pool.DescriptorPool(db)
+ db.Add(self.factory_test1_fd)
+ db.Add(self.factory_test2_fd)
+ factory = message_factory.MessageFactory()
+ cls = factory.GetPrototype(pool.FindMessageTypeByName(
+ 'google.protobuf.python.internal.Factory2Message'))
+ self.assertIsNot(cls, factory_test2_pb2.Factory2Message)
+ self._ExerciseDynamicClass(cls)
+ cls2 = factory.GetPrototype(pool.FindMessageTypeByName(
+ 'google.protobuf.python.internal.Factory2Message'))
+ self.assertIs(cls, cls2)
+
+ def testGetMessages(self):
+ # performed twice because multiple calls with the same input must be allowed
+ for _ in range(2):
+ messages = message_factory.GetMessages([self.factory_test2_fd,
+ self.factory_test1_fd])
+ self.assertContainsSubset(
+ ['google.protobuf.python.internal.Factory2Message',
+ 'google.protobuf.python.internal.Factory1Message'],
+ messages.keys())
+ self._ExerciseDynamicClass(
+ messages['google.protobuf.python.internal.Factory2Message'])
+ self.assertContainsSubset(
+ ['google.protobuf.python.internal.Factory2Message.one_more_field',
+ 'google.protobuf.python.internal.another_field'],
+ (messages['google.protobuf.python.internal.Factory1Message']
+ ._extensions_by_name.keys()))
+ factory_msg1 = messages['google.protobuf.python.internal.Factory1Message']
+ msg1 = messages['google.protobuf.python.internal.Factory1Message']()
+ ext1 = factory_msg1._extensions_by_name[
+ 'google.protobuf.python.internal.Factory2Message.one_more_field']
+ ext2 = factory_msg1._extensions_by_name[
+ 'google.protobuf.python.internal.another_field']
+ msg1.Extensions[ext1] = 'test1'
+ msg1.Extensions[ext2] = 'test2'
+ self.assertEquals('test1', msg1.Extensions[ext1])
+ self.assertEquals('test2', msg1.Extensions[ext2])
+
+
+if __name__ == '__main__':
+ basetest.main()
diff --git a/python/google/protobuf/internal/message_listener.py b/python/google/protobuf/internal/message_listener.py
index 1080234d..0fc255a7 100755
--- a/python/google/protobuf/internal/message_listener.py
+++ b/python/google/protobuf/internal/message_listener.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
diff --git a/python/google/protobuf/internal/message_python_test.py b/python/google/protobuf/internal/message_python_test.py
new file mode 100644
index 00000000..c40623a8
--- /dev/null
+++ b/python/google/protobuf/internal/message_python_test.py
@@ -0,0 +1,54 @@
+#! /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 ..public.message for the pure Python implementation."""
+
+import os
+os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'python'
+
+# We must set the implementation version above before the google3 imports.
+# pylint: disable=g-import-not-at-top
+from google.apputils import basetest
+from google.protobuf.internal import api_implementation
+# Run all tests from the original module by putting them in our namespace.
+# pylint: disable=wildcard-import
+from google.protobuf.internal.message_test import *
+
+
+class ConfirmPurePythonTest(basetest.TestCase):
+
+ def testImplementationSetting(self):
+ self.assertEqual('python', api_implementation.Type())
+
+
+if __name__ == '__main__':
+ basetest.main()
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index 65174373..ed1298af 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -2,7 +2,7 @@
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -45,10 +45,18 @@ __author__ = 'gps@google.com (Gregory P. Smith)'
import copy
import math
+import operator
+import pickle
+import sys
import unittest
-from google.protobuf import unittest_import_pb2
+
+from google.apputils import basetest
+from google.protobuf.internal import _parameterized
from google.protobuf import unittest_pb2
+from google.protobuf import unittest_proto3_arena_pb2
+from google.protobuf.internal import api_implementation
from google.protobuf.internal import test_util
+from google.protobuf import message
# Python pre-2.6 does not have isinf() or isnan() functions, so we have
# to provide our own.
@@ -63,118 +71,144 @@ def IsPosInf(val):
def IsNegInf(val):
return isinf(val) and (val < 0)
-class MessageTest(unittest.TestCase):
- def testGoldenMessage(self):
- golden_data = test_util.GoldenFile('golden_message').read()
- golden_message = unittest_pb2.TestAllTypes()
- golden_message.ParseFromString(golden_data)
- test_util.ExpectAllFieldsSet(self, golden_message)
- self.assertTrue(golden_message.SerializeToString() == golden_data)
- golden_copy = copy.deepcopy(golden_message)
- self.assertTrue(golden_copy.SerializeToString() == golden_data)
+@_parameterized.Parameters(
+ (unittest_pb2),
+ (unittest_proto3_arena_pb2))
+class MessageTest(basetest.TestCase):
- def testGoldenExtensions(self):
- golden_data = test_util.GoldenFile('golden_message').read()
- golden_message = unittest_pb2.TestAllExtensions()
+ def testBadUtf8String(self, message_module):
+ if api_implementation.Type() != 'python':
+ self.skipTest("Skipping testBadUtf8String, currently only the python "
+ "api implementation raises UnicodeDecodeError when a "
+ "string field contains bad utf-8.")
+ bad_utf8_data = test_util.GoldenFileData('bad_utf8_string')
+ with self.assertRaises(UnicodeDecodeError) as context:
+ message_module.TestAllTypes.FromString(bad_utf8_data)
+ self.assertIn('TestAllTypes.optional_string', str(context.exception))
+
+ def testGoldenMessage(self, message_module):
+ # Proto3 doesn't have the "default_foo" members or foreign enums,
+ # and doesn't preserve unknown fields, so for proto3 we use a golden
+ # message that doesn't have these fields set.
+ if message_module is unittest_pb2:
+ golden_data = test_util.GoldenFileData(
+ 'golden_message_oneof_implemented')
+ else:
+ golden_data = test_util.GoldenFileData('golden_message_proto3')
+
+ golden_message = message_module.TestAllTypes()
golden_message.ParseFromString(golden_data)
- all_set = unittest_pb2.TestAllExtensions()
- test_util.SetAllExtensions(all_set)
- self.assertEquals(all_set, golden_message)
- self.assertTrue(golden_message.SerializeToString() == golden_data)
+ if message_module is unittest_pb2:
+ test_util.ExpectAllFieldsSet(self, golden_message)
+ self.assertEqual(golden_data, golden_message.SerializeToString())
golden_copy = copy.deepcopy(golden_message)
- self.assertTrue(golden_copy.SerializeToString() == golden_data)
+ self.assertEqual(golden_data, golden_copy.SerializeToString())
- def testGoldenPackedMessage(self):
- golden_data = test_util.GoldenFile('golden_packed_fields_message').read()
- golden_message = unittest_pb2.TestPackedTypes()
+ def testGoldenPackedMessage(self, message_module):
+ golden_data = test_util.GoldenFileData('golden_packed_fields_message')
+ golden_message = message_module.TestPackedTypes()
golden_message.ParseFromString(golden_data)
- all_set = unittest_pb2.TestPackedTypes()
+ all_set = message_module.TestPackedTypes()
test_util.SetAllPackedFields(all_set)
- self.assertEquals(all_set, golden_message)
- self.assertTrue(all_set.SerializeToString() == golden_data)
+ self.assertEqual(all_set, golden_message)
+ self.assertEqual(golden_data, all_set.SerializeToString())
golden_copy = copy.deepcopy(golden_message)
- self.assertTrue(golden_copy.SerializeToString() == golden_data)
+ self.assertEqual(golden_data, golden_copy.SerializeToString())
- def testGoldenPackedExtensions(self):
- golden_data = test_util.GoldenFile('golden_packed_fields_message').read()
- golden_message = unittest_pb2.TestPackedExtensions()
+ def testPickleSupport(self, message_module):
+ golden_data = test_util.GoldenFileData('golden_message')
+ golden_message = message_module.TestAllTypes()
golden_message.ParseFromString(golden_data)
- all_set = unittest_pb2.TestPackedExtensions()
- test_util.SetAllPackedExtensions(all_set)
- self.assertEquals(all_set, golden_message)
- self.assertTrue(all_set.SerializeToString() == golden_data)
- golden_copy = copy.deepcopy(golden_message)
- self.assertTrue(golden_copy.SerializeToString() == golden_data)
-
- def testPositiveInfinity(self):
- golden_data = ('\x5D\x00\x00\x80\x7F'
- '\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
- '\xCD\x02\x00\x00\x80\x7F'
- '\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\x7F')
- golden_message = unittest_pb2.TestAllTypes()
+ pickled_message = pickle.dumps(golden_message)
+
+ unpickled_message = pickle.loads(pickled_message)
+ self.assertEqual(unpickled_message, golden_message)
+
+ def testPositiveInfinity(self, message_module):
+ golden_data = (b'\x5D\x00\x00\x80\x7F'
+ b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
+ b'\xCD\x02\x00\x00\x80\x7F'
+ b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\x7F')
+ golden_message = message_module.TestAllTypes()
golden_message.ParseFromString(golden_data)
self.assertTrue(IsPosInf(golden_message.optional_float))
self.assertTrue(IsPosInf(golden_message.optional_double))
self.assertTrue(IsPosInf(golden_message.repeated_float[0]))
self.assertTrue(IsPosInf(golden_message.repeated_double[0]))
- self.assertTrue(golden_message.SerializeToString() == golden_data)
-
- def testNegativeInfinity(self):
- golden_data = ('\x5D\x00\x00\x80\xFF'
- '\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
- '\xCD\x02\x00\x00\x80\xFF'
- '\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\xFF')
- golden_message = unittest_pb2.TestAllTypes()
+ self.assertEqual(golden_data, golden_message.SerializeToString())
+
+ def testNegativeInfinity(self, message_module):
+ golden_data = (b'\x5D\x00\x00\x80\xFF'
+ b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
+ b'\xCD\x02\x00\x00\x80\xFF'
+ b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\xFF')
+ golden_message = message_module.TestAllTypes()
golden_message.ParseFromString(golden_data)
self.assertTrue(IsNegInf(golden_message.optional_float))
self.assertTrue(IsNegInf(golden_message.optional_double))
self.assertTrue(IsNegInf(golden_message.repeated_float[0]))
self.assertTrue(IsNegInf(golden_message.repeated_double[0]))
- self.assertTrue(golden_message.SerializeToString() == golden_data)
-
- def testNotANumber(self):
- golden_data = ('\x5D\x00\x00\xC0\x7F'
- '\x61\x00\x00\x00\x00\x00\x00\xF8\x7F'
- '\xCD\x02\x00\x00\xC0\x7F'
- '\xD1\x02\x00\x00\x00\x00\x00\x00\xF8\x7F')
- golden_message = unittest_pb2.TestAllTypes()
+ self.assertEqual(golden_data, golden_message.SerializeToString())
+
+ def testNotANumber(self, message_module):
+ golden_data = (b'\x5D\x00\x00\xC0\x7F'
+ b'\x61\x00\x00\x00\x00\x00\x00\xF8\x7F'
+ b'\xCD\x02\x00\x00\xC0\x7F'
+ b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF8\x7F')
+ golden_message = message_module.TestAllTypes()
golden_message.ParseFromString(golden_data)
self.assertTrue(isnan(golden_message.optional_float))
self.assertTrue(isnan(golden_message.optional_double))
self.assertTrue(isnan(golden_message.repeated_float[0]))
self.assertTrue(isnan(golden_message.repeated_double[0]))
- self.assertTrue(golden_message.SerializeToString() == golden_data)
- def testPositiveInfinityPacked(self):
- golden_data = ('\xA2\x06\x04\x00\x00\x80\x7F'
- '\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF0\x7F')
- golden_message = unittest_pb2.TestPackedTypes()
+ # The protocol buffer may serialize to any one of multiple different
+ # representations of a NaN. Rather than verify a specific representation,
+ # verify the serialized string can be converted into a correctly
+ # behaving protocol buffer.
+ serialized = golden_message.SerializeToString()
+ message = message_module.TestAllTypes()
+ message.ParseFromString(serialized)
+ self.assertTrue(isnan(message.optional_float))
+ self.assertTrue(isnan(message.optional_double))
+ self.assertTrue(isnan(message.repeated_float[0]))
+ self.assertTrue(isnan(message.repeated_double[0]))
+
+ def testPositiveInfinityPacked(self, message_module):
+ golden_data = (b'\xA2\x06\x04\x00\x00\x80\x7F'
+ b'\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF0\x7F')
+ golden_message = message_module.TestPackedTypes()
golden_message.ParseFromString(golden_data)
self.assertTrue(IsPosInf(golden_message.packed_float[0]))
self.assertTrue(IsPosInf(golden_message.packed_double[0]))
- self.assertTrue(golden_message.SerializeToString() == golden_data)
+ self.assertEqual(golden_data, golden_message.SerializeToString())
- def testNegativeInfinityPacked(self):
- golden_data = ('\xA2\x06\x04\x00\x00\x80\xFF'
- '\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF0\xFF')
- golden_message = unittest_pb2.TestPackedTypes()
+ def testNegativeInfinityPacked(self, message_module):
+ golden_data = (b'\xA2\x06\x04\x00\x00\x80\xFF'
+ b'\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF0\xFF')
+ golden_message = message_module.TestPackedTypes()
golden_message.ParseFromString(golden_data)
self.assertTrue(IsNegInf(golden_message.packed_float[0]))
self.assertTrue(IsNegInf(golden_message.packed_double[0]))
- self.assertTrue(golden_message.SerializeToString() == golden_data)
+ self.assertEqual(golden_data, golden_message.SerializeToString())
- def testNotANumberPacked(self):
- golden_data = ('\xA2\x06\x04\x00\x00\xC0\x7F'
- '\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF8\x7F')
- golden_message = unittest_pb2.TestPackedTypes()
+ def testNotANumberPacked(self, message_module):
+ golden_data = (b'\xA2\x06\x04\x00\x00\xC0\x7F'
+ b'\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF8\x7F')
+ golden_message = message_module.TestPackedTypes()
golden_message.ParseFromString(golden_data)
self.assertTrue(isnan(golden_message.packed_float[0]))
self.assertTrue(isnan(golden_message.packed_double[0]))
- self.assertTrue(golden_message.SerializeToString() == golden_data)
- def testExtremeFloatValues(self):
- message = unittest_pb2.TestAllTypes()
+ serialized = golden_message.SerializeToString()
+ message = message_module.TestPackedTypes()
+ message.ParseFromString(serialized)
+ self.assertTrue(isnan(message.packed_float[0]))
+ self.assertTrue(isnan(message.packed_double[0]))
+
+ def testExtremeFloatValues(self, message_module):
+ message = message_module.TestAllTypes()
# Most positive exponent, no significand bits set.
kMostPosExponentNoSigBits = math.pow(2, 127)
@@ -218,8 +252,8 @@ class MessageTest(unittest.TestCase):
message.ParseFromString(message.SerializeToString())
self.assertTrue(message.optional_float == -kMostNegExponentOneSigBit)
- def testExtremeFloatValues(self):
- message = unittest_pb2.TestAllTypes()
+ def testExtremeDoubleValues(self, message_module):
+ message = message_module.TestAllTypes()
# Most positive exponent, no significand bits set.
kMostPosExponentNoSigBits = math.pow(2, 1023)
@@ -263,9 +297,43 @@ class MessageTest(unittest.TestCase):
message.ParseFromString(message.SerializeToString())
self.assertTrue(message.optional_double == -kMostNegExponentOneSigBit)
- def testSortingRepeatedScalarFieldsDefaultComparator(self):
+ def testFloatPrinting(self, message_module):
+ message = message_module.TestAllTypes()
+ message.optional_float = 2.0
+ self.assertEqual(str(message), 'optional_float: 2.0\n')
+
+ def testHighPrecisionFloatPrinting(self, message_module):
+ message = message_module.TestAllTypes()
+ message.optional_double = 0.12345678912345678
+ if sys.version_info.major >= 3:
+ self.assertEqual(str(message), 'optional_double: 0.12345678912345678\n')
+ else:
+ self.assertEqual(str(message), 'optional_double: 0.123456789123\n')
+
+ def testUnknownFieldPrinting(self, message_module):
+ populated = message_module.TestAllTypes()
+ test_util.SetAllNonLazyFields(populated)
+ empty = message_module.TestEmptyMessage()
+ empty.ParseFromString(populated.SerializeToString())
+ self.assertEqual(str(empty), '')
+
+ def testRepeatedNestedFieldIteration(self, message_module):
+ msg = message_module.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.assertEqual([1, 2, 3, 4],
+ [m.bb for m in msg.repeated_nested_message])
+ self.assertEqual([4, 3, 2, 1],
+ [m.bb for m in reversed(msg.repeated_nested_message)])
+ self.assertEqual([4, 3, 2, 1],
+ [m.bb for m in msg.repeated_nested_message[::-1]])
+
+ def testSortingRepeatedScalarFieldsDefaultComparator(self, message_module):
"""Check some different types with the default comparator."""
- message = unittest_pb2.TestAllTypes()
+ message = message_module.TestAllTypes()
# TODO(mattp): would testing more scalar types strengthen test?
message.repeated_int32.append(1)
@@ -292,22 +360,22 @@ class MessageTest(unittest.TestCase):
self.assertEqual(message.repeated_string[1], 'b')
self.assertEqual(message.repeated_string[2], 'c')
- message.repeated_bytes.append('a')
- message.repeated_bytes.append('c')
- message.repeated_bytes.append('b')
+ message.repeated_bytes.append(b'a')
+ message.repeated_bytes.append(b'c')
+ message.repeated_bytes.append(b'b')
message.repeated_bytes.sort()
- self.assertEqual(message.repeated_bytes[0], 'a')
- self.assertEqual(message.repeated_bytes[1], 'b')
- self.assertEqual(message.repeated_bytes[2], 'c')
+ self.assertEqual(message.repeated_bytes[0], b'a')
+ self.assertEqual(message.repeated_bytes[1], b'b')
+ self.assertEqual(message.repeated_bytes[2], b'c')
- def testSortingRepeatedScalarFieldsCustomComparator(self):
+ def testSortingRepeatedScalarFieldsCustomComparator(self, message_module):
"""Check some different types with custom comparator."""
- message = unittest_pb2.TestAllTypes()
+ message = message_module.TestAllTypes()
message.repeated_int32.append(-3)
message.repeated_int32.append(-2)
message.repeated_int32.append(-1)
- message.repeated_int32.sort(lambda x,y: cmp(abs(x), abs(y)))
+ message.repeated_int32.sort(key=abs)
self.assertEqual(message.repeated_int32[0], -1)
self.assertEqual(message.repeated_int32[1], -2)
self.assertEqual(message.repeated_int32[2], -3)
@@ -315,14 +383,14 @@ class MessageTest(unittest.TestCase):
message.repeated_string.append('aaa')
message.repeated_string.append('bb')
message.repeated_string.append('c')
- message.repeated_string.sort(lambda x,y: cmp(len(x), len(y)))
+ message.repeated_string.sort(key=len)
self.assertEqual(message.repeated_string[0], 'c')
self.assertEqual(message.repeated_string[1], 'bb')
self.assertEqual(message.repeated_string[2], 'aaa')
- def testSortingRepeatedCompositeFieldsCustomComparator(self):
+ def testSortingRepeatedCompositeFieldsCustomComparator(self, message_module):
"""Check passing a custom comparator to sort a repeated composite field."""
- message = unittest_pb2.TestAllTypes()
+ message = message_module.TestAllTypes()
message.repeated_nested_message.add().bb = 1
message.repeated_nested_message.add().bb = 3
@@ -330,7 +398,7 @@ class MessageTest(unittest.TestCase):
message.repeated_nested_message.add().bb = 6
message.repeated_nested_message.add().bb = 5
message.repeated_nested_message.add().bb = 4
- message.repeated_nested_message.sort(lambda x,y: cmp(x.bb, y.bb))
+ message.repeated_nested_message.sort(key=operator.attrgetter('bb'))
self.assertEqual(message.repeated_nested_message[0].bb, 1)
self.assertEqual(message.repeated_nested_message[1].bb, 2)
self.assertEqual(message.repeated_nested_message[2].bb, 3)
@@ -338,6 +406,736 @@ class MessageTest(unittest.TestCase):
self.assertEqual(message.repeated_nested_message[4].bb, 5)
self.assertEqual(message.repeated_nested_message[5].bb, 6)
+ def testRepeatedCompositeFieldSortArguments(self, message_module):
+ """Check sorting a repeated composite field using list.sort() arguments."""
+ message = message_module.TestAllTypes()
+
+ get_bb = operator.attrgetter('bb')
+ cmp_bb = lambda a, b: cmp(a.bb, b.bb)
+ message.repeated_nested_message.add().bb = 1
+ message.repeated_nested_message.add().bb = 3
+ message.repeated_nested_message.add().bb = 2
+ message.repeated_nested_message.add().bb = 6
+ message.repeated_nested_message.add().bb = 5
+ message.repeated_nested_message.add().bb = 4
+ message.repeated_nested_message.sort(key=get_bb)
+ self.assertEqual([k.bb for k in message.repeated_nested_message],
+ [1, 2, 3, 4, 5, 6])
+ message.repeated_nested_message.sort(key=get_bb, reverse=True)
+ self.assertEqual([k.bb for k in message.repeated_nested_message],
+ [6, 5, 4, 3, 2, 1])
+ if sys.version_info.major >= 3: return # No cmp sorting in PY3.
+ message.repeated_nested_message.sort(sort_function=cmp_bb)
+ self.assertEqual([k.bb for k in message.repeated_nested_message],
+ [1, 2, 3, 4, 5, 6])
+ message.repeated_nested_message.sort(cmp=cmp_bb, reverse=True)
+ self.assertEqual([k.bb for k in message.repeated_nested_message],
+ [6, 5, 4, 3, 2, 1])
+
+ def testRepeatedScalarFieldSortArguments(self, message_module):
+ """Check sorting a scalar field using list.sort() arguments."""
+ message = message_module.TestAllTypes()
+
+ message.repeated_int32.append(-3)
+ message.repeated_int32.append(-2)
+ message.repeated_int32.append(-1)
+ message.repeated_int32.sort(key=abs)
+ self.assertEqual(list(message.repeated_int32), [-1, -2, -3])
+ message.repeated_int32.sort(key=abs, reverse=True)
+ self.assertEqual(list(message.repeated_int32), [-3, -2, -1])
+ if sys.version_info.major < 3: # No cmp sorting in PY3.
+ abs_cmp = lambda a, b: cmp(abs(a), abs(b))
+ message.repeated_int32.sort(sort_function=abs_cmp)
+ self.assertEqual(list(message.repeated_int32), [-1, -2, -3])
+ message.repeated_int32.sort(cmp=abs_cmp, reverse=True)
+ self.assertEqual(list(message.repeated_int32), [-3, -2, -1])
+
+ message.repeated_string.append('aaa')
+ message.repeated_string.append('bb')
+ message.repeated_string.append('c')
+ message.repeated_string.sort(key=len)
+ self.assertEqual(list(message.repeated_string), ['c', 'bb', 'aaa'])
+ message.repeated_string.sort(key=len, reverse=True)
+ self.assertEqual(list(message.repeated_string), ['aaa', 'bb', 'c'])
+ if sys.version_info.major < 3: # No cmp sorting in PY3.
+ len_cmp = lambda a, b: cmp(len(a), len(b))
+ message.repeated_string.sort(sort_function=len_cmp)
+ self.assertEqual(list(message.repeated_string), ['c', 'bb', 'aaa'])
+ message.repeated_string.sort(cmp=len_cmp, reverse=True)
+ self.assertEqual(list(message.repeated_string), ['aaa', 'bb', 'c'])
+
+ def testRepeatedFieldsComparable(self, message_module):
+ m1 = message_module.TestAllTypes()
+ m2 = message_module.TestAllTypes()
+ m1.repeated_int32.append(0)
+ m1.repeated_int32.append(1)
+ m1.repeated_int32.append(2)
+ m2.repeated_int32.append(0)
+ m2.repeated_int32.append(1)
+ m2.repeated_int32.append(2)
+ m1.repeated_nested_message.add().bb = 1
+ m1.repeated_nested_message.add().bb = 2
+ m1.repeated_nested_message.add().bb = 3
+ m2.repeated_nested_message.add().bb = 1
+ m2.repeated_nested_message.add().bb = 2
+ m2.repeated_nested_message.add().bb = 3
+
+ if sys.version_info.major >= 3: return # No cmp() in PY3.
+
+ # These comparisons should not raise errors.
+ _ = m1 < m2
+ _ = m1.repeated_nested_message < m2.repeated_nested_message
+
+ # Make sure cmp always works. If it wasn't defined, these would be
+ # id() comparisons and would all fail.
+ self.assertEqual(cmp(m1, m2), 0)
+ self.assertEqual(cmp(m1.repeated_int32, m2.repeated_int32), 0)
+ self.assertEqual(cmp(m1.repeated_int32, [0, 1, 2]), 0)
+ self.assertEqual(cmp(m1.repeated_nested_message,
+ m2.repeated_nested_message), 0)
+ with self.assertRaises(TypeError):
+ # Can't compare repeated composite containers to lists.
+ cmp(m1.repeated_nested_message, m2.repeated_nested_message[:])
+
+ # TODO(anuraag): Implement extensiondict comparison in C++ and then add test
+
+ def ensureNestedMessageExists(self, msg, attribute):
+ """Make sure that a nested message object exists.
+
+ As soon as a nested message attribute is accessed, it will be present in the
+ _fields dict, without being marked as actually being set.
+ """
+ getattr(msg, attribute)
+ self.assertFalse(msg.HasField(attribute))
+
+ def testOneofGetCaseNonexistingField(self, message_module):
+ m = message_module.TestAllTypes()
+ self.assertRaises(ValueError, m.WhichOneof, 'no_such_oneof_field')
+
+ def testOneofDefaultValues(self, message_module):
+ m = message_module.TestAllTypes()
+ self.assertIs(None, m.WhichOneof('oneof_field'))
+ self.assertFalse(m.HasField('oneof_uint32'))
+
+ # Oneof is set even when setting it to a default value.
+ m.oneof_uint32 = 0
+ self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+ self.assertTrue(m.HasField('oneof_uint32'))
+ self.assertFalse(m.HasField('oneof_string'))
+
+ m.oneof_string = ""
+ self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+ self.assertTrue(m.HasField('oneof_string'))
+ self.assertFalse(m.HasField('oneof_uint32'))
+
+ def testOneofSemantics(self, message_module):
+ m = message_module.TestAllTypes()
+ self.assertIs(None, m.WhichOneof('oneof_field'))
+
+ m.oneof_uint32 = 11
+ self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+ self.assertTrue(m.HasField('oneof_uint32'))
+
+ m.oneof_string = u'foo'
+ self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+ self.assertFalse(m.HasField('oneof_uint32'))
+ self.assertTrue(m.HasField('oneof_string'))
+
+ m.oneof_nested_message.bb = 11
+ self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field'))
+ self.assertFalse(m.HasField('oneof_string'))
+ self.assertTrue(m.HasField('oneof_nested_message'))
+
+ m.oneof_bytes = b'bb'
+ self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
+ self.assertFalse(m.HasField('oneof_nested_message'))
+ self.assertTrue(m.HasField('oneof_bytes'))
+
+ def testOneofCompositeFieldReadAccess(self, message_module):
+ m = message_module.TestAllTypes()
+ m.oneof_uint32 = 11
+
+ self.ensureNestedMessageExists(m, 'oneof_nested_message')
+ self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+ self.assertEqual(11, m.oneof_uint32)
+
+ def testOneofWhichOneof(self, message_module):
+ m = message_module.TestAllTypes()
+ self.assertIs(None, m.WhichOneof('oneof_field'))
+ if message_module is unittest_pb2:
+ self.assertFalse(m.HasField('oneof_field'))
+
+ m.oneof_uint32 = 11
+ self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+ if message_module is unittest_pb2:
+ self.assertTrue(m.HasField('oneof_field'))
+
+ m.oneof_bytes = b'bb'
+ self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
+
+ m.ClearField('oneof_bytes')
+ self.assertIs(None, m.WhichOneof('oneof_field'))
+ if message_module is unittest_pb2:
+ self.assertFalse(m.HasField('oneof_field'))
+
+ def testOneofClearField(self, message_module):
+ m = message_module.TestAllTypes()
+ m.oneof_uint32 = 11
+ m.ClearField('oneof_field')
+ if message_module is unittest_pb2:
+ self.assertFalse(m.HasField('oneof_field'))
+ self.assertFalse(m.HasField('oneof_uint32'))
+ self.assertIs(None, m.WhichOneof('oneof_field'))
+
+ def testOneofClearSetField(self, message_module):
+ m = message_module.TestAllTypes()
+ m.oneof_uint32 = 11
+ m.ClearField('oneof_uint32')
+ if message_module is unittest_pb2:
+ self.assertFalse(m.HasField('oneof_field'))
+ self.assertFalse(m.HasField('oneof_uint32'))
+ self.assertIs(None, m.WhichOneof('oneof_field'))
+
+ def testOneofClearUnsetField(self, message_module):
+ m = message_module.TestAllTypes()
+ m.oneof_uint32 = 11
+ self.ensureNestedMessageExists(m, 'oneof_nested_message')
+ m.ClearField('oneof_nested_message')
+ self.assertEqual(11, m.oneof_uint32)
+ if message_module is unittest_pb2:
+ self.assertTrue(m.HasField('oneof_field'))
+ self.assertTrue(m.HasField('oneof_uint32'))
+ self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+
+ def testOneofDeserialize(self, message_module):
+ m = message_module.TestAllTypes()
+ m.oneof_uint32 = 11
+ m2 = message_module.TestAllTypes()
+ m2.ParseFromString(m.SerializeToString())
+ self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+ def testOneofCopyFrom(self, message_module):
+ m = message_module.TestAllTypes()
+ m.oneof_uint32 = 11
+ m2 = message_module.TestAllTypes()
+ m2.CopyFrom(m)
+ self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+ def testOneofNestedMergeFrom(self, message_module):
+ m = message_module.NestedTestAllTypes()
+ m.payload.oneof_uint32 = 11
+ m2 = message_module.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 testOneofMessageMergeFrom(self, message_module):
+ m = message_module.NestedTestAllTypes()
+ m.payload.oneof_nested_message.bb = 11
+ m.child.payload.oneof_nested_message.bb = 12
+ m2 = message_module.NestedTestAllTypes()
+ m2.payload.oneof_uint32 = 13
+ m2.MergeFrom(m)
+ self.assertEqual('oneof_nested_message',
+ m2.payload.WhichOneof('oneof_field'))
+ self.assertEqual('oneof_nested_message',
+ m2.child.payload.WhichOneof('oneof_field'))
+
+ def testOneofNestedMessageInit(self, message_module):
+ m = message_module.TestAllTypes(
+ oneof_nested_message=message_module.TestAllTypes.NestedMessage())
+ self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field'))
+
+ def testOneofClear(self, message_module):
+ m = message_module.TestAllTypes()
+ m.oneof_uint32 = 11
+ m.Clear()
+ self.assertIsNone(m.WhichOneof('oneof_field'))
+ m.oneof_bytes = b'bb'
+ self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
+
+ def testAssignByteStringToUnicodeField(self, message_module):
+ """Assigning a byte string to a string field should result
+ in the value being converted to a Unicode string."""
+ m = message_module.TestAllTypes()
+ m.optional_string = str('')
+ self.assertTrue(isinstance(m.optional_string, unicode))
+
+# TODO(haberman): why are these tests Google-internal only?
+
+ def testLongValuedSlice(self, message_module):
+ """It should be possible to use long-valued indicies in slices
+
+ This didn't used to work in the v2 C++ implementation.
+ """
+ m = message_module.TestAllTypes()
+
+ # Repeated scalar
+ m.repeated_int32.append(1)
+ sl = m.repeated_int32[long(0):long(len(m.repeated_int32))]
+ self.assertEqual(len(m.repeated_int32), len(sl))
+
+ # Repeated composite
+ m.repeated_nested_message.add().bb = 3
+ sl = m.repeated_nested_message[long(0):long(len(m.repeated_nested_message))]
+ self.assertEqual(len(m.repeated_nested_message), len(sl))
+
+ def testExtendShouldNotSwallowExceptions(self, message_module):
+ """This didn't use to work in the v2 C++ implementation."""
+ m = message_module.TestAllTypes()
+ with self.assertRaises(NameError) as _:
+ m.repeated_int32.extend(a for i in range(10)) # pylint: disable=undefined-variable
+ with self.assertRaises(NameError) as _:
+ m.repeated_nested_enum.extend(
+ a for i in range(10)) # pylint: disable=undefined-variable
+
+ FALSY_VALUES = [None, False, 0, 0.0, b'', u'', bytearray(), [], {}, set()]
+
+ def testExtendInt32WithNothing(self, message_module):
+ """Test no-ops extending repeated int32 fields."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_int32)
+
+ # TODO(ptucker): Deprecate this behavior. b/18413862
+ for falsy_value in MessageTest.FALSY_VALUES:
+ m.repeated_int32.extend(falsy_value)
+ self.assertSequenceEqual([], m.repeated_int32)
+
+ m.repeated_int32.extend([])
+ self.assertSequenceEqual([], m.repeated_int32)
+
+ def testExtendFloatWithNothing(self, message_module):
+ """Test no-ops extending repeated float fields."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_float)
+
+ # TODO(ptucker): Deprecate this behavior. b/18413862
+ for falsy_value in MessageTest.FALSY_VALUES:
+ m.repeated_float.extend(falsy_value)
+ self.assertSequenceEqual([], m.repeated_float)
+
+ m.repeated_float.extend([])
+ self.assertSequenceEqual([], m.repeated_float)
+
+ def testExtendStringWithNothing(self, message_module):
+ """Test no-ops extending repeated string fields."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_string)
+
+ # TODO(ptucker): Deprecate this behavior. b/18413862
+ for falsy_value in MessageTest.FALSY_VALUES:
+ m.repeated_string.extend(falsy_value)
+ self.assertSequenceEqual([], m.repeated_string)
+
+ m.repeated_string.extend([])
+ self.assertSequenceEqual([], m.repeated_string)
+
+ def testExtendInt32WithPythonList(self, message_module):
+ """Test extending repeated int32 fields with python lists."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_int32)
+ m.repeated_int32.extend([0])
+ self.assertSequenceEqual([0], m.repeated_int32)
+ m.repeated_int32.extend([1, 2])
+ self.assertSequenceEqual([0, 1, 2], m.repeated_int32)
+ m.repeated_int32.extend([3, 4])
+ self.assertSequenceEqual([0, 1, 2, 3, 4], m.repeated_int32)
+
+ def testExtendFloatWithPythonList(self, message_module):
+ """Test extending repeated float fields with python lists."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_float)
+ m.repeated_float.extend([0.0])
+ self.assertSequenceEqual([0.0], m.repeated_float)
+ m.repeated_float.extend([1.0, 2.0])
+ self.assertSequenceEqual([0.0, 1.0, 2.0], m.repeated_float)
+ m.repeated_float.extend([3.0, 4.0])
+ self.assertSequenceEqual([0.0, 1.0, 2.0, 3.0, 4.0], m.repeated_float)
+
+ def testExtendStringWithPythonList(self, message_module):
+ """Test extending repeated string fields with python lists."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_string)
+ m.repeated_string.extend([''])
+ self.assertSequenceEqual([''], m.repeated_string)
+ m.repeated_string.extend(['11', '22'])
+ self.assertSequenceEqual(['', '11', '22'], m.repeated_string)
+ m.repeated_string.extend(['33', '44'])
+ self.assertSequenceEqual(['', '11', '22', '33', '44'], m.repeated_string)
+
+ def testExtendStringWithString(self, message_module):
+ """Test extending repeated string fields with characters from a string."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_string)
+ m.repeated_string.extend('abc')
+ self.assertSequenceEqual(['a', 'b', 'c'], m.repeated_string)
+
+ class TestIterable(object):
+ """This iterable object mimics the behavior of numpy.array.
+
+ __nonzero__ fails for length > 1, and returns bool(item[0]) for length == 1.
+
+ """
+
+ def __init__(self, values=None):
+ self._list = values or []
+
+ def __nonzero__(self):
+ size = len(self._list)
+ if size == 0:
+ return False
+ if size == 1:
+ return bool(self._list[0])
+ raise ValueError('Truth value is ambiguous.')
+
+ def __len__(self):
+ return len(self._list)
+
+ def __iter__(self):
+ return self._list.__iter__()
+
+ def testExtendInt32WithIterable(self, message_module):
+ """Test extending repeated int32 fields with iterable."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_int32)
+ m.repeated_int32.extend(MessageTest.TestIterable([]))
+ self.assertSequenceEqual([], m.repeated_int32)
+ m.repeated_int32.extend(MessageTest.TestIterable([0]))
+ self.assertSequenceEqual([0], m.repeated_int32)
+ m.repeated_int32.extend(MessageTest.TestIterable([1, 2]))
+ self.assertSequenceEqual([0, 1, 2], m.repeated_int32)
+ m.repeated_int32.extend(MessageTest.TestIterable([3, 4]))
+ self.assertSequenceEqual([0, 1, 2, 3, 4], m.repeated_int32)
+
+ def testExtendFloatWithIterable(self, message_module):
+ """Test extending repeated float fields with iterable."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_float)
+ m.repeated_float.extend(MessageTest.TestIterable([]))
+ self.assertSequenceEqual([], m.repeated_float)
+ m.repeated_float.extend(MessageTest.TestIterable([0.0]))
+ self.assertSequenceEqual([0.0], m.repeated_float)
+ m.repeated_float.extend(MessageTest.TestIterable([1.0, 2.0]))
+ self.assertSequenceEqual([0.0, 1.0, 2.0], m.repeated_float)
+ m.repeated_float.extend(MessageTest.TestIterable([3.0, 4.0]))
+ self.assertSequenceEqual([0.0, 1.0, 2.0, 3.0, 4.0], m.repeated_float)
+
+ def testExtendStringWithIterable(self, message_module):
+ """Test extending repeated string fields with iterable."""
+ m = message_module.TestAllTypes()
+ self.assertSequenceEqual([], m.repeated_string)
+ m.repeated_string.extend(MessageTest.TestIterable([]))
+ self.assertSequenceEqual([], m.repeated_string)
+ m.repeated_string.extend(MessageTest.TestIterable(['']))
+ self.assertSequenceEqual([''], m.repeated_string)
+ m.repeated_string.extend(MessageTest.TestIterable(['1', '2']))
+ self.assertSequenceEqual(['', '1', '2'], m.repeated_string)
+ m.repeated_string.extend(MessageTest.TestIterable(['3', '4']))
+ self.assertSequenceEqual(['', '1', '2', '3', '4'], m.repeated_string)
+
+ def testPickleRepeatedScalarContainer(self, message_module):
+ # TODO(tibell): The pure-Python implementation support pickling of
+ # scalar containers in *some* cases. For now the cpp2 version
+ # throws an exception to avoid a segfault. Investigate if we
+ # want to support pickling of these fields.
+ #
+ # For more information see: https://b2.corp.google.com/u/0/issues/18677897
+ if (api_implementation.Type() != 'cpp' or
+ api_implementation.Version() == 2):
+ return
+ m = message_module.TestAllTypes()
+ with self.assertRaises(pickle.PickleError) as _:
+ pickle.dumps(m.repeated_int32, pickle.HIGHEST_PROTOCOL)
+
+
+ def testSortEmptyRepeatedCompositeContainer(self, message_module):
+ """Exercise a scenario that has led to segfaults in the past.
+ """
+ m = message_module.TestAllTypes()
+ m.repeated_nested_message.sort()
+
+ def testHasFieldOnRepeatedField(self, message_module):
+ """Using HasField on a repeated field should raise an exception.
+ """
+ m = message_module.TestAllTypes()
+ with self.assertRaises(ValueError) as _:
+ m.HasField('repeated_int32')
+
+ def testRepeatedScalarFieldPop(self, message_module):
+ m = message_module.TestAllTypes()
+ with self.assertRaises(IndexError) as _:
+ m.repeated_int32.pop()
+ m.repeated_int32.extend(range(5))
+ self.assertEqual(4, m.repeated_int32.pop())
+ self.assertEqual(0, m.repeated_int32.pop(0))
+ self.assertEqual(2, m.repeated_int32.pop(1))
+ self.assertEqual([1, 3], m.repeated_int32)
+
+ def testRepeatedCompositeFieldPop(self, message_module):
+ m = message_module.TestAllTypes()
+ with self.assertRaises(IndexError) as _:
+ m.repeated_nested_message.pop()
+ for i in range(5):
+ n = m.repeated_nested_message.add()
+ n.bb = i
+ self.assertEqual(4, m.repeated_nested_message.pop().bb)
+ self.assertEqual(0, m.repeated_nested_message.pop(0).bb)
+ self.assertEqual(2, m.repeated_nested_message.pop(1).bb)
+ self.assertEqual([1, 3], [n.bb for n in m.repeated_nested_message])
+
+
+# Class to test proto2-only features (required, extensions, etc.)
+class Proto2Test(basetest.TestCase):
+
+ def testFieldPresence(self):
+ message = unittest_pb2.TestAllTypes()
+
+ self.assertFalse(message.HasField("optional_int32"))
+ self.assertFalse(message.HasField("optional_bool"))
+ self.assertFalse(message.HasField("optional_nested_message"))
+
+ with self.assertRaises(ValueError):
+ message.HasField("field_doesnt_exist")
+
+ with self.assertRaises(ValueError):
+ message.HasField("repeated_int32")
+ with self.assertRaises(ValueError):
+ message.HasField("repeated_nested_message")
+
+ self.assertEqual(0, message.optional_int32)
+ self.assertEqual(False, message.optional_bool)
+ self.assertEqual(0, message.optional_nested_message.bb)
+
+ # Fields are set even when setting the values to default values.
+ message.optional_int32 = 0
+ message.optional_bool = False
+ message.optional_nested_message.bb = 0
+ self.assertTrue(message.HasField("optional_int32"))
+ self.assertTrue(message.HasField("optional_bool"))
+ self.assertTrue(message.HasField("optional_nested_message"))
+
+ # Set the fields to non-default values.
+ message.optional_int32 = 5
+ message.optional_bool = True
+ message.optional_nested_message.bb = 15
+
+ self.assertTrue(message.HasField("optional_int32"))
+ self.assertTrue(message.HasField("optional_bool"))
+ self.assertTrue(message.HasField("optional_nested_message"))
+
+ # Clearing the fields unsets them and resets their value to default.
+ message.ClearField("optional_int32")
+ message.ClearField("optional_bool")
+ message.ClearField("optional_nested_message")
+
+ self.assertFalse(message.HasField("optional_int32"))
+ self.assertFalse(message.HasField("optional_bool"))
+ self.assertFalse(message.HasField("optional_nested_message"))
+ self.assertEqual(0, message.optional_int32)
+ self.assertEqual(False, message.optional_bool)
+ self.assertEqual(0, message.optional_nested_message.bb)
+
+ # TODO(tibell): The C++ implementations actually allows assignment
+ # of unknown enum values to *scalar* fields (but not repeated
+ # fields). Once checked enum fields becomes the default in the
+ # Python implementation, the C++ implementation should follow suit.
+ def testAssignInvalidEnum(self):
+ """It should not be possible to assign an invalid enum number to an
+ enum field."""
+ m = unittest_pb2.TestAllTypes()
+
+ with self.assertRaises(ValueError) as _:
+ m.optional_nested_enum = 1234567
+ self.assertRaises(ValueError, m.repeated_nested_enum.append, 1234567)
+
+ def testGoldenExtensions(self):
+ golden_data = test_util.GoldenFileData('golden_message')
+ golden_message = unittest_pb2.TestAllExtensions()
+ golden_message.ParseFromString(golden_data)
+ all_set = unittest_pb2.TestAllExtensions()
+ test_util.SetAllExtensions(all_set)
+ self.assertEqual(all_set, golden_message)
+ self.assertEqual(golden_data, golden_message.SerializeToString())
+ golden_copy = copy.deepcopy(golden_message)
+ self.assertEqual(golden_data, golden_copy.SerializeToString())
+
+ def testGoldenPackedExtensions(self):
+ golden_data = test_util.GoldenFileData('golden_packed_fields_message')
+ golden_message = unittest_pb2.TestPackedExtensions()
+ golden_message.ParseFromString(golden_data)
+ all_set = unittest_pb2.TestPackedExtensions()
+ test_util.SetAllPackedExtensions(all_set)
+ self.assertEqual(all_set, golden_message)
+ self.assertEqual(golden_data, all_set.SerializeToString())
+ golden_copy = copy.deepcopy(golden_message)
+ self.assertEqual(golden_data, golden_copy.SerializeToString())
+
+ def testPickleIncompleteProto(self):
+ golden_message = unittest_pb2.TestRequired(a=1)
+ pickled_message = pickle.dumps(golden_message)
+
+ unpickled_message = pickle.loads(pickled_message)
+ self.assertEqual(unpickled_message, golden_message)
+ self.assertEqual(unpickled_message.a, 1)
+ # This is still an incomplete proto - so serializing should fail
+ self.assertRaises(message.EncodeError, unpickled_message.SerializeToString)
+
+
+ # TODO(haberman): this isn't really a proto2-specific test except that this
+ # message has a required field in it. Should probably be factored out so
+ # that we can test the other parts with proto3.
+ def testParsingMerge(self):
+ """Check the merge behavior when a required or optional field appears
+ multiple times in the input."""
+ messages = [
+ unittest_pb2.TestAllTypes(),
+ unittest_pb2.TestAllTypes(),
+ unittest_pb2.TestAllTypes() ]
+ messages[0].optional_int32 = 1
+ messages[1].optional_int64 = 2
+ messages[2].optional_int32 = 3
+ messages[2].optional_string = 'hello'
+
+ merged_message = unittest_pb2.TestAllTypes()
+ merged_message.optional_int32 = 3
+ merged_message.optional_int64 = 2
+ merged_message.optional_string = 'hello'
+
+ generator = unittest_pb2.TestParsingMerge.RepeatedFieldsGenerator()
+ generator.field1.extend(messages)
+ generator.field2.extend(messages)
+ generator.field3.extend(messages)
+ generator.ext1.extend(messages)
+ generator.ext2.extend(messages)
+ generator.group1.add().field1.MergeFrom(messages[0])
+ generator.group1.add().field1.MergeFrom(messages[1])
+ generator.group1.add().field1.MergeFrom(messages[2])
+ generator.group2.add().field1.MergeFrom(messages[0])
+ generator.group2.add().field1.MergeFrom(messages[1])
+ generator.group2.add().field1.MergeFrom(messages[2])
+
+ data = generator.SerializeToString()
+ parsing_merge = unittest_pb2.TestParsingMerge()
+ parsing_merge.ParseFromString(data)
+
+ # Required and optional fields should be merged.
+ self.assertEqual(parsing_merge.required_all_types, merged_message)
+ self.assertEqual(parsing_merge.optional_all_types, merged_message)
+ self.assertEqual(parsing_merge.optionalgroup.optional_group_all_types,
+ merged_message)
+ self.assertEqual(parsing_merge.Extensions[
+ unittest_pb2.TestParsingMerge.optional_ext],
+ merged_message)
+
+ # Repeated fields should not be merged.
+ self.assertEqual(len(parsing_merge.repeated_all_types), 3)
+ self.assertEqual(len(parsing_merge.repeatedgroup), 3)
+ self.assertEqual(len(parsing_merge.Extensions[
+ unittest_pb2.TestParsingMerge.repeated_ext]), 3)
+
+
+# Class to test proto3-only features/behavior (updated field presence & enums)
+class Proto3Test(basetest.TestCase):
+
+ def testFieldPresence(self):
+ message = unittest_proto3_arena_pb2.TestAllTypes()
+
+ # We can't test presence of non-repeated, non-submessage fields.
+ with self.assertRaises(ValueError):
+ message.HasField("optional_int32")
+ with self.assertRaises(ValueError):
+ message.HasField("optional_float")
+ with self.assertRaises(ValueError):
+ message.HasField("optional_string")
+ with self.assertRaises(ValueError):
+ message.HasField("optional_bool")
+
+ # But we can still test presence of submessage fields.
+ self.assertFalse(message.HasField("optional_nested_message"))
+
+ # As with proto2, we can't test presence of fields that don't exist, or
+ # repeated fields.
+ with self.assertRaises(ValueError):
+ message.HasField("field_doesnt_exist")
+
+ with self.assertRaises(ValueError):
+ message.HasField("repeated_int32")
+ with self.assertRaises(ValueError):
+ message.HasField("repeated_nested_message")
+
+ # Fields should default to their type-specific default.
+ self.assertEqual(0, message.optional_int32)
+ self.assertEqual(0, message.optional_float)
+ self.assertEqual("", message.optional_string)
+ self.assertEqual(False, message.optional_bool)
+ self.assertEqual(0, message.optional_nested_message.bb)
+
+ # Setting a submessage should still return proper presence information.
+ message.optional_nested_message.bb = 0
+ self.assertTrue(message.HasField("optional_nested_message"))
+
+ # Set the fields to non-default values.
+ message.optional_int32 = 5
+ message.optional_float = 1.1
+ message.optional_string = "abc"
+ message.optional_bool = True
+ message.optional_nested_message.bb = 15
+
+ # Clearing the fields unsets them and resets their value to default.
+ message.ClearField("optional_int32")
+ message.ClearField("optional_float")
+ message.ClearField("optional_string")
+ message.ClearField("optional_bool")
+ message.ClearField("optional_nested_message")
+
+ self.assertEqual(0, message.optional_int32)
+ self.assertEqual(0, message.optional_float)
+ self.assertEqual("", message.optional_string)
+ self.assertEqual(False, message.optional_bool)
+ self.assertEqual(0, message.optional_nested_message.bb)
+
+ def testAssignUnknownEnum(self):
+ """Assigning an unknown enum value is allowed and preserves the value."""
+ m = unittest_proto3_arena_pb2.TestAllTypes()
+
+ m.optional_nested_enum = 1234567
+ self.assertEqual(1234567, m.optional_nested_enum)
+ m.repeated_nested_enum.append(22334455)
+ self.assertEqual(22334455, m.repeated_nested_enum[0])
+ # Assignment is a different code path than append for the C++ impl.
+ m.repeated_nested_enum[0] = 7654321
+ self.assertEqual(7654321, m.repeated_nested_enum[0])
+ serialized = m.SerializeToString()
+
+ m2 = unittest_proto3_arena_pb2.TestAllTypes()
+ m2.ParseFromString(serialized)
+ self.assertEqual(1234567, m2.optional_nested_enum)
+ self.assertEqual(7654321, m2.repeated_nested_enum[0])
+
+
+class ValidTypeNamesTest(basetest.TestCase):
+
+ def assertImportFromName(self, msg, base_name):
+ # Parse <type 'module.class_name'> to extra 'some.name' as a string.
+ tp_name = str(type(msg)).split("'")[1]
+ valid_names = ('Repeated%sContainer' % base_name,
+ 'Repeated%sFieldContainer' % base_name)
+ self.assertTrue(any(tp_name.endswith(v) for v in valid_names),
+ '%r does end with any of %r' % (tp_name, valid_names))
+
+ parts = tp_name.split('.')
+ class_name = parts[-1]
+ module_name = '.'.join(parts[:-1])
+ __import__(module_name, fromlist=[class_name])
+
+ def testTypeNamesCanBeImported(self):
+ # If import doesn't work, pickling won't work either.
+ pb = unittest_pb2.TestAllTypes()
+ self.assertImportFromName(pb.repeated_int32, 'Scalar')
+ self.assertImportFromName(pb.repeated_nested_message, 'Composite')
+
if __name__ == '__main__':
- unittest.main()
+ basetest.main()
diff --git a/python/google/protobuf/internal/missing_enum_values.proto b/python/google/protobuf/internal/missing_enum_values.proto
new file mode 100644
index 00000000..161fc5e1
--- /dev/null
+++ b/python/google/protobuf/internal/missing_enum_values.proto
@@ -0,0 +1,52 @@
+// 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;
+
+message TestEnumValues {
+ enum NestedEnum {
+ ZERO = 0;
+ ONE = 1;
+ }
+ optional NestedEnum optional_nested_enum = 1;
+ repeated NestedEnum repeated_nested_enum = 2;
+ repeated NestedEnum packed_nested_enum = 3 [packed = true];
+}
+
+message TestMissingEnumValues {
+ enum NestedEnum {
+ TWO = 2;
+ }
+ optional NestedEnum optional_nested_enum = 1;
+ repeated NestedEnum repeated_nested_enum = 2;
+ repeated NestedEnum packed_nested_enum = 3 [packed = true];
+}
diff --git a/python/google/protobuf/internal/more_extensions.proto b/python/google/protobuf/internal/more_extensions.proto
index e2d97010..78f14673 100644
--- a/python/google/protobuf/internal/more_extensions.proto
+++ b/python/google/protobuf/internal/more_extensions.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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
new file mode 100644
index 00000000..11f85ef6
--- /dev/null
+++ b/python/google/protobuf/internal/more_extensions_dynamic.proto
@@ -0,0 +1,50 @@
+// 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: jasonh@google.com (Jason Hsueh)
+//
+// This file is used to test a corner case in the CPP implementation where the
+// 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";
+
+package google.protobuf.internal;
+
+message DynamicMessageType {
+ optional int32 a = 1;
+}
+
+extend ExtendedMessage {
+ optional int32 dynamic_int32_extension = 100;
+ optional DynamicMessageType dynamic_message_extension = 101;
+}
diff --git a/python/google/protobuf/internal/more_messages.proto b/python/google/protobuf/internal/more_messages.proto
index c701b446..2c6ab9ef 100644
--- a/python/google/protobuf/internal/more_messages.proto
+++ b/python/google/protobuf/internal/more_messages.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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 66fca918..6ad0f90d 100755
--- a/python/google/protobuf/internal/python_message.py
+++ b/python/google/protobuf/internal/python_message.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -28,6 +28,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# Keep it Python2.5 compatible for GAE.
+#
+# Copyright 2007 Google Inc. All Rights Reserved.
+#
# This code is meant to work on Python 2.4 and above only.
#
# TODO(robinson): Helpers for verbose, common checks like seeing if a
@@ -50,10 +54,16 @@ this file*.
__author__ = 'robinson@google.com (Will Robinson)'
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
+import sys
+if sys.version_info[0] < 3:
+ try:
+ from cStringIO import StringIO as BytesIO
+ except ImportError:
+ from StringIO import StringIO as BytesIO
+ import copy_reg as copyreg
+else:
+ from io import BytesIO
+ import copyreg
import struct
import weakref
@@ -61,6 +71,7 @@ import weakref
from google.protobuf.internal import containers
from google.protobuf.internal import decoder
from google.protobuf.internal import encoder
+from google.protobuf.internal import enum_type_wrapper
from google.protobuf.internal import message_listener as message_listener_mod
from google.protobuf.internal import type_checkers
from google.protobuf.internal import wire_format
@@ -71,9 +82,10 @@ from google.protobuf import text_format
_FieldDescriptor = descriptor_mod.FieldDescriptor
-def NewMessage(descriptor, dictionary):
+def NewMessage(bases, descriptor, dictionary):
_AddClassAttributesForNestedExtensions(descriptor, dictionary)
_AddSlots(descriptor, dictionary)
+ return bases
def InitMessage(descriptor, cls):
@@ -83,7 +95,7 @@ def InitMessage(descriptor, cls):
if (descriptor.has_options and
descriptor.GetOptions().message_set_wire_format):
cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = (
- decoder.MessageSetItemDecoder(cls._extensions_by_number))
+ decoder.MessageSetItemDecoder(cls._extensions_by_number), None)
# Attach stuff to each FieldDescriptor for quick lookup later on.
for field in descriptor.fields:
@@ -95,7 +107,8 @@ def InitMessage(descriptor, cls):
_AddPropertiesForExtensions(descriptor, cls)
_AddStaticMethods(cls)
_AddMessageMethods(descriptor, cls)
- _AddPrivateHelperMethods(cls)
+ _AddPrivateHelperMethods(descriptor, cls)
+ copyreg.pickle(cls, lambda obj: (cls, (), obj.__getstate__()))
# Stateless helpers for GeneratedProtocolMessageType below.
@@ -145,6 +158,10 @@ def _VerifyExtensionHandle(message, extension_handle):
if not extension_handle.is_extension:
raise KeyError('"%s" is not an extension.' % extension_handle.full_name)
+ if not extension_handle.containing_type:
+ raise KeyError('"%s" is missing a containing_type.'
+ % extension_handle.full_name)
+
if extension_handle.containing_type is not message.DESCRIPTOR:
raise KeyError('Extension "%s" extends message type "%s", but this '
'message is of type "%s".' %
@@ -164,10 +181,12 @@ def _AddSlots(message_descriptor, dictionary):
dictionary['__slots__'] = ['_cached_byte_size',
'_cached_byte_size_dirty',
'_fields',
+ '_unknown_fields',
'_is_present_in_parent',
'_listener',
'_listener_for_children',
- '__weakref__']
+ '__weakref__',
+ '_oneofs']
def _IsMessageSetExtension(field):
@@ -200,10 +219,20 @@ def _AttachFieldHelpers(cls, field_descriptor):
def AddDecoder(wiretype, is_packed):
tag_bytes = encoder.TagBytes(field_descriptor.number, wiretype)
- cls._decoders_by_tag[tag_bytes] = (
- type_checkers.TYPE_TO_DECODER[field_descriptor.type](
- field_descriptor.number, is_repeated, is_packed,
- field_descriptor, field_descriptor._default_constructor))
+ decode_type = field_descriptor.type
+ if (decode_type == _FieldDescriptor.TYPE_ENUM and
+ type_checkers.SupportsOpenEnums(field_descriptor)):
+ decode_type = _FieldDescriptor.TYPE_INT32
+
+ oneof_descriptor = None
+ if field_descriptor.containing_oneof is not None:
+ oneof_descriptor = field_descriptor
+
+ field_decoder = type_checkers.TYPE_TO_DECODER[decode_type](
+ field_descriptor.number, is_repeated, is_packed,
+ field_descriptor, field_descriptor._default_constructor)
+
+ cls._decoders_by_tag[tag_bytes] = (field_decoder, oneof_descriptor)
AddDecoder(type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type],
False)
@@ -224,11 +253,14 @@ def _AddClassAttributesForNestedExtensions(descriptor, dictionary):
def _AddEnumValues(descriptor, cls):
"""Sets class-level attributes for all enum fields defined in this message.
+ Also exporting a class-level object that can name enum values.
+
Args:
descriptor: Descriptor object for this message type.
cls: Class we're constructing for this message type.
"""
for enum_type in descriptor.enum_types:
+ setattr(cls, enum_type.name, enum_type_wrapper.EnumTypeWrapper(enum_type))
for enum_value in enum_type.values:
setattr(cls, enum_value.name, enum_value.number)
@@ -248,7 +280,7 @@ def _DefaultValueConstructorForField(field):
"""
if field.label == _FieldDescriptor.LABEL_REPEATED:
- if field.default_value != []:
+ if field.has_default_value and field.default_value != []:
raise ValueError('Repeated field default value not empty list: %s' % (
field.default_value))
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
@@ -260,7 +292,7 @@ def _DefaultValueConstructorForField(field):
message._listener_for_children, field.message_type)
return MakeRepeatedMessageDefault
else:
- type_checker = type_checkers.GetTypeChecker(field.cpp_type, field.type)
+ type_checker = type_checkers.GetTypeChecker(field)
def MakeRepeatedScalarDefault(message):
return containers.RepeatedScalarFieldContainer(
message._listener_for_children, type_checker)
@@ -272,14 +304,29 @@ def _DefaultValueConstructorForField(field):
def MakeSubMessageDefault(message):
result = message_type._concrete_class()
result._SetListener(message._listener_for_children)
+ if field.containing_oneof:
+ message._UpdateOneofState(field)
return result
return MakeSubMessageDefault
def MakeScalarDefault(message):
+ # TODO(protobuf-team): This may be broken since there may not be
+ # default_value. Combine with has_default_value somehow.
return field.default_value
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
@@ -287,6 +334,13 @@ def _AddInitMethod(message_descriptor, cls):
self._cached_byte_size = 0
self._cached_byte_size_dirty = len(kwargs) > 0
self._fields = {}
+ # Contains a mapping from oneof field descriptors to the descriptor
+ # of the currently set field in that oneof field.
+ self._oneofs = {}
+
+ # _unknown_fields is () when empty for efficiency, and will be turned into
+ # a list if fields are added.
+ self._unknown_fields = ()
self._is_present_in_parent = False
self._listener = message_listener_mod.NullMessageListener()
self._listener_for_children = _Listener(self)
@@ -305,10 +359,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
@@ -423,22 +483,41 @@ def _AddPropertiesForNonRepeatedScalarField(field, cls):
"""
proto_field_name = field.name
property_name = _PropertyName(proto_field_name)
- type_checker = type_checkers.GetTypeChecker(field.cpp_type, field.type)
+ type_checker = type_checkers.GetTypeChecker(field)
default_value = field.default_value
valid_values = set()
+ is_proto3 = field.containing_type.syntax == "proto3"
def getter(self):
+ # TODO(protobuf-team): This may be broken since there may not be
+ # default_value. Combine with has_default_value somehow.
return self._fields.get(field, default_value)
getter.__module__ = None
getter.__doc__ = 'Getter for %s.' % proto_field_name
- def setter(self, new_value):
- type_checker.CheckValue(new_value)
- self._fields[field] = new_value
+
+ clear_when_set_to_default = is_proto3 and not field.containing_oneof
+
+ def field_setter(self, new_value):
+ # pylint: disable=protected-access
+ # Testing the value for truthiness captures all of the proto3 defaults
+ # (0, 0.0, enum 0, and False).
+ new_value = type_checker.CheckValue(new_value)
+ if clear_when_set_to_default and not new_value:
+ self._fields.pop(field, None)
+ else:
+ self._fields[field] = new_value
# Check _cached_byte_size_dirty inline to improve performance, since scalar
# setters are called frequently.
if not self._cached_byte_size_dirty:
self._Modified()
+ if field.containing_oneof:
+ def setter(self, new_value):
+ field_setter(self, new_value)
+ self._UpdateOneofState(field)
+ else:
+ setter = field_setter
+
setter.__module__ = None
setter.__doc__ = 'Setter for %s.' % proto_field_name
@@ -462,14 +541,22 @@ def _AddPropertiesForNonRepeatedCompositeField(field, cls):
# for non-repeated scalars.
proto_field_name = field.name
property_name = _PropertyName(proto_field_name)
+
+ # TODO(komarek): Can anyone explain to me why we cache the message_type this
+ # way, instead of referring to field.message_type inside of getter(self)?
+ # What if someone sets message_type later on (which makes for simpler
+ # dyanmic proto descriptor and class creation code).
message_type = field.message_type
def getter(self):
field_value = self._fields.get(field)
if field_value is None:
# Construct a new object to represent this field.
- field_value = message_type._concrete_class()
- field_value._SetListener(self._listener_for_children)
+ field_value = message_type._concrete_class() # use field.message_type?
+ field_value._SetListener(
+ _OneofListener(self, field)
+ if field.containing_oneof is not None
+ else self._listener_for_children)
# Atomically check if another thread has preempted us and, if not, swap
# in the new object we just created. If someone has preempted us, we
@@ -557,27 +644,48 @@ def _AddListFieldsMethod(message_descriptor, cls):
cls.ListFields = ListFields
+_Proto3HasError = 'Protocol message has no non-repeated submessage field "%s"'
+_Proto2HasError = 'Protocol message has no non-repeated field "%s"'
def _AddHasFieldMethod(message_descriptor, cls):
"""Helper for _AddMessageMethods()."""
- singular_fields = {}
+ is_proto3 = (message_descriptor.syntax == "proto3")
+ error_msg = _Proto3HasError if is_proto3 else _Proto2HasError
+
+ hassable_fields = {}
for field in message_descriptor.fields:
- if field.label != _FieldDescriptor.LABEL_REPEATED:
- singular_fields[field.name] = field
+ if field.label == _FieldDescriptor.LABEL_REPEATED:
+ continue
+ # For proto3, only submessages and fields inside a oneof have presence.
+ if (is_proto3 and field.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE and
+ not field.containing_oneof):
+ continue
+ hassable_fields[field.name] = field
+
+ if not is_proto3:
+ # Fields inside oneofs are never repeated (enforced by the compiler).
+ for oneof in message_descriptor.oneofs:
+ hassable_fields[oneof.name] = oneof
def HasField(self, field_name):
try:
- field = singular_fields[field_name]
+ field = hassable_fields[field_name]
except KeyError:
- raise ValueError(
- 'Protocol message has no singular "%s" field.' % field_name)
+ raise ValueError(error_msg % field_name)
- if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
- value = self._fields.get(field)
- return value is not None and value._is_present_in_parent
+ if isinstance(field, descriptor_mod.OneofDescriptor):
+ try:
+ return HasField(self, self._oneofs[field].name)
+ except KeyError:
+ return False
else:
- return field in self._fields
+ if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+ value = self._fields.get(field)
+ return value is not None and value._is_present_in_parent
+ else:
+ return field in self._fields
+
cls.HasField = HasField
@@ -587,7 +695,14 @@ def _AddClearFieldMethod(message_descriptor, cls):
try:
field = message_descriptor.fields_by_name[field_name]
except KeyError:
- raise ValueError('Protocol message has no "%s" field.' % field_name)
+ try:
+ field = message_descriptor.oneofs_by_name[field_name]
+ if field in self._oneofs:
+ field = self._oneofs[field]
+ else:
+ return
+ except KeyError:
+ raise ValueError('Protocol message has no "%s" field.' % field_name)
if field in self._fields:
# Note: If the field is a sub-message, its listener will still point
@@ -595,6 +710,9 @@ def _AddClearFieldMethod(message_descriptor, cls):
# will call _Modified() and invalidate our byte size. Big deal.
del self._fields[field]
+ if self._oneofs.get(field.containing_oneof, None) is field:
+ del self._oneofs[field.containing_oneof]
+
# Always call _Modified() -- even if nothing was changed, this is
# a mutating method, and thus calling it should cause the field to become
# present in the parent message.
@@ -620,6 +738,8 @@ def _AddClearMethod(message_descriptor, cls):
def Clear(self):
# Clear fields.
self._fields = {}
+ self._unknown_fields = ()
+ self._oneofs = {}
self._Modified()
cls.Clear = Clear
@@ -649,7 +769,16 @@ def _AddEqualsMethod(message_descriptor, cls):
if self is other:
return True
- return self.ListFields() == other.ListFields()
+ if not self.ListFields() == other.ListFields():
+ return False
+
+ # Sort unknown fields because their order shouldn't affect equality test.
+ unknown_fields = list(self._unknown_fields)
+ unknown_fields.sort()
+ other_unknown_fields = list(other._unknown_fields)
+ other_unknown_fields.sort()
+
+ return unknown_fields == other_unknown_fields
cls.__eq__ = __eq__
@@ -710,6 +839,9 @@ def _AddByteSizeMethod(message_descriptor, cls):
for field_descriptor, field_value in self.ListFields():
size += field_descriptor._sizer(field_value)
+ for tag_bytes, value_bytes in self._unknown_fields:
+ size += len(tag_bytes) + len(value_bytes)
+
self._cached_byte_size = size
self._cached_byte_size_dirty = False
self._listener_for_children.dirty = False
@@ -726,8 +858,8 @@ def _AddSerializeToStringMethod(message_descriptor, cls):
errors = []
if not self.IsInitialized():
raise message_mod.EncodeError(
- 'Message is missing required fields: ' +
- ','.join(self.FindInitializationErrors()))
+ 'Message %s is missing required fields: %s' % (
+ self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
return self.SerializePartialToString()
cls.SerializeToString = SerializeToString
@@ -736,7 +868,7 @@ def _AddSerializePartialToStringMethod(message_descriptor, cls):
"""Helper for _AddMessageMethods()."""
def SerializePartialToString(self):
- out = StringIO()
+ out = BytesIO()
self._InternalSerialize(out.write)
return out.getvalue()
cls.SerializePartialToString = SerializePartialToString
@@ -744,6 +876,9 @@ def _AddSerializePartialToStringMethod(message_descriptor, cls):
def InternalSerialize(self, write_bytes):
for field_descriptor, field_value in self.ListFields():
field_descriptor._encoder(write_bytes, field_value)
+ for tag_bytes, value_bytes in self._unknown_fields:
+ write_bytes(tag_bytes)
+ write_bytes(value_bytes)
cls._InternalSerialize = InternalSerialize
@@ -756,7 +891,8 @@ def _AddMergeFromStringMethod(message_descriptor, cls):
# The only reason _InternalParse would return early is if it
# encountered an end-group tag.
raise message_mod.DecodeError('Unexpected end-group tag.')
- except IndexError:
+ except (IndexError, TypeError):
+ # Now ord(buf[p:p+1]) == ord('') gets TypeError.
raise message_mod.DecodeError('Truncated message.')
except struct.error, e:
raise message_mod.DecodeError(e)
@@ -766,20 +902,30 @@ def _AddMergeFromStringMethod(message_descriptor, cls):
local_ReadTag = decoder.ReadTag
local_SkipField = decoder.SkipField
decoders_by_tag = cls._decoders_by_tag
+ is_proto3 = message_descriptor.syntax == "proto3"
def InternalParse(self, buffer, pos, end):
self._Modified()
field_dict = self._fields
+ unknown_field_list = self._unknown_fields
while pos != end:
(tag_bytes, new_pos) = local_ReadTag(buffer, pos)
- field_decoder = decoders_by_tag.get(tag_bytes)
+ field_decoder, field_desc = decoders_by_tag.get(tag_bytes, (None, None))
if field_decoder is None:
+ value_start_pos = new_pos
new_pos = local_SkipField(buffer, new_pos, end, tag_bytes)
if new_pos == -1:
return pos
+ if not is_proto3:
+ if not unknown_field_list:
+ unknown_field_list = self._unknown_fields = []
+ unknown_field_list.append(
+ (tag_bytes, buffer[value_start_pos:new_pos]))
pos = new_pos
else:
pos = field_decoder(buffer, new_pos, end, self, field_dict)
+ if field_desc:
+ self._UpdateOneofState(field_desc)
return pos
cls._InternalParse = InternalParse
@@ -812,7 +958,7 @@ def _AddIsInitializedMethod(message_descriptor, cls):
errors.extend(self.FindInitializationErrors())
return False
- for field, value in self._fields.iteritems():
+ for field, value in list(self._fields.items()): # dict can change size!
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
if field.label == _FieldDescriptor.LABEL_REPEATED:
for element in value:
@@ -873,7 +1019,8 @@ def _AddMergeFromMethod(cls):
def MergeFrom(self, msg):
if not isinstance(msg, cls):
raise TypeError(
- "Parameter to MergeFrom() must be instance of same class.")
+ "Parameter to MergeFrom() must be instance of same class: "
+ "expected %s got %s." % (cls.__name__, type(msg).__name__))
assert msg is not self
self._Modified()
@@ -895,12 +1042,40 @@ def _AddMergeFromMethod(cls):
# Construct a new object to represent this field.
field_value = field._default_constructor(self)
fields[field] = field_value
+ if field.containing_oneof:
+ self._UpdateOneofState(field)
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:
+ self._unknown_fields = []
+ self._unknown_fields.extend(msg._unknown_fields)
+
cls.MergeFrom = MergeFrom
+def _AddWhichOneofMethod(message_descriptor, cls):
+ def WhichOneof(self, oneof_name):
+ """Returns the name of the currently set field inside a oneof, or None."""
+ try:
+ field = message_descriptor.oneofs_by_name[oneof_name]
+ except KeyError:
+ raise ValueError(
+ 'Protocol message has no oneof "%s" field.' % oneof_name)
+
+ nested_field = self._oneofs.get(field, None)
+ if nested_field is not None and self.HasField(nested_field.name):
+ return nested_field.name
+ else:
+ return None
+
+ cls.WhichOneof = WhichOneof
+
+
def _AddMessageMethods(message_descriptor, cls):
"""Adds implementations of all Message methods to cls."""
_AddListFieldsMethod(message_descriptor, cls)
@@ -920,9 +1095,9 @@ def _AddMessageMethods(message_descriptor, cls):
_AddMergeFromStringMethod(message_descriptor, cls)
_AddIsInitializedMethod(message_descriptor, cls)
_AddMergeFromMethod(cls)
+ _AddWhichOneofMethod(message_descriptor, cls)
-
-def _AddPrivateHelperMethods(cls):
+def _AddPrivateHelperMethods(message_descriptor, cls):
"""Adds implementation of private helper methods to cls."""
def Modified(self):
@@ -940,8 +1115,20 @@ def _AddPrivateHelperMethods(cls):
self._is_present_in_parent = True
self._listener.Modified()
+ def _UpdateOneofState(self, field):
+ """Sets field as the active field in its containing oneof.
+
+ Will also delete currently active field in the oneof, if it is different
+ from the argument. Does not mark the message as modified.
+ """
+ other_field = self._oneofs.setdefault(field.containing_oneof, field)
+ if other_field is not field:
+ del self._fields[other_field]
+ self._oneofs[field.containing_oneof] = field
+
cls._Modified = Modified
cls.SetInParent = Modified
+ cls._UpdateOneofState = _UpdateOneofState
class _Listener(object):
@@ -990,6 +1177,27 @@ class _Listener(object):
pass
+class _OneofListener(_Listener):
+ """Special listener implementation for setting composite oneof fields."""
+
+ def __init__(self, parent_message, field):
+ """Args:
+ parent_message: The message whose _Modified() method we should call when
+ we receive Modified() messages.
+ field: The descriptor of the field being set in the parent message.
+ """
+ super(_OneofListener, self).__init__(parent_message)
+ self._field = field
+
+ def Modified(self):
+ """Also updates the state of the containing oneof in the parent message."""
+ try:
+ self._parent_message_weakref._UpdateOneofState(self._field)
+ super(_OneofListener, self).Modified()
+ except ReferenceError:
+ pass
+
+
# TODO(robinson): Move elsewhere? This file is getting pretty ridiculous...
# TODO(robinson): Unify error handling of "unknown extension" crap.
# TODO(robinson): Support iteritems()-style iteration over all
@@ -1080,10 +1288,10 @@ class _ExtensionDict(object):
# It's slightly wasteful to lookup the type checker each time,
# but we expect this to be a vanishingly uncommon case anyway.
- type_checker = type_checkers.GetTypeChecker(
- extension_handle.cpp_type, extension_handle.type)
- type_checker.CheckValue(value)
- self._extended_message._fields[extension_handle] = value
+ type_checker = type_checkers.GetTypeChecker(extension_handle)
+ # pylint: disable=protected-access
+ self._extended_message._fields[extension_handle] = (
+ type_checker.CheckValue(value))
self._extended_message._Modified()
def _FindExtensionByName(self, name):
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
index 7b9d3398..a62d9845 100755
--- a/python/google/protobuf/internal/reflection_test.py
+++ b/python/google/protobuf/internal/reflection_test.py
@@ -3,7 +3,7 @@
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -35,12 +35,12 @@
pure-Python protocol compiler.
"""
-__author__ = 'robinson@google.com (Will Robinson)'
-
+import copy
+import gc
import operator
import struct
-import unittest
+from google.apputils import basetest
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_pb2
@@ -48,6 +48,7 @@ from google.protobuf import descriptor_pb2
from google.protobuf import descriptor
from google.protobuf import message
from google.protobuf import reflection
+from google.protobuf import text_format
from google.protobuf.internal import api_implementation
from google.protobuf.internal import more_extensions_pb2
from google.protobuf.internal import more_messages_pb2
@@ -101,7 +102,7 @@ class _MiniDecoder(object):
return self._pos == len(self._bytes)
-class ReflectionTest(unittest.TestCase):
+class ReflectionTest(basetest.TestCase):
def assertListsEqual(self, values, others):
self.assertEqual(len(values), len(others))
@@ -318,15 +319,6 @@ class ReflectionTest(unittest.TestCase):
# ...and ensure that the scalar field has returned to its default.
self.assertEqual(0, getattr(composite_field, scalar_field_name))
- # Finally, ensure that modifications to the old composite field object
- # don't have any effect on the parent. Possible only with the pure-python
- # implementation of the API.
- #
- # (NOTE that when we clear the composite field in the parent, we actually
- # don't recursively clear down the tree. Instead, we just disconnect the
- # cleared composite from the tree.)
- if api_implementation.Type() != 'python':
- return
self.assertTrue(old_composite_field is not composite_field)
setattr(old_composite_field, scalar_field_name, new_val)
self.assertTrue(not composite_field.HasField(scalar_field_name))
@@ -348,8 +340,6 @@ class ReflectionTest(unittest.TestCase):
nested.bb = 23
def testDisconnectingNestedMessageBeforeSettingField(self):
- if api_implementation.Type() != 'python':
- return
proto = unittest_pb2.TestAllTypes()
nested = proto.optional_nested_message
proto.ClearField('optional_nested_message') # Should disconnect from parent
@@ -358,6 +348,64 @@ class ReflectionTest(unittest.TestCase):
self.assertTrue(not proto.HasField('optional_nested_message'))
self.assertEqual(0, proto.optional_nested_message.bb)
+ def testGetDefaultMessageAfterDisconnectingDefaultMessage(self):
+ proto = unittest_pb2.TestAllTypes()
+ nested = proto.optional_nested_message
+ proto.ClearField('optional_nested_message')
+ del proto
+ del nested
+ # Force a garbage collect so that the underlying CMessages are freed along
+ # with the Messages they point to. This is to make sure we're not deleting
+ # default message instances.
+ gc.collect()
+ proto = unittest_pb2.TestAllTypes()
+ nested = proto.optional_nested_message
+
+ def testDisconnectingNestedMessageAfterSettingField(self):
+ proto = unittest_pb2.TestAllTypes()
+ nested = proto.optional_nested_message
+ nested.bb = 5
+ self.assertTrue(proto.HasField('optional_nested_message'))
+ proto.ClearField('optional_nested_message') # Should disconnect from parent
+ self.assertEqual(5, nested.bb)
+ self.assertEqual(0, proto.optional_nested_message.bb)
+ self.assertTrue(nested is not proto.optional_nested_message)
+ nested.bb = 23
+ self.assertTrue(not proto.HasField('optional_nested_message'))
+ self.assertEqual(0, proto.optional_nested_message.bb)
+
+ def testDisconnectingNestedMessageBeforeGettingField(self):
+ proto = unittest_pb2.TestAllTypes()
+ self.assertTrue(not proto.HasField('optional_nested_message'))
+ proto.ClearField('optional_nested_message')
+ self.assertTrue(not proto.HasField('optional_nested_message'))
+
+ def testDisconnectingNestedMessageAfterMerge(self):
+ # This test exercises the code path that does not use ReleaseMessage().
+ # The underlying fear is that if we use ReleaseMessage() incorrectly,
+ # we will have memory leaks. It's hard to check that that doesn't happen,
+ # but at least we can exercise that code path to make sure it works.
+ proto1 = unittest_pb2.TestAllTypes()
+ proto2 = unittest_pb2.TestAllTypes()
+ proto2.optional_nested_message.bb = 5
+ proto1.MergeFrom(proto2)
+ self.assertTrue(proto1.HasField('optional_nested_message'))
+ proto1.ClearField('optional_nested_message')
+ self.assertTrue(not proto1.HasField('optional_nested_message'))
+
+ def testDisconnectingLazyNestedMessage(self):
+ # This test exercises releasing a nested message that is lazy. This test
+ # only exercises real code in the C++ implementation as Python does not
+ # support lazy parsing, but the current C++ implementation results in
+ # memory corruption and a crash.
+ if api_implementation.Type() != 'python':
+ return
+ proto = unittest_pb2.TestAllTypes()
+ proto.optional_lazy_message.bb = 5
+ proto.ClearField('optional_lazy_message')
+ del proto
+ gc.collect()
+
def testHasBitsWhenModifyingRepeatedFields(self):
# Test nesting when we add an element to a repeated field in a submessage.
proto = unittest_pb2.TestNestedMessageHasBits()
@@ -485,7 +533,7 @@ class ReflectionTest(unittest.TestCase):
self.assertEqual(0.0, proto.optional_double)
self.assertEqual(False, proto.optional_bool)
self.assertEqual('', proto.optional_string)
- self.assertEqual('', proto.optional_bytes)
+ self.assertEqual(b'', proto.optional_bytes)
self.assertEqual(41, proto.default_int32)
self.assertEqual(42, proto.default_int64)
@@ -501,7 +549,7 @@ class ReflectionTest(unittest.TestCase):
self.assertEqual(52e3, proto.default_double)
self.assertEqual(True, proto.default_bool)
self.assertEqual('hello', proto.default_string)
- self.assertEqual('world', proto.default_bytes)
+ self.assertEqual(b'world', proto.default_bytes)
self.assertEqual(unittest_pb2.TestAllTypes.BAR, proto.default_nested_enum)
self.assertEqual(unittest_pb2.FOREIGN_BAR, proto.default_foreign_enum)
self.assertEqual(unittest_import_pb2.IMPORT_BAR,
@@ -518,6 +566,17 @@ class ReflectionTest(unittest.TestCase):
proto = unittest_pb2.TestAllTypes()
self.assertRaises(ValueError, proto.ClearField, 'nonexistent_field')
+ def testClearRemovesChildren(self):
+ # Make sure there aren't any implementation bugs that are only partially
+ # clearing the message (which can happen in the more complex C++
+ # implementation which has parallel message lists).
+ proto = unittest_pb2.TestRequiredForeign()
+ for i in range(10):
+ proto.repeated_message.add()
+ proto2 = unittest_pb2.TestRequiredForeign()
+ proto.CopyFrom(proto2)
+ self.assertRaises(IndexError, lambda: proto.repeated_message[5])
+
def testDisallowedAssignments(self):
# It's illegal to assign values directly to repeated fields
# or to nonrepeated composite fields. Ensure that this fails.
@@ -546,6 +605,30 @@ class ReflectionTest(unittest.TestCase):
self.assertRaises(TypeError, setattr, proto, 'optional_string', 10)
self.assertRaises(TypeError, setattr, proto, 'optional_bytes', 10)
+ def testIntegerTypes(self):
+ def TestGetAndDeserialize(field_name, value, expected_type):
+ proto = unittest_pb2.TestAllTypes()
+ setattr(proto, field_name, value)
+ self.assertTrue(isinstance(getattr(proto, field_name), expected_type))
+ proto2 = unittest_pb2.TestAllTypes()
+ proto2.ParseFromString(proto.SerializeToString())
+ self.assertTrue(isinstance(getattr(proto2, field_name), expected_type))
+
+ TestGetAndDeserialize('optional_int32', 1, int)
+ TestGetAndDeserialize('optional_int32', 1 << 30, int)
+ TestGetAndDeserialize('optional_uint32', 1 << 30, int)
+ if struct.calcsize('L') == 4:
+ # Python only has signed ints, so 32-bit python can't fit an uint32
+ # in an int.
+ TestGetAndDeserialize('optional_uint32', 1 << 31, long)
+ else:
+ # 64-bit python can fit uint32 inside an int
+ TestGetAndDeserialize('optional_uint32', 1 << 31, int)
+ TestGetAndDeserialize('optional_int64', 1 << 30, long)
+ TestGetAndDeserialize('optional_int64', 1 << 60, long)
+ TestGetAndDeserialize('optional_uint64', 1 << 30, long)
+ TestGetAndDeserialize('optional_uint64', 1 << 60, long)
+
def testSingleScalarBoundsChecking(self):
def TestMinAndMaxIntegers(field_name, expected_min, expected_max):
pb = unittest_pb2.TestAllTypes()
@@ -565,29 +648,6 @@ class ReflectionTest(unittest.TestCase):
pb.optional_nested_enum = 1
self.assertEqual(1, pb.optional_nested_enum)
- # Invalid enum values.
- pb.optional_nested_enum = 0
- self.assertEqual(0, pb.optional_nested_enum)
-
- bytes_size_before = pb.ByteSize()
-
- pb.optional_nested_enum = 4
- self.assertEqual(4, pb.optional_nested_enum)
-
- pb.optional_nested_enum = 0
- self.assertEqual(0, pb.optional_nested_enum)
-
- # Make sure that setting the same enum field doesn't just add unknown
- # fields (but overwrites them).
- self.assertEqual(bytes_size_before, pb.ByteSize())
-
- # Is the invalid value preserved after serialization?
- serialized = pb.SerializeToString()
- pb2 = unittest_pb2.TestAllTypes()
- pb2.ParseFromString(serialized)
- self.assertEqual(0, pb2.optional_nested_enum)
- self.assertEqual(pb, pb2)
-
def testRepeatedScalarTypeSafety(self):
proto = unittest_pb2.TestAllTypes()
self.assertRaises(TypeError, proto.repeated_int32.append, 1.1)
@@ -635,6 +695,77 @@ class ReflectionTest(unittest.TestCase):
self.assertEqual(3, proto.BAZ)
self.assertEqual(3, unittest_pb2.TestAllTypes.BAZ)
+ def testEnum_Name(self):
+ self.assertEqual('FOREIGN_FOO',
+ unittest_pb2.ForeignEnum.Name(unittest_pb2.FOREIGN_FOO))
+ self.assertEqual('FOREIGN_BAR',
+ unittest_pb2.ForeignEnum.Name(unittest_pb2.FOREIGN_BAR))
+ self.assertEqual('FOREIGN_BAZ',
+ unittest_pb2.ForeignEnum.Name(unittest_pb2.FOREIGN_BAZ))
+ self.assertRaises(ValueError,
+ unittest_pb2.ForeignEnum.Name, 11312)
+
+ proto = unittest_pb2.TestAllTypes()
+ self.assertEqual('FOO',
+ proto.NestedEnum.Name(proto.FOO))
+ self.assertEqual('FOO',
+ unittest_pb2.TestAllTypes.NestedEnum.Name(proto.FOO))
+ self.assertEqual('BAR',
+ proto.NestedEnum.Name(proto.BAR))
+ self.assertEqual('BAR',
+ unittest_pb2.TestAllTypes.NestedEnum.Name(proto.BAR))
+ self.assertEqual('BAZ',
+ proto.NestedEnum.Name(proto.BAZ))
+ self.assertEqual('BAZ',
+ unittest_pb2.TestAllTypes.NestedEnum.Name(proto.BAZ))
+ self.assertRaises(ValueError,
+ proto.NestedEnum.Name, 11312)
+ self.assertRaises(ValueError,
+ unittest_pb2.TestAllTypes.NestedEnum.Name, 11312)
+
+ def testEnum_Value(self):
+ self.assertEqual(unittest_pb2.FOREIGN_FOO,
+ unittest_pb2.ForeignEnum.Value('FOREIGN_FOO'))
+ self.assertEqual(unittest_pb2.FOREIGN_BAR,
+ unittest_pb2.ForeignEnum.Value('FOREIGN_BAR'))
+ self.assertEqual(unittest_pb2.FOREIGN_BAZ,
+ unittest_pb2.ForeignEnum.Value('FOREIGN_BAZ'))
+ self.assertRaises(ValueError,
+ unittest_pb2.ForeignEnum.Value, 'FO')
+
+ proto = unittest_pb2.TestAllTypes()
+ self.assertEqual(proto.FOO,
+ proto.NestedEnum.Value('FOO'))
+ self.assertEqual(proto.FOO,
+ unittest_pb2.TestAllTypes.NestedEnum.Value('FOO'))
+ self.assertEqual(proto.BAR,
+ proto.NestedEnum.Value('BAR'))
+ self.assertEqual(proto.BAR,
+ unittest_pb2.TestAllTypes.NestedEnum.Value('BAR'))
+ self.assertEqual(proto.BAZ,
+ proto.NestedEnum.Value('BAZ'))
+ self.assertEqual(proto.BAZ,
+ unittest_pb2.TestAllTypes.NestedEnum.Value('BAZ'))
+ self.assertRaises(ValueError,
+ proto.NestedEnum.Value, 'Foo')
+ self.assertRaises(ValueError,
+ unittest_pb2.TestAllTypes.NestedEnum.Value, 'Foo')
+
+ def testEnum_KeysAndValues(self):
+ self.assertEqual(['FOREIGN_FOO', 'FOREIGN_BAR', 'FOREIGN_BAZ'],
+ unittest_pb2.ForeignEnum.keys())
+ self.assertEqual([4, 5, 6],
+ unittest_pb2.ForeignEnum.values())
+ self.assertEqual([('FOREIGN_FOO', 4), ('FOREIGN_BAR', 5),
+ ('FOREIGN_BAZ', 6)],
+ unittest_pb2.ForeignEnum.items())
+
+ proto = unittest_pb2.TestAllTypes()
+ self.assertEqual(['FOO', 'BAR', 'BAZ', 'NEG'], proto.NestedEnum.keys())
+ self.assertEqual([1, 2, 3, -1], proto.NestedEnum.values())
+ self.assertEqual([('FOO', 1), ('BAR', 2), ('BAZ', 3), ('NEG', -1)],
+ proto.NestedEnum.items())
+
def testRepeatedScalars(self):
proto = unittest_pb2.TestAllTypes()
@@ -826,6 +957,35 @@ class ReflectionTest(unittest.TestCase):
self.assertEqual(1, len(proto.repeated_nested_message))
self.assertEqual(23, proto.repeated_nested_message[0].bb)
+ def testRepeatedCompositeRemove(self):
+ proto = unittest_pb2.TestAllTypes()
+
+ self.assertEqual(0, len(proto.repeated_nested_message))
+ m0 = proto.repeated_nested_message.add()
+ # Need to set some differentiating variable so m0 != m1 != m2:
+ m0.bb = len(proto.repeated_nested_message)
+ m1 = proto.repeated_nested_message.add()
+ m1.bb = len(proto.repeated_nested_message)
+ self.assertTrue(m0 != m1)
+ m2 = proto.repeated_nested_message.add()
+ m2.bb = len(proto.repeated_nested_message)
+ self.assertListsEqual([m0, m1, m2], proto.repeated_nested_message)
+
+ self.assertEqual(3, len(proto.repeated_nested_message))
+ proto.repeated_nested_message.remove(m0)
+ self.assertEqual(2, len(proto.repeated_nested_message))
+ self.assertEqual(m1, proto.repeated_nested_message[0])
+ self.assertEqual(m2, proto.repeated_nested_message[1])
+
+ # Removing m0 again or removing None should raise error
+ self.assertRaises(ValueError, proto.repeated_nested_message.remove, m0)
+ self.assertRaises(ValueError, proto.repeated_nested_message.remove, None)
+ self.assertEqual(2, len(proto.repeated_nested_message))
+
+ proto.repeated_nested_message.remove(m2)
+ self.assertEqual(1, len(proto.repeated_nested_message))
+ self.assertEqual(m1, proto.repeated_nested_message[0])
+
def testHandWrittenReflection(self):
# Hand written extensions are only supported by the pure-Python
# implementation of the API.
@@ -856,6 +1016,68 @@ class ReflectionTest(unittest.TestCase):
self.assertEqual(23, myproto_instance.foo_field)
self.assertTrue(myproto_instance.HasField('foo_field'))
+ def testDescriptorProtoSupport(self):
+ # Hand written descriptors/reflection are only supported by the pure-Python
+ # implementation of the API.
+ if api_implementation.Type() != 'python':
+ return
+
+ def AddDescriptorField(proto, field_name, field_type):
+ AddDescriptorField.field_index += 1
+ new_field = proto.field.add()
+ new_field.name = field_name
+ new_field.type = field_type
+ new_field.number = AddDescriptorField.field_index
+ new_field.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL
+
+ AddDescriptorField.field_index = 0
+
+ desc_proto = descriptor_pb2.DescriptorProto()
+ desc_proto.name = 'Car'
+ fdp = descriptor_pb2.FieldDescriptorProto
+ AddDescriptorField(desc_proto, 'name', fdp.TYPE_STRING)
+ AddDescriptorField(desc_proto, 'year', fdp.TYPE_INT64)
+ AddDescriptorField(desc_proto, 'automatic', fdp.TYPE_BOOL)
+ AddDescriptorField(desc_proto, 'price', fdp.TYPE_DOUBLE)
+ # Add a repeated field
+ AddDescriptorField.field_index += 1
+ new_field = desc_proto.field.add()
+ new_field.name = 'owners'
+ new_field.type = fdp.TYPE_STRING
+ new_field.number = AddDescriptorField.field_index
+ new_field.label = descriptor_pb2.FieldDescriptorProto.LABEL_REPEATED
+
+ desc = descriptor.MakeDescriptor(desc_proto)
+ self.assertTrue(desc.fields_by_name.has_key('name'))
+ self.assertTrue(desc.fields_by_name.has_key('year'))
+ self.assertTrue(desc.fields_by_name.has_key('automatic'))
+ self.assertTrue(desc.fields_by_name.has_key('price'))
+ self.assertTrue(desc.fields_by_name.has_key('owners'))
+
+ class CarMessage(message.Message):
+ __metaclass__ = reflection.GeneratedProtocolMessageType
+ DESCRIPTOR = desc
+
+ prius = CarMessage()
+ prius.name = 'prius'
+ prius.year = 2010
+ prius.automatic = True
+ prius.price = 25134.75
+ prius.owners.extend(['bob', 'susan'])
+
+ serialized_prius = prius.SerializeToString()
+ new_prius = reflection.ParseMessage(desc, serialized_prius)
+ self.assertTrue(new_prius is not prius)
+ self.assertEqual(prius, new_prius)
+
+ # these are unnecessary assuming message equality works as advertised but
+ # explicitly check to be safe since we're mucking about in metaclass foo
+ self.assertEqual(prius.name, new_prius.name)
+ self.assertEqual(prius.year, new_prius.year)
+ self.assertEqual(prius.automatic, new_prius.automatic)
+ self.assertEqual(prius.price, new_prius.price)
+ self.assertEqual(prius.owners, new_prius.owners)
+
def testTopLevelExtensionsForOptionalScalar(self):
extendee_proto = unittest_pb2.TestAllExtensions()
extension = unittest_pb2.optional_int32_extension
@@ -945,6 +1167,14 @@ class ReflectionTest(unittest.TestCase):
self.assertTrue(required is not extendee_proto.Extensions[extension])
self.assertTrue(not extendee_proto.HasExtension(extension))
+ def testRegisteredExtensions(self):
+ self.assertTrue('protobuf_unittest.optional_int32_extension' in
+ unittest_pb2.TestAllExtensions._extensions_by_name)
+ self.assertTrue(1 in unittest_pb2.TestAllExtensions._extensions_by_number)
+ # Make sure extensions haven't been registered into types that shouldn't
+ # have any.
+ self.assertEquals(0, len(unittest_pb2.TestAllTypes._extensions_by_name))
+
# If message A directly contains message B, and
# a.HasField('b') is currently False, then mutating any
# extension in B should change a.HasField('b') to True
@@ -1020,15 +1250,18 @@ class ReflectionTest(unittest.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
@@ -1241,9 +1474,27 @@ class ReflectionTest(unittest.TestCase):
proto2 = unittest_pb2.TestAllExtensions()
self.assertRaises(TypeError, proto1.CopyFrom, proto2)
+ def testDeepCopy(self):
+ proto1 = unittest_pb2.TestAllTypes()
+ proto1.optional_int32 = 1
+ proto2 = copy.deepcopy(proto1)
+ self.assertEqual(1, proto2.optional_int32)
+
+ proto1.repeated_int32.append(2)
+ proto1.repeated_int32.append(3)
+ container = copy.deepcopy(proto1.repeated_int32)
+ self.assertEqual([2, 3], container)
+
+ # TODO(anuraag): Implement deepcopy for repeated composite / extension dict
+
def testClear(self):
proto = unittest_pb2.TestAllTypes()
- test_util.SetAllFields(proto)
+ # C++ implementation does not support lazy fields right now so leave it
+ # out for now.
+ if api_implementation.Type() == 'python':
+ test_util.SetAllFields(proto)
+ else:
+ test_util.SetAllNonLazyFields(proto)
# Clear the message.
proto.Clear()
self.assertEquals(proto.ByteSize(), 0)
@@ -1259,6 +1510,45 @@ class ReflectionTest(unittest.TestCase):
empty_proto = unittest_pb2.TestAllExtensions()
self.assertEquals(proto, empty_proto)
+ def testDisconnectingBeforeClear(self):
+ proto = unittest_pb2.TestAllTypes()
+ nested = proto.optional_nested_message
+ proto.Clear()
+ self.assertTrue(nested is not proto.optional_nested_message)
+ nested.bb = 23
+ self.assertTrue(not proto.HasField('optional_nested_message'))
+ self.assertEqual(0, proto.optional_nested_message.bb)
+
+ proto = unittest_pb2.TestAllTypes()
+ nested = proto.optional_nested_message
+ nested.bb = 5
+ foreign = proto.optional_foreign_message
+ foreign.c = 6
+
+ proto.Clear()
+ self.assertTrue(nested is not proto.optional_nested_message)
+ self.assertTrue(foreign is not proto.optional_foreign_message)
+ self.assertEqual(5, nested.bb)
+ self.assertEqual(6, foreign.c)
+ nested.bb = 15
+ foreign.c = 16
+ self.assertFalse(proto.HasField('optional_nested_message'))
+ self.assertEqual(0, proto.optional_nested_message.bb)
+ self.assertFalse(proto.HasField('optional_foreign_message'))
+ self.assertEqual(0, proto.optional_foreign_message.c)
+
+ def testOneOf(self):
+ proto = unittest_pb2.TestAllTypes()
+ proto.oneof_uint32 = 10
+ proto.oneof_nested_message.bb = 11
+ self.assertEqual(11, proto.oneof_nested_message.bb)
+ self.assertFalse(proto.HasField('oneof_uint32'))
+ nested = proto.oneof_nested_message
+ proto.oneof_string = 'abc'
+ self.assertEqual('abc', proto.oneof_string)
+ self.assertEqual(11, nested.bb)
+ self.assertFalse(proto.HasField('oneof_nested_message'))
+
def assertInitialized(self, proto):
self.assertTrue(proto.IsInitialized())
# Neither method should raise an exception.
@@ -1329,6 +1619,40 @@ class ReflectionTest(unittest.TestCase):
self.assertFalse(proto.IsInitialized(errors))
self.assertEqual(errors, ['a', 'b', 'c'])
+ @basetest.unittest.skipIf(
+ api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
+ 'Errors are only available from the most recent C++ implementation.')
+ def testFileDescriptorErrors(self):
+ file_name = 'test_file_descriptor_errors.proto'
+ package_name = 'test_file_descriptor_errors.proto'
+ file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
+ file_descriptor_proto.name = file_name
+ file_descriptor_proto.package = package_name
+ m1 = file_descriptor_proto.message_type.add()
+ m1.name = 'msg1'
+ # Compiles the proto into the C++ descriptor pool
+ descriptor.FileDescriptor(
+ file_name,
+ package_name,
+ serialized_pb=file_descriptor_proto.SerializeToString())
+ # Add a FileDescriptorProto that has duplicate symbols
+ another_file_name = 'another_test_file_descriptor_errors.proto'
+ file_descriptor_proto.name = another_file_name
+ m2 = file_descriptor_proto.message_type.add()
+ m2.name = 'msg2'
+ with self.assertRaises(TypeError) as cm:
+ descriptor.FileDescriptor(
+ another_file_name,
+ package_name,
+ serialized_pb=file_descriptor_proto.SerializeToString())
+ self.assertTrue(hasattr(cm, 'exception'), '%s not raised' %
+ getattr(cm.expected, '__name__', cm.expected))
+ self.assertIn('test_file_descriptor_errors.proto', str(cm.exception))
+ # Error message will say something about this definition being a
+ # duplicate, though we don't check the message exactly to avoid a
+ # dependency on the C++ logging code.
+ self.assertIn('test_file_descriptor_errors.msg1', str(cm.exception))
+
def testStringUTF8Encoding(self):
proto = unittest_pb2.TestAllTypes()
@@ -1346,18 +1670,15 @@ class ReflectionTest(unittest.TestCase):
proto.optional_string = str('Testing')
self.assertEqual(proto.optional_string, unicode('Testing'))
- if api_implementation.Type() == 'python':
- # Values of type 'str' are also accepted as long as they can be
- # encoded in UTF-8.
- self.assertEqual(type(proto.optional_string), str)
-
- # Try to assign a 'str' value which contains bytes that aren't 7-bit ASCII.
- self.assertRaises(ValueError,
- setattr, proto, 'optional_string', str('a\x80a'))
- # Assign a 'str' object which contains a UTF-8 encoded string.
+ # Try to assign a 'bytes' object which contains non-UTF-8.
self.assertRaises(ValueError,
- setattr, proto, 'optional_string', 'ТеÑÑ‚')
- # No exception thrown.
+ setattr, proto, 'optional_string', b'a\x80a')
+ # 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):
@@ -1379,7 +1700,8 @@ class ReflectionTest(unittest.TestCase):
self.assertEqual(proto.ByteSize(), len(serialized))
raw = unittest_mset_pb2.RawMessageSet()
- raw.MergeFromString(serialized)
+ bytes_read = raw.MergeFromString(serialized)
+ self.assertEqual(len(serialized), bytes_read)
message2 = unittest_mset_pb2.TestMessageSetExtension2()
@@ -1390,7 +1712,8 @@ class ReflectionTest(unittest.TestCase):
# Check the actual bytes on the wire.
self.assertTrue(
raw.item[0].message.endswith(test_utf8_bytes))
- message2.MergeFromString(raw.item[0].message)
+ bytes_read = message2.MergeFromString(raw.item[0].message)
+ self.assertEqual(len(raw.item[0].message), bytes_read)
self.assertEqual(type(message2.str), unicode)
self.assertEqual(message2.str, test_utf8)
@@ -1401,17 +1724,22 @@ class ReflectionTest(unittest.TestCase):
# MergeFromString and thus has no way to throw the exception.
#
# The pure Python API always returns objects of type 'unicode' (UTF-8
- # encoded), or 'str' (in 7 bit ASCII).
- bytes = raw.item[0].message.replace(
- test_utf8_bytes, len(test_utf8_bytes) * '\xff')
+ # encoded), or 'bytes' (in 7 bit ASCII).
+ badbytes = raw.item[0].message.replace(
+ test_utf8_bytes, len(test_utf8_bytes) * b'\xff')
unicode_decode_failed = False
try:
- message2.MergeFromString(bytes)
- except UnicodeDecodeError, e:
+ message2.MergeFromString(badbytes)
+ except UnicodeDecodeError:
unicode_decode_failed = True
string_field = message2.str
- self.assertTrue(unicode_decode_failed or type(string_field) == str)
+ self.assertTrue(unicode_decode_failed or type(string_field) is bytes)
+
+ def testBytesInTextFormat(self):
+ proto = unittest_pb2.TestAllTypes(optional_bytes=b'\x00\x7f\x80\xff')
+ self.assertEqual(u'optional_bytes: "\\000\\177\\200\\377"\n',
+ unicode(proto))
def testEmptyNestedMessage(self):
proto = unittest_pb2.TestAllTypes()
@@ -1425,16 +1753,19 @@ class ReflectionTest(unittest.TestCase):
self.assertTrue(proto.HasField('optional_nested_message'))
proto = unittest_pb2.TestAllTypes()
- proto.optional_nested_message.MergeFromString('')
+ bytes_read = proto.optional_nested_message.MergeFromString(b'')
+ self.assertEqual(0, bytes_read)
self.assertTrue(proto.HasField('optional_nested_message'))
proto = unittest_pb2.TestAllTypes()
- proto.optional_nested_message.ParseFromString('')
+ proto.optional_nested_message.ParseFromString(b'')
self.assertTrue(proto.HasField('optional_nested_message'))
serialized = proto.SerializeToString()
proto2 = unittest_pb2.TestAllTypes()
- proto2.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ proto2.MergeFromString(serialized))
self.assertTrue(proto2.HasField('optional_nested_message'))
def testSetInParent(self):
@@ -1443,12 +1774,41 @@ class ReflectionTest(unittest.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)
+
+ @basetest.unittest.skipIf(
+ api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
+ 'CPPv2-specific test')
+ def testBadArguments(self):
+ # Some of these assertions used to segfault.
+ from google.protobuf.pyext import _message
+ self.assertRaises(TypeError, _message.Message._GetFieldDescriptor, 3)
+ self.assertRaises(TypeError, _message.Message._GetExtensionDescriptor, 42)
+ self.assertRaises(TypeError,
+ unittest_pb2.TestAllTypes().__getattribute__, 42)
+
# Since we had so many tests for protocol buffer equality, we broke these out
# into separate TestCase classes.
-class TestAllTypesEqualityTest(unittest.TestCase):
+class TestAllTypesEqualityTest(basetest.TestCase):
def setUp(self):
self.first_proto = unittest_pb2.TestAllTypes()
@@ -1464,7 +1824,7 @@ class TestAllTypesEqualityTest(unittest.TestCase):
self.assertEqual(self.first_proto, self.second_proto)
-class FullProtosEqualityTest(unittest.TestCase):
+class FullProtosEqualityTest(basetest.TestCase):
"""Equality tests using completely-full protos as a starting point."""
@@ -1550,7 +1910,7 @@ class FullProtosEqualityTest(unittest.TestCase):
self.assertEqual(self.first_proto, self.second_proto)
-class ExtensionEqualityTest(unittest.TestCase):
+class ExtensionEqualityTest(basetest.TestCase):
def testExtensionEquality(self):
first_proto = unittest_pb2.TestAllExtensions()
@@ -1583,7 +1943,7 @@ class ExtensionEqualityTest(unittest.TestCase):
self.assertEqual(first_proto, second_proto)
-class MutualRecursionEqualityTest(unittest.TestCase):
+class MutualRecursionEqualityTest(basetest.TestCase):
def testEqualityWithMutualRecursion(self):
first_proto = unittest_pb2.TestMutualRecursionA()
@@ -1595,7 +1955,7 @@ class MutualRecursionEqualityTest(unittest.TestCase):
self.assertEqual(first_proto, second_proto)
-class ByteSizeTest(unittest.TestCase):
+class ByteSizeTest(basetest.TestCase):
def setUp(self):
self.proto = unittest_pb2.TestAllTypes()
@@ -1891,14 +2251,16 @@ class ByteSizeTest(unittest.TestCase):
# * Handling of empty submessages (with and without "has"
# bits set).
-class SerializationTest(unittest.TestCase):
+class SerializationTest(basetest.TestCase):
def testSerializeEmtpyMessage(self):
first_proto = unittest_pb2.TestAllTypes()
second_proto = unittest_pb2.TestAllTypes()
serialized = first_proto.SerializeToString()
self.assertEqual(first_proto.ByteSize(), len(serialized))
- second_proto.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ second_proto.MergeFromString(serialized))
self.assertEqual(first_proto, second_proto)
def testSerializeAllFields(self):
@@ -1907,7 +2269,9 @@ class SerializationTest(unittest.TestCase):
test_util.SetAllFields(first_proto)
serialized = first_proto.SerializeToString()
self.assertEqual(first_proto.ByteSize(), len(serialized))
- second_proto.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ second_proto.MergeFromString(serialized))
self.assertEqual(first_proto, second_proto)
def testSerializeAllExtensions(self):
@@ -1915,7 +2279,19 @@ class SerializationTest(unittest.TestCase):
second_proto = unittest_pb2.TestAllExtensions()
test_util.SetAllExtensions(first_proto)
serialized = first_proto.SerializeToString()
- second_proto.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ second_proto.MergeFromString(serialized))
+ self.assertEqual(first_proto, second_proto)
+
+ def testSerializeWithOptionalGroup(self):
+ first_proto = unittest_pb2.TestAllTypes()
+ second_proto = unittest_pb2.TestAllTypes()
+ first_proto.optionalgroup.a = 242
+ serialized = first_proto.SerializeToString()
+ self.assertEqual(
+ len(serialized),
+ second_proto.MergeFromString(serialized))
self.assertEqual(first_proto, second_proto)
def testSerializeNegativeValues(self):
@@ -2007,7 +2383,9 @@ class SerializationTest(unittest.TestCase):
second_proto.optional_int32 = 100
second_proto.optional_nested_message.bb = 999
- second_proto.MergeFromString(serialized)
+ bytes_parsed = second_proto.MergeFromString(serialized)
+ self.assertEqual(len(serialized), bytes_parsed)
+
# Ensure that we append to repeated fields.
self.assertEqual(['baz', 'foobar'], list(second_proto.repeated_string))
# Ensure that we overwrite nonrepeatd scalars.
@@ -2032,20 +2410,28 @@ class SerializationTest(unittest.TestCase):
raw = unittest_mset_pb2.RawMessageSet()
self.assertEqual(False,
raw.DESCRIPTOR.GetOptions().message_set_wire_format)
- raw.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ raw.MergeFromString(serialized))
self.assertEqual(2, len(raw.item))
message1 = unittest_mset_pb2.TestMessageSetExtension1()
- message1.MergeFromString(raw.item[0].message)
+ self.assertEqual(
+ len(raw.item[0].message),
+ message1.MergeFromString(raw.item[0].message))
self.assertEqual(123, message1.i)
message2 = unittest_mset_pb2.TestMessageSetExtension2()
- message2.MergeFromString(raw.item[1].message)
+ self.assertEqual(
+ len(raw.item[1].message),
+ message2.MergeFromString(raw.item[1].message))
self.assertEqual('foo', message2.str)
# Deserialize using the MessageSet wire format.
proto2 = unittest_mset_pb2.TestMessageSet()
- proto2.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ proto2.MergeFromString(serialized))
self.assertEqual(123, proto2.Extensions[extension1].i)
self.assertEqual('foo', proto2.Extensions[extension2].str)
@@ -2085,7 +2471,9 @@ class SerializationTest(unittest.TestCase):
# Parse message using the message set wire format.
proto = unittest_mset_pb2.TestMessageSet()
- proto.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ proto.MergeFromString(serialized))
# Check that the message parsed well.
extension_message1 = unittest_mset_pb2.TestMessageSetExtension1
@@ -2103,7 +2491,9 @@ class SerializationTest(unittest.TestCase):
proto2 = unittest_pb2.TestEmptyMessage()
# Parsing this message should succeed.
- proto2.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ proto2.MergeFromString(serialized))
# Now test with a int64 field set.
proto = unittest_pb2.TestAllTypes()
@@ -2113,13 +2503,15 @@ class SerializationTest(unittest.TestCase):
# unknown.
proto2 = unittest_pb2.TestEmptyMessage()
# Parsing this message should succeed.
- proto2.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ proto2.MergeFromString(serialized))
def _CheckRaises(self, exc_class, callable_obj, exception):
"""This method checks if the excpetion type and message are as expected."""
try:
callable_obj()
- except exc_class, ex:
+ except exc_class as ex:
# Check if the exception message is the right one.
self.assertEqual(exception, str(ex))
return
@@ -2131,15 +2523,22 @@ class SerializationTest(unittest.TestCase):
self._CheckRaises(
message.EncodeError,
proto.SerializeToString,
- 'Message is missing required fields: a,b,c')
+ 'Message protobuf_unittest.TestRequired is missing required fields: '
+ 'a,b,c')
# Shouldn't raise exceptions.
partial = proto.SerializePartialToString()
+ proto2 = unittest_pb2.TestRequired()
+ self.assertFalse(proto2.HasField('a'))
+ # proto2 ParseFromString does not check that required fields are set.
+ proto2.ParseFromString(partial)
+ self.assertFalse(proto2.HasField('a'))
+
proto.a = 1
self._CheckRaises(
message.EncodeError,
proto.SerializeToString,
- 'Message is missing required fields: b,c')
+ 'Message protobuf_unittest.TestRequired is missing required fields: b,c')
# Shouldn't raise exceptions.
partial = proto.SerializePartialToString()
@@ -2147,7 +2546,7 @@ class SerializationTest(unittest.TestCase):
self._CheckRaises(
message.EncodeError,
proto.SerializeToString,
- 'Message is missing required fields: c')
+ 'Message protobuf_unittest.TestRequired is missing required fields: c')
# Shouldn't raise exceptions.
partial = proto.SerializePartialToString()
@@ -2157,11 +2556,15 @@ class SerializationTest(unittest.TestCase):
partial = proto.SerializePartialToString()
proto2 = unittest_pb2.TestRequired()
- proto2.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ proto2.MergeFromString(serialized))
self.assertEqual(1, proto2.a)
self.assertEqual(2, proto2.b)
self.assertEqual(3, proto2.c)
- proto2.ParseFromString(partial)
+ self.assertEqual(
+ len(partial),
+ proto2.MergeFromString(partial))
self.assertEqual(1, proto2.a)
self.assertEqual(2, proto2.b)
self.assertEqual(3, proto2.c)
@@ -2176,7 +2579,8 @@ class SerializationTest(unittest.TestCase):
self._CheckRaises(
message.EncodeError,
proto.SerializeToString,
- 'Message is missing required fields: '
+ 'Message protobuf_unittest.TestRequiredForeign '
+ 'is missing required fields: '
'optional_message.b,optional_message.c')
proto.optional_message.b = 2
@@ -2188,7 +2592,7 @@ class SerializationTest(unittest.TestCase):
self._CheckRaises(
message.EncodeError,
proto.SerializeToString,
- 'Message is missing required fields: '
+ 'Message protobuf_unittest.TestRequiredForeign is missing required fields: '
'repeated_message[0].b,repeated_message[0].c,'
'repeated_message[1].a,repeated_message[1].c')
@@ -2228,7 +2632,9 @@ class SerializationTest(unittest.TestCase):
second_proto.packed_double.extend([1.0, 2.0])
second_proto.packed_sint32.append(4)
- second_proto.MergeFromString(serialized)
+ self.assertEqual(
+ len(serialized),
+ second_proto.MergeFromString(serialized))
self.assertEqual([3, 1, 2], second_proto.packed_int32)
self.assertEqual([1.0, 2.0, 3.0], second_proto.packed_double)
self.assertEqual([4], second_proto.packed_sint32)
@@ -2261,7 +2667,10 @@ class SerializationTest(unittest.TestCase):
unpacked = unittest_pb2.TestUnpackedTypes()
test_util.SetAllUnpackedFields(unpacked)
packed = unittest_pb2.TestPackedTypes()
- packed.MergeFromString(unpacked.SerializeToString())
+ serialized = unpacked.SerializeToString()
+ self.assertEqual(
+ len(serialized),
+ packed.MergeFromString(serialized))
expected = unittest_pb2.TestPackedTypes()
test_util.SetAllPackedFields(expected)
self.assertEqual(expected, packed)
@@ -2270,7 +2679,10 @@ class SerializationTest(unittest.TestCase):
packed = unittest_pb2.TestPackedTypes()
test_util.SetAllPackedFields(packed)
unpacked = unittest_pb2.TestUnpackedTypes()
- unpacked.MergeFromString(packed.SerializeToString())
+ serialized = packed.SerializeToString()
+ self.assertEqual(
+ len(serialized),
+ unpacked.MergeFromString(serialized))
expected = unittest_pb2.TestUnpackedTypes()
test_util.SetAllUnpackedFields(expected)
self.assertEqual(expected, unpacked)
@@ -2322,7 +2734,7 @@ class SerializationTest(unittest.TestCase):
optional_int32=1,
optional_string='foo',
optional_bool=True,
- optional_bytes='bar',
+ optional_bytes=b'bar',
optional_nested_message=unittest_pb2.TestAllTypes.NestedMessage(bb=1),
optional_foreign_message=unittest_pb2.ForeignMessage(c=1),
optional_nested_enum=unittest_pb2.TestAllTypes.FOO,
@@ -2340,7 +2752,7 @@ class SerializationTest(unittest.TestCase):
self.assertEqual(1, proto.optional_int32)
self.assertEqual('foo', proto.optional_string)
self.assertEqual(True, proto.optional_bool)
- self.assertEqual('bar', proto.optional_bytes)
+ self.assertEqual(b'bar', proto.optional_bytes)
self.assertEqual(1, proto.optional_nested_message.bb)
self.assertEqual(1, proto.optional_foreign_message.c)
self.assertEqual(unittest_pb2.TestAllTypes.FOO,
@@ -2390,7 +2802,7 @@ class SerializationTest(unittest.TestCase):
self.assertEqual(3, proto.repeated_int32[2])
-class OptionsTest(unittest.TestCase):
+class OptionsTest(basetest.TestCase):
def testMessageOptions(self):
proto = unittest_mset_pb2.TestMessageSet()
@@ -2417,5 +2829,138 @@ class OptionsTest(unittest.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=[],
+ nested_types=[], enum_types=[],
+ extensions=[])
+ child_desc = descriptor.Descriptor('child', 'package.parent.child', '',
+ containing_type=None, fields=[],
+ nested_types=[leaf_desc], enum_types=[],
+ extensions=[])
+ sibling_desc = descriptor.Descriptor('sibling', 'package.parent.sibling',
+ '', containing_type=None, fields=[],
+ nested_types=[], enum_types=[],
+ extensions=[])
+ parent_desc = descriptor.Descriptor('parent', 'package.parent', '',
+ containing_type=None, fields=[],
+ nested_types=[child_desc, sibling_desc],
+ enum_types=[], extensions=[])
+ message_class = reflection.MakeClass(parent_desc)
+ self.assertIn('child', message_class.__dict__)
+ self.assertIn('sibling', message_class.__dict__)
+ self.assertIn('leaf', message_class.child.__dict__)
+
+ def _GetSerializedFileDescriptor(self, name):
+ """Get a serialized representation of a test FileDescriptorProto.
+
+ Args:
+ name: All calls to this must use a unique message name, to avoid
+ collisions in the cpp descriptor pool.
+ Returns:
+ A string containing the serialized form of a test FileDescriptorProto.
+ """
+ file_descriptor_str = (
+ 'message_type {'
+ ' name: "' + name + '"'
+ ' field {'
+ ' name: "flat"'
+ ' number: 1'
+ ' label: LABEL_REPEATED'
+ ' type: TYPE_UINT32'
+ ' }'
+ ' field {'
+ ' name: "bar"'
+ ' number: 2'
+ ' label: LABEL_OPTIONAL'
+ ' type: TYPE_MESSAGE'
+ ' type_name: "Bar"'
+ ' }'
+ ' nested_type {'
+ ' name: "Bar"'
+ ' field {'
+ ' name: "baz"'
+ ' number: 3'
+ ' label: LABEL_OPTIONAL'
+ ' type: TYPE_MESSAGE'
+ ' type_name: "Baz"'
+ ' }'
+ ' nested_type {'
+ ' name: "Baz"'
+ ' enum_type {'
+ ' name: "deep_enum"'
+ ' value {'
+ ' name: "VALUE_A"'
+ ' number: 0'
+ ' }'
+ ' }'
+ ' field {'
+ ' name: "deep"'
+ ' number: 4'
+ ' label: LABEL_OPTIONAL'
+ ' type: TYPE_UINT32'
+ ' }'
+ ' }'
+ ' }'
+ '}')
+ file_descriptor = descriptor_pb2.FileDescriptorProto()
+ text_format.Merge(file_descriptor_str, file_descriptor)
+ return file_descriptor.SerializeToString()
+
+ def testParsingFlatClassWithExplicitClassDeclaration(self):
+ """Test that the generated class can parse a flat message."""
+ file_descriptor = descriptor_pb2.FileDescriptorProto()
+ file_descriptor.ParseFromString(self._GetSerializedFileDescriptor('A'))
+ msg_descriptor = descriptor.MakeDescriptor(
+ file_descriptor.message_type[0])
+
+ class MessageClass(message.Message):
+ __metaclass__ = reflection.GeneratedProtocolMessageType
+ DESCRIPTOR = msg_descriptor
+ msg = MessageClass()
+ msg_str = (
+ 'flat: 0 '
+ 'flat: 1 '
+ 'flat: 2 ')
+ text_format.Merge(msg_str, msg)
+ self.assertEqual(msg.flat, [0, 1, 2])
+
+ def testParsingFlatClass(self):
+ """Test that the generated class can parse a flat message."""
+ file_descriptor = descriptor_pb2.FileDescriptorProto()
+ file_descriptor.ParseFromString(self._GetSerializedFileDescriptor('B'))
+ msg_descriptor = descriptor.MakeDescriptor(
+ file_descriptor.message_type[0])
+ msg_class = reflection.MakeClass(msg_descriptor)
+ msg = msg_class()
+ msg_str = (
+ 'flat: 0 '
+ 'flat: 1 '
+ 'flat: 2 ')
+ text_format.Merge(msg_str, msg)
+ self.assertEqual(msg.flat, [0, 1, 2])
+
+ def testParsingNestedClass(self):
+ """Test that the generated class can parse a nested message."""
+ file_descriptor = descriptor_pb2.FileDescriptorProto()
+ file_descriptor.ParseFromString(self._GetSerializedFileDescriptor('C'))
+ msg_descriptor = descriptor.MakeDescriptor(
+ file_descriptor.message_type[0])
+ msg_class = reflection.MakeClass(msg_descriptor)
+ msg = msg_class()
+ msg_str = (
+ 'bar {'
+ ' baz {'
+ ' deep: 4'
+ ' }'
+ '}')
+ text_format.Merge(msg_str, msg)
+ self.assertEqual(msg.bar.baz.deep, 4)
+
if __name__ == '__main__':
- unittest.main()
+ basetest.main()
diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py
index e04f8252..d066ae70 100755
--- a/python/google/protobuf/internal/service_reflection_test.py
+++ b/python/google/protobuf/internal/service_reflection_test.py
@@ -2,7 +2,7 @@
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -34,13 +34,13 @@
__author__ = 'petar@google.com (Petar Petrov)'
-import unittest
+from google.apputils import basetest
from google.protobuf import unittest_pb2
from google.protobuf import service_reflection
from google.protobuf import service
-class FooUnitTest(unittest.TestCase):
+class FooUnitTest(basetest.TestCase):
def testService(self):
class MockRpcChannel(service.RpcChannel):
@@ -118,7 +118,7 @@ class FooUnitTest(unittest.TestCase):
rpc_controller = 'controller'
request = 'request'
- # GetDescriptor now static, still works as instance method for compatability
+ # GetDescriptor now static, still works as instance method for compatibility
self.assertEqual(unittest_pb2.TestService_Stub.GetDescriptor(),
stub.GetDescriptor())
@@ -133,4 +133,4 @@ class FooUnitTest(unittest.TestCase):
if __name__ == '__main__':
- unittest.main()
+ basetest.main()
diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py
new file mode 100644
index 00000000..47572d58
--- /dev/null
+++ b/python/google/protobuf/internal/symbol_database_test.py
@@ -0,0 +1,120 @@
+#! /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.symbol_database."""
+
+from google.apputils import basetest
+from google.protobuf import unittest_pb2
+from google.protobuf import symbol_database
+
+
+class SymbolDatabaseTest(basetest.TestCase):
+
+ def _Database(self):
+ db = symbol_database.SymbolDatabase()
+ # Register representative types from unittest_pb2.
+ db.RegisterFileDescriptor(unittest_pb2.DESCRIPTOR)
+ db.RegisterMessage(unittest_pb2.TestAllTypes)
+ db.RegisterMessage(unittest_pb2.TestAllTypes.NestedMessage)
+ db.RegisterMessage(unittest_pb2.TestAllTypes.OptionalGroup)
+ db.RegisterMessage(unittest_pb2.TestAllTypes.RepeatedGroup)
+ db.RegisterEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
+ db.RegisterEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
+ return db
+
+ def testGetPrototype(self):
+ instance = self._Database().GetPrototype(
+ unittest_pb2.TestAllTypes.DESCRIPTOR)
+ self.assertTrue(instance is unittest_pb2.TestAllTypes)
+
+ def testGetMessages(self):
+ messages = self._Database().GetMessages(
+ ['google/protobuf/unittest.proto'])
+ self.assertTrue(
+ unittest_pb2.TestAllTypes is
+ messages['protobuf_unittest.TestAllTypes'])
+
+ def testGetSymbol(self):
+ self.assertEquals(
+ unittest_pb2.TestAllTypes, self._Database().GetSymbol(
+ 'protobuf_unittest.TestAllTypes'))
+ self.assertEquals(
+ unittest_pb2.TestAllTypes.NestedMessage, self._Database().GetSymbol(
+ 'protobuf_unittest.TestAllTypes.NestedMessage'))
+ self.assertEquals(
+ unittest_pb2.TestAllTypes.OptionalGroup, self._Database().GetSymbol(
+ 'protobuf_unittest.TestAllTypes.OptionalGroup'))
+ self.assertEquals(
+ unittest_pb2.TestAllTypes.RepeatedGroup, self._Database().GetSymbol(
+ 'protobuf_unittest.TestAllTypes.RepeatedGroup'))
+
+ def testEnums(self):
+ # Check registration of types in the pool.
+ self.assertEquals(
+ 'protobuf_unittest.ForeignEnum',
+ self._Database().pool.FindEnumTypeByName(
+ 'protobuf_unittest.ForeignEnum').full_name)
+ self.assertEquals(
+ 'protobuf_unittest.TestAllTypes.NestedEnum',
+ self._Database().pool.FindEnumTypeByName(
+ 'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
+
+ def testFindMessageTypeByName(self):
+ self.assertEquals(
+ 'protobuf_unittest.TestAllTypes',
+ self._Database().pool.FindMessageTypeByName(
+ 'protobuf_unittest.TestAllTypes').full_name)
+ self.assertEquals(
+ 'protobuf_unittest.TestAllTypes.NestedMessage',
+ self._Database().pool.FindMessageTypeByName(
+ 'protobuf_unittest.TestAllTypes.NestedMessage').full_name)
+
+ def testFindFindContainingSymbol(self):
+ # Lookup based on either enum or message.
+ self.assertEquals(
+ 'google/protobuf/unittest.proto',
+ self._Database().pool.FindFileContainingSymbol(
+ 'protobuf_unittest.TestAllTypes.NestedEnum').name)
+ self.assertEquals(
+ 'google/protobuf/unittest.proto',
+ self._Database().pool.FindFileContainingSymbol(
+ 'protobuf_unittest.TestAllTypes').name)
+
+ def testFindFileByName(self):
+ self.assertEquals(
+ 'google/protobuf/unittest.proto',
+ self._Database().pool.FindFileByName(
+ 'google/protobuf/unittest.proto').name)
+
+
+if __name__ == '__main__':
+ basetest.main()
diff --git a/python/google/protobuf/internal/test_bad_identifiers.proto b/python/google/protobuf/internal/test_bad_identifiers.proto
new file mode 100644
index 00000000..c4860ea8
--- /dev/null
+++ b/python/google/protobuf/internal/test_bad_identifiers.proto
@@ -0,0 +1,53 @@
+// 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)
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+option py_generic_services = true;
+
+message TestBadIdentifiers {
+ extensions 100 to max;
+}
+
+// Make sure these reasonable extension names don't conflict with internal
+// variables.
+extend TestBadIdentifiers {
+ optional string message = 100 [default="foo"];
+ optional string descriptor = 101 [default="bar"];
+ optional string reflection = 102 [default="baz"];
+ optional string service = 103 [default="qux"];
+}
+
+message AnotherMessage {}
+service AnotherService {}
diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py
index 1df16194..d84e3836 100755
--- a/python/google/protobuf/internal/test_util.py
+++ b/python/google/protobuf/internal/test_util.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -40,13 +40,19 @@ import os.path
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_pb2
+from google.protobuf import descriptor_pb2
+# Tests whether the given TestAllTypes message is proto2 or not.
+# This is used to gate several fields/features that only exist
+# for the proto2 version of the message.
+def IsProto2(message):
+ return message.DESCRIPTOR.syntax == "proto2"
-def SetAllFields(message):
- """Sets every field in the message to a unique value.
+def SetAllNonLazyFields(message):
+ """Sets every non-lazy field in the message to a unique value.
Args:
- message: A unittest_pb2.TestAllTypes instance.
+ message: A TestAllTypes instance.
"""
#
@@ -66,26 +72,22 @@ def SetAllFields(message):
message.optional_float = 111
message.optional_double = 112
message.optional_bool = True
- # TODO(robinson): Firmly spec out and test how
- # protos interact with unicode. One specific example:
- # what happens if we change the literal below to
- # u'115'? What *should* happen? Still some discussion
- # to finish with Kenton about bytes vs. strings
- # and forcing everything to be utf8. :-/
- message.optional_string = '115'
- message.optional_bytes = '116'
+ message.optional_string = u'115'
+ message.optional_bytes = b'116'
message.optionalgroup.a = 117
message.optional_nested_message.bb = 118
message.optional_foreign_message.c = 119
message.optional_import_message.d = 120
+ message.optional_public_import_message.e = 126
message.optional_nested_enum = unittest_pb2.TestAllTypes.BAZ
message.optional_foreign_enum = unittest_pb2.FOREIGN_BAZ
- message.optional_import_enum = unittest_import_pb2.IMPORT_BAZ
+ if IsProto2(message):
+ message.optional_import_enum = unittest_import_pb2.IMPORT_BAZ
- message.optional_string_piece = '124'
- message.optional_cord = '125'
+ message.optional_string_piece = u'124'
+ message.optional_cord = u'125'
#
# Repeated fields.
@@ -104,20 +106,22 @@ def SetAllFields(message):
message.repeated_float.append(211)
message.repeated_double.append(212)
message.repeated_bool.append(True)
- message.repeated_string.append('215')
- message.repeated_bytes.append('216')
+ message.repeated_string.append(u'215')
+ message.repeated_bytes.append(b'216')
message.repeatedgroup.add().a = 217
message.repeated_nested_message.add().bb = 218
message.repeated_foreign_message.add().c = 219
message.repeated_import_message.add().d = 220
+ message.repeated_lazy_message.add().bb = 227
message.repeated_nested_enum.append(unittest_pb2.TestAllTypes.BAR)
message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAR)
- message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAR)
+ if IsProto2(message):
+ message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAR)
- message.repeated_string_piece.append('224')
- message.repeated_cord.append('225')
+ message.repeated_string_piece.append(u'224')
+ message.repeated_cord.append(u'225')
# Add a second one of each field.
message.repeated_int32.append(301)
@@ -133,47 +137,60 @@ def SetAllFields(message):
message.repeated_float.append(311)
message.repeated_double.append(312)
message.repeated_bool.append(False)
- message.repeated_string.append('315')
- message.repeated_bytes.append('316')
+ message.repeated_string.append(u'315')
+ message.repeated_bytes.append(b'316')
message.repeatedgroup.add().a = 317
message.repeated_nested_message.add().bb = 318
message.repeated_foreign_message.add().c = 319
message.repeated_import_message.add().d = 320
+ message.repeated_lazy_message.add().bb = 327
message.repeated_nested_enum.append(unittest_pb2.TestAllTypes.BAZ)
message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAZ)
- message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAZ)
+ if IsProto2(message):
+ message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAZ)
- message.repeated_string_piece.append('324')
- message.repeated_cord.append('325')
+ message.repeated_string_piece.append(u'324')
+ message.repeated_cord.append(u'325')
#
# Fields that have defaults.
#
- message.default_int32 = 401
- message.default_int64 = 402
- message.default_uint32 = 403
- message.default_uint64 = 404
- message.default_sint32 = 405
- message.default_sint64 = 406
- message.default_fixed32 = 407
- message.default_fixed64 = 408
- message.default_sfixed32 = 409
- message.default_sfixed64 = 410
- message.default_float = 411
- message.default_double = 412
- message.default_bool = False
- message.default_string = '415'
- message.default_bytes = '416'
-
- message.default_nested_enum = unittest_pb2.TestAllTypes.FOO
- message.default_foreign_enum = unittest_pb2.FOREIGN_FOO
- message.default_import_enum = unittest_import_pb2.IMPORT_FOO
-
- message.default_string_piece = '424'
- message.default_cord = '425'
+ if IsProto2(message):
+ message.default_int32 = 401
+ message.default_int64 = 402
+ message.default_uint32 = 403
+ message.default_uint64 = 404
+ message.default_sint32 = 405
+ message.default_sint64 = 406
+ message.default_fixed32 = 407
+ message.default_fixed64 = 408
+ message.default_sfixed32 = 409
+ message.default_sfixed64 = 410
+ message.default_float = 411
+ message.default_double = 412
+ message.default_bool = False
+ message.default_string = '415'
+ message.default_bytes = b'416'
+
+ message.default_nested_enum = unittest_pb2.TestAllTypes.FOO
+ message.default_foreign_enum = unittest_pb2.FOREIGN_FOO
+ message.default_import_enum = unittest_import_pb2.IMPORT_FOO
+
+ message.default_string_piece = '424'
+ message.default_cord = '425'
+
+ message.oneof_uint32 = 601
+ message.oneof_nested_message.bb = 602
+ message.oneof_string = '603'
+ message.oneof_bytes = b'604'
+
+
+def SetAllFields(message):
+ SetAllNonLazyFields(message)
+ message.optional_lazy_message.bb = 127
def SetAllExtensions(message):
@@ -204,21 +221,23 @@ def SetAllExtensions(message):
extensions[pb2.optional_float_extension] = 111
extensions[pb2.optional_double_extension] = 112
extensions[pb2.optional_bool_extension] = True
- extensions[pb2.optional_string_extension] = '115'
- extensions[pb2.optional_bytes_extension] = '116'
+ extensions[pb2.optional_string_extension] = u'115'
+ extensions[pb2.optional_bytes_extension] = b'116'
extensions[pb2.optionalgroup_extension].a = 117
extensions[pb2.optional_nested_message_extension].bb = 118
extensions[pb2.optional_foreign_message_extension].c = 119
extensions[pb2.optional_import_message_extension].d = 120
+ extensions[pb2.optional_public_import_message_extension].e = 126
+ extensions[pb2.optional_lazy_message_extension].bb = 127
extensions[pb2.optional_nested_enum_extension] = pb2.TestAllTypes.BAZ
extensions[pb2.optional_nested_enum_extension] = pb2.TestAllTypes.BAZ
extensions[pb2.optional_foreign_enum_extension] = pb2.FOREIGN_BAZ
extensions[pb2.optional_import_enum_extension] = import_pb2.IMPORT_BAZ
- extensions[pb2.optional_string_piece_extension] = '124'
- extensions[pb2.optional_cord_extension] = '125'
+ extensions[pb2.optional_string_piece_extension] = u'124'
+ extensions[pb2.optional_cord_extension] = u'125'
#
# Repeated fields.
@@ -237,20 +256,21 @@ def SetAllExtensions(message):
extensions[pb2.repeated_float_extension].append(211)
extensions[pb2.repeated_double_extension].append(212)
extensions[pb2.repeated_bool_extension].append(True)
- extensions[pb2.repeated_string_extension].append('215')
- extensions[pb2.repeated_bytes_extension].append('216')
+ extensions[pb2.repeated_string_extension].append(u'215')
+ extensions[pb2.repeated_bytes_extension].append(b'216')
extensions[pb2.repeatedgroup_extension].add().a = 217
extensions[pb2.repeated_nested_message_extension].add().bb = 218
extensions[pb2.repeated_foreign_message_extension].add().c = 219
extensions[pb2.repeated_import_message_extension].add().d = 220
+ extensions[pb2.repeated_lazy_message_extension].add().bb = 227
extensions[pb2.repeated_nested_enum_extension].append(pb2.TestAllTypes.BAR)
extensions[pb2.repeated_foreign_enum_extension].append(pb2.FOREIGN_BAR)
extensions[pb2.repeated_import_enum_extension].append(import_pb2.IMPORT_BAR)
- extensions[pb2.repeated_string_piece_extension].append('224')
- extensions[pb2.repeated_cord_extension].append('225')
+ extensions[pb2.repeated_string_piece_extension].append(u'224')
+ extensions[pb2.repeated_cord_extension].append(u'225')
# Append a second one of each field.
extensions[pb2.repeated_int32_extension].append(301)
@@ -266,20 +286,21 @@ def SetAllExtensions(message):
extensions[pb2.repeated_float_extension].append(311)
extensions[pb2.repeated_double_extension].append(312)
extensions[pb2.repeated_bool_extension].append(False)
- extensions[pb2.repeated_string_extension].append('315')
- extensions[pb2.repeated_bytes_extension].append('316')
+ extensions[pb2.repeated_string_extension].append(u'315')
+ extensions[pb2.repeated_bytes_extension].append(b'316')
extensions[pb2.repeatedgroup_extension].add().a = 317
extensions[pb2.repeated_nested_message_extension].add().bb = 318
extensions[pb2.repeated_foreign_message_extension].add().c = 319
extensions[pb2.repeated_import_message_extension].add().d = 320
+ extensions[pb2.repeated_lazy_message_extension].add().bb = 327
extensions[pb2.repeated_nested_enum_extension].append(pb2.TestAllTypes.BAZ)
extensions[pb2.repeated_foreign_enum_extension].append(pb2.FOREIGN_BAZ)
extensions[pb2.repeated_import_enum_extension].append(import_pb2.IMPORT_BAZ)
- extensions[pb2.repeated_string_piece_extension].append('324')
- extensions[pb2.repeated_cord_extension].append('325')
+ extensions[pb2.repeated_string_piece_extension].append(u'324')
+ extensions[pb2.repeated_cord_extension].append(u'325')
#
# Fields with defaults.
@@ -298,16 +319,21 @@ def SetAllExtensions(message):
extensions[pb2.default_float_extension] = 411
extensions[pb2.default_double_extension] = 412
extensions[pb2.default_bool_extension] = False
- extensions[pb2.default_string_extension] = '415'
- extensions[pb2.default_bytes_extension] = '416'
+ extensions[pb2.default_string_extension] = u'415'
+ extensions[pb2.default_bytes_extension] = b'416'
extensions[pb2.default_nested_enum_extension] = pb2.TestAllTypes.FOO
extensions[pb2.default_foreign_enum_extension] = pb2.FOREIGN_FOO
extensions[pb2.default_import_enum_extension] = import_pb2.IMPORT_FOO
- extensions[pb2.default_string_piece_extension] = '424'
+ extensions[pb2.default_string_piece_extension] = u'424'
extensions[pb2.default_cord_extension] = '425'
+ extensions[pb2.oneof_uint32_extension] = 601
+ extensions[pb2.oneof_nested_message_extension].bb = 602
+ extensions[pb2.oneof_string_extension] = u'603'
+ extensions[pb2.oneof_bytes_extension] = b'604'
+
def SetAllFieldsAndExtensions(message):
"""Sets every field and extension in the message to a unique value.
@@ -346,7 +372,7 @@ def ExpectAllFieldsAndExtensionsInOrder(serialized):
message.my_float = 1.0
expected_strings.append(message.SerializeToString())
message.Clear()
- expected = ''.join(expected_strings)
+ expected = b''.join(expected_strings)
if expected != serialized:
raise ValueError('Expected %r, found %r' % (expected, serialized))
@@ -382,7 +408,8 @@ def ExpectAllFieldsSet(test_case, message):
test_case.assertTrue(message.HasField('optional_nested_enum'))
test_case.assertTrue(message.HasField('optional_foreign_enum'))
- test_case.assertTrue(message.HasField('optional_import_enum'))
+ if IsProto2(message):
+ test_case.assertTrue(message.HasField('optional_import_enum'))
test_case.assertTrue(message.HasField('optional_string_piece'))
test_case.assertTrue(message.HasField('optional_cord'))
@@ -401,19 +428,22 @@ def ExpectAllFieldsSet(test_case, message):
test_case.assertEqual(112, message.optional_double)
test_case.assertEqual(True, message.optional_bool)
test_case.assertEqual('115', message.optional_string)
- test_case.assertEqual('116', message.optional_bytes)
+ test_case.assertEqual(b'116', message.optional_bytes)
test_case.assertEqual(117, message.optionalgroup.a)
test_case.assertEqual(118, message.optional_nested_message.bb)
test_case.assertEqual(119, message.optional_foreign_message.c)
test_case.assertEqual(120, message.optional_import_message.d)
+ test_case.assertEqual(126, message.optional_public_import_message.e)
+ test_case.assertEqual(127, message.optional_lazy_message.bb)
test_case.assertEqual(unittest_pb2.TestAllTypes.BAZ,
message.optional_nested_enum)
test_case.assertEqual(unittest_pb2.FOREIGN_BAZ,
message.optional_foreign_enum)
- test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
- message.optional_import_enum)
+ if IsProto2(message):
+ test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
+ message.optional_import_enum)
# -----------------------------------------------------------------
@@ -439,7 +469,8 @@ def ExpectAllFieldsSet(test_case, message):
test_case.assertEqual(2, len(message.repeated_import_message))
test_case.assertEqual(2, len(message.repeated_nested_enum))
test_case.assertEqual(2, len(message.repeated_foreign_enum))
- test_case.assertEqual(2, len(message.repeated_import_enum))
+ if IsProto2(message):
+ test_case.assertEqual(2, len(message.repeated_import_enum))
test_case.assertEqual(2, len(message.repeated_string_piece))
test_case.assertEqual(2, len(message.repeated_cord))
@@ -458,19 +489,21 @@ def ExpectAllFieldsSet(test_case, message):
test_case.assertEqual(212, message.repeated_double[0])
test_case.assertEqual(True, message.repeated_bool[0])
test_case.assertEqual('215', message.repeated_string[0])
- test_case.assertEqual('216', message.repeated_bytes[0])
+ test_case.assertEqual(b'216', message.repeated_bytes[0])
test_case.assertEqual(217, message.repeatedgroup[0].a)
test_case.assertEqual(218, message.repeated_nested_message[0].bb)
test_case.assertEqual(219, message.repeated_foreign_message[0].c)
test_case.assertEqual(220, message.repeated_import_message[0].d)
+ test_case.assertEqual(227, message.repeated_lazy_message[0].bb)
test_case.assertEqual(unittest_pb2.TestAllTypes.BAR,
message.repeated_nested_enum[0])
test_case.assertEqual(unittest_pb2.FOREIGN_BAR,
message.repeated_foreign_enum[0])
- test_case.assertEqual(unittest_import_pb2.IMPORT_BAR,
- message.repeated_import_enum[0])
+ if IsProto2(message):
+ test_case.assertEqual(unittest_import_pb2.IMPORT_BAR,
+ message.repeated_import_enum[0])
test_case.assertEqual(301, message.repeated_int32[1])
test_case.assertEqual(302, message.repeated_int64[1])
@@ -486,64 +519,68 @@ def ExpectAllFieldsSet(test_case, message):
test_case.assertEqual(312, message.repeated_double[1])
test_case.assertEqual(False, message.repeated_bool[1])
test_case.assertEqual('315', message.repeated_string[1])
- test_case.assertEqual('316', message.repeated_bytes[1])
+ test_case.assertEqual(b'316', message.repeated_bytes[1])
test_case.assertEqual(317, message.repeatedgroup[1].a)
test_case.assertEqual(318, message.repeated_nested_message[1].bb)
test_case.assertEqual(319, message.repeated_foreign_message[1].c)
test_case.assertEqual(320, message.repeated_import_message[1].d)
+ test_case.assertEqual(327, message.repeated_lazy_message[1].bb)
test_case.assertEqual(unittest_pb2.TestAllTypes.BAZ,
message.repeated_nested_enum[1])
test_case.assertEqual(unittest_pb2.FOREIGN_BAZ,
message.repeated_foreign_enum[1])
- test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
- message.repeated_import_enum[1])
+ if IsProto2(message):
+ test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
+ message.repeated_import_enum[1])
# -----------------------------------------------------------------
- test_case.assertTrue(message.HasField('default_int32'))
- test_case.assertTrue(message.HasField('default_int64'))
- test_case.assertTrue(message.HasField('default_uint32'))
- test_case.assertTrue(message.HasField('default_uint64'))
- test_case.assertTrue(message.HasField('default_sint32'))
- test_case.assertTrue(message.HasField('default_sint64'))
- test_case.assertTrue(message.HasField('default_fixed32'))
- test_case.assertTrue(message.HasField('default_fixed64'))
- test_case.assertTrue(message.HasField('default_sfixed32'))
- test_case.assertTrue(message.HasField('default_sfixed64'))
- test_case.assertTrue(message.HasField('default_float'))
- test_case.assertTrue(message.HasField('default_double'))
- test_case.assertTrue(message.HasField('default_bool'))
- test_case.assertTrue(message.HasField('default_string'))
- test_case.assertTrue(message.HasField('default_bytes'))
-
- test_case.assertTrue(message.HasField('default_nested_enum'))
- test_case.assertTrue(message.HasField('default_foreign_enum'))
- test_case.assertTrue(message.HasField('default_import_enum'))
-
- test_case.assertEqual(401, message.default_int32)
- test_case.assertEqual(402, message.default_int64)
- test_case.assertEqual(403, message.default_uint32)
- test_case.assertEqual(404, message.default_uint64)
- test_case.assertEqual(405, message.default_sint32)
- test_case.assertEqual(406, message.default_sint64)
- test_case.assertEqual(407, message.default_fixed32)
- test_case.assertEqual(408, message.default_fixed64)
- test_case.assertEqual(409, message.default_sfixed32)
- test_case.assertEqual(410, message.default_sfixed64)
- test_case.assertEqual(411, message.default_float)
- test_case.assertEqual(412, message.default_double)
- test_case.assertEqual(False, message.default_bool)
- test_case.assertEqual('415', message.default_string)
- test_case.assertEqual('416', message.default_bytes)
-
- test_case.assertEqual(unittest_pb2.TestAllTypes.FOO,
- message.default_nested_enum)
- test_case.assertEqual(unittest_pb2.FOREIGN_FOO,
- message.default_foreign_enum)
- test_case.assertEqual(unittest_import_pb2.IMPORT_FOO,
- message.default_import_enum)
+ if IsProto2(message):
+ test_case.assertTrue(message.HasField('default_int32'))
+ test_case.assertTrue(message.HasField('default_int64'))
+ test_case.assertTrue(message.HasField('default_uint32'))
+ test_case.assertTrue(message.HasField('default_uint64'))
+ test_case.assertTrue(message.HasField('default_sint32'))
+ test_case.assertTrue(message.HasField('default_sint64'))
+ test_case.assertTrue(message.HasField('default_fixed32'))
+ test_case.assertTrue(message.HasField('default_fixed64'))
+ test_case.assertTrue(message.HasField('default_sfixed32'))
+ test_case.assertTrue(message.HasField('default_sfixed64'))
+ test_case.assertTrue(message.HasField('default_float'))
+ test_case.assertTrue(message.HasField('default_double'))
+ test_case.assertTrue(message.HasField('default_bool'))
+ test_case.assertTrue(message.HasField('default_string'))
+ test_case.assertTrue(message.HasField('default_bytes'))
+
+ test_case.assertTrue(message.HasField('default_nested_enum'))
+ test_case.assertTrue(message.HasField('default_foreign_enum'))
+ test_case.assertTrue(message.HasField('default_import_enum'))
+
+ test_case.assertEqual(401, message.default_int32)
+ test_case.assertEqual(402, message.default_int64)
+ test_case.assertEqual(403, message.default_uint32)
+ test_case.assertEqual(404, message.default_uint64)
+ test_case.assertEqual(405, message.default_sint32)
+ test_case.assertEqual(406, message.default_sint64)
+ test_case.assertEqual(407, message.default_fixed32)
+ test_case.assertEqual(408, message.default_fixed64)
+ test_case.assertEqual(409, message.default_sfixed32)
+ test_case.assertEqual(410, message.default_sfixed64)
+ test_case.assertEqual(411, message.default_float)
+ test_case.assertEqual(412, message.default_double)
+ test_case.assertEqual(False, message.default_bool)
+ test_case.assertEqual('415', message.default_string)
+ test_case.assertEqual(b'416', message.default_bytes)
+
+ test_case.assertEqual(unittest_pb2.TestAllTypes.FOO,
+ message.default_nested_enum)
+ test_case.assertEqual(unittest_pb2.FOREIGN_FOO,
+ message.default_foreign_enum)
+ test_case.assertEqual(unittest_import_pb2.IMPORT_FOO,
+ message.default_import_enum)
+
def GoldenFile(filename):
"""Finds the given golden file and returns a file object representing it."""
@@ -558,16 +595,22 @@ def GoldenFile(filename):
path = os.path.join(path, '..')
raise RuntimeError(
- 'Could not find golden files. This test must be run from within the '
- 'protobuf source package so that it can read test data files from the '
- 'C++ source tree.')
+ 'Could not find golden files. This test must be run from within the '
+ 'protobuf source package so that it can read test data files from the '
+ 'C++ source tree.')
+
+
+def GoldenFileData(filename):
+ """Finds the given golden file and returns its contents."""
+ with GoldenFile(filename) as f:
+ return f.read()
def SetAllPackedFields(message):
"""Sets every field in the message to a unique value.
Args:
- message: A unittest_pb2.TestPackedTypes instance.
+ message: A TestPackedTypes instance.
"""
message.packed_int32.extend([601, 701])
message.packed_int64.extend([602, 702])
diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py
new file mode 100755
index 00000000..db0222bd
--- /dev/null
+++ b/python/google/protobuf/internal/text_encoding_test.py
@@ -0,0 +1,68 @@
+#! /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.text_encoding."""
+
+from google.apputils import basetest
+from google.protobuf import text_encoding
+
+TEST_VALUES = [
+ ("foo\\rbar\\nbaz\\t",
+ "foo\\rbar\\nbaz\\t",
+ b"foo\rbar\nbaz\t"),
+ ("\\'full of \\\"sound\\\" and \\\"fury\\\"\\'",
+ "\\'full of \\\"sound\\\" and \\\"fury\\\"\\'",
+ b"'full of \"sound\" and \"fury\"'"),
+ ("signi\\\\fying\\\\ nothing\\\\",
+ "signi\\\\fying\\\\ nothing\\\\",
+ b"signi\\fying\\ nothing\\"),
+ ("\\010\\t\\n\\013\\014\\r",
+ "\x08\\t\\n\x0b\x0c\\r",
+ b"\010\011\012\013\014\015")]
+
+
+class TextEncodingTestCase(basetest.TestCase):
+ def testCEscape(self):
+ for escaped, escaped_utf8, unescaped in TEST_VALUES:
+ self.assertEquals(escaped,
+ text_encoding.CEscape(unescaped, as_utf8=False))
+ self.assertEquals(escaped_utf8,
+ text_encoding.CEscape(unescaped, as_utf8=True))
+
+ def testCUnescape(self):
+ for escaped, escaped_utf8, unescaped in TEST_VALUES:
+ self.assertEquals(unescaped, text_encoding.CUnescape(escaped))
+ self.assertEquals(unescaped, text_encoding.CUnescape(escaped_utf8))
+
+
+if __name__ == "__main__":
+ basetest.main()
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index 73d97d18..7d5813fb 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -2,7 +2,7 @@
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -34,68 +34,51 @@
__author__ = 'kenton@google.com (Kenton Varda)'
-import difflib
import re
-import unittest
-from google.protobuf import text_format
-from google.protobuf.internal import test_util
-from google.protobuf import unittest_pb2
+from google.apputils import basetest
+from google.protobuf.internal import _parameterized
+
from google.protobuf import unittest_mset_pb2
+from google.protobuf import unittest_pb2
+from google.protobuf import unittest_proto3_arena_pb2
+from google.protobuf.internal import api_implementation
+from google.protobuf.internal import test_util
+from google.protobuf import text_format
+# Base class with some common functionality.
+class TextFormatBase(basetest.TestCase):
-class TextFormatTest(unittest.TestCase):
def ReadGolden(self, golden_filename):
- f = test_util.GoldenFile(golden_filename)
- golden_lines = f.readlines()
- f.close()
- return golden_lines
+ with test_util.GoldenFile(golden_filename) as f:
+ return (f.readlines() if str is bytes else # PY3
+ [golden_line.decode('utf-8') for golden_line in f])
def CompareToGoldenFile(self, text, golden_filename):
golden_lines = self.ReadGolden(golden_filename)
- self.CompareToGoldenLines(text, golden_lines)
+ self.assertMultiLineEqual(text, ''.join(golden_lines))
def CompareToGoldenText(self, text, golden_text):
- self.CompareToGoldenLines(text, golden_text.splitlines(1))
+ self.assertMultiLineEqual(text, golden_text)
- def CompareToGoldenLines(self, text, golden_lines):
- actual_lines = text.splitlines(1)
- self.assertEqual(golden_lines, actual_lines,
- "Text doesn't match golden. Diff:\n" +
- ''.join(difflib.ndiff(golden_lines, actual_lines)))
+ def RemoveRedundantZeros(self, text):
+ # Some platforms print 1e+5 as 1e+005. This is fine, but we need to remove
+ # these zeros in order to match the golden file.
+ text = text.replace('e+0','e+').replace('e+0','e+') \
+ .replace('e-0','e-').replace('e-0','e-')
+ # Floating point fields are printed with .0 suffix even if they are
+ # actualy integer numbers.
+ text = re.compile('\.0$', re.MULTILINE).sub('', text)
+ return text
- def testPrintAllFields(self):
- message = unittest_pb2.TestAllTypes()
- test_util.SetAllFields(message)
- self.CompareToGoldenFile(
- self.RemoveRedundantZeros(text_format.MessageToString(message)),
- 'text_format_unittest_data.txt')
- def testPrintAllExtensions(self):
- message = unittest_pb2.TestAllExtensions()
- test_util.SetAllExtensions(message)
- self.CompareToGoldenFile(
- self.RemoveRedundantZeros(text_format.MessageToString(message)),
- 'text_format_unittest_extensions_data.txt')
+@_parameterized.Parameters(
+ (unittest_pb2),
+ (unittest_proto3_arena_pb2))
+class TextFormatTest(TextFormatBase):
- def testPrintMessageSet(self):
- message = unittest_mset_pb2.TestMessageSetContainer()
- ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
- ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
- message.message_set.Extensions[ext1].i = 23
- message.message_set.Extensions[ext2].str = 'foo'
- self.CompareToGoldenText(text_format.MessageToString(message),
- 'message_set {\n'
- ' [protobuf_unittest.TestMessageSetExtension1] {\n'
- ' i: 23\n'
- ' }\n'
- ' [protobuf_unittest.TestMessageSetExtension2] {\n'
- ' str: \"foo\"\n'
- ' }\n'
- '}\n')
-
- def testPrintExotic(self):
- message = unittest_pb2.TestAllTypes()
+ def testPrintExotic(self, message_module):
+ message = message_module.TestAllTypes()
message.repeated_int64.append(-9223372036854775808)
message.repeated_uint64.append(18446744073709551615)
message.repeated_double.append(123.456)
@@ -104,62 +87,54 @@ class TextFormatTest(unittest.TestCase):
message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
message.repeated_string.append(u'\u00fc\ua71f')
self.CompareToGoldenText(
- self.RemoveRedundantZeros(text_format.MessageToString(message)),
- 'repeated_int64: -9223372036854775808\n'
- 'repeated_uint64: 18446744073709551615\n'
- 'repeated_double: 123.456\n'
- 'repeated_double: 1.23e+22\n'
- 'repeated_double: 1.23e-18\n'
- 'repeated_string: '
- '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n'
- 'repeated_string: "\\303\\274\\352\\234\\237"\n')
-
- def testPrintNestedMessageAsOneLine(self):
- message = unittest_pb2.TestAllTypes()
+ self.RemoveRedundantZeros(text_format.MessageToString(message)),
+ 'repeated_int64: -9223372036854775808\n'
+ 'repeated_uint64: 18446744073709551615\n'
+ 'repeated_double: 123.456\n'
+ 'repeated_double: 1.23e+22\n'
+ 'repeated_double: 1.23e-18\n'
+ 'repeated_string:'
+ ' "\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n'
+ 'repeated_string: "\\303\\274\\352\\234\\237"\n')
+
+ def testPrintExoticUnicodeSubclass(self, message_module):
+ class UnicodeSub(unicode):
+ pass
+ message = message_module.TestAllTypes()
+ message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f'))
+ self.CompareToGoldenText(
+ text_format.MessageToString(message),
+ 'repeated_string: "\\303\\274\\352\\234\\237"\n')
+
+ def testPrintNestedMessageAsOneLine(self, message_module):
+ message = message_module.TestAllTypes()
msg = message.repeated_nested_message.add()
- msg.bb = 42;
+ msg.bb = 42
self.CompareToGoldenText(
text_format.MessageToString(message, as_one_line=True),
'repeated_nested_message { bb: 42 }')
- def testPrintRepeatedFieldsAsOneLine(self):
- message = unittest_pb2.TestAllTypes()
+ def testPrintRepeatedFieldsAsOneLine(self, message_module):
+ message = message_module.TestAllTypes()
message.repeated_int32.append(1)
message.repeated_int32.append(1)
message.repeated_int32.append(3)
- message.repeated_string.append("Google")
- message.repeated_string.append("Zurich")
+ message.repeated_string.append('Google')
+ message.repeated_string.append('Zurich')
self.CompareToGoldenText(
text_format.MessageToString(message, as_one_line=True),
'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 '
'repeated_string: "Google" repeated_string: "Zurich"')
- def testPrintNestedNewLineInStringAsOneLine(self):
- message = unittest_pb2.TestAllTypes()
- message.optional_string = "a\nnew\nline"
+ def testPrintNestedNewLineInStringAsOneLine(self, message_module):
+ message = message_module.TestAllTypes()
+ message.optional_string = 'a\nnew\nline'
self.CompareToGoldenText(
text_format.MessageToString(message, as_one_line=True),
'optional_string: "a\\nnew\\nline"')
- def testPrintMessageSetAsOneLine(self):
- message = unittest_mset_pb2.TestMessageSetContainer()
- ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
- ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
- message.message_set.Extensions[ext1].i = 23
- message.message_set.Extensions[ext2].str = 'foo'
- self.CompareToGoldenText(
- text_format.MessageToString(message, as_one_line=True),
- 'message_set {'
- ' [protobuf_unittest.TestMessageSetExtension1] {'
- ' i: 23'
- ' }'
- ' [protobuf_unittest.TestMessageSetExtension2] {'
- ' str: \"foo\"'
- ' }'
- ' }')
-
- def testPrintExoticAsOneLine(self):
- message = unittest_pb2.TestAllTypes()
+ def testPrintExoticAsOneLine(self, message_module):
+ message = message_module.TestAllTypes()
message.repeated_int64.append(-9223372036854775808)
message.repeated_uint64.append(18446744073709551615)
message.repeated_double.append(123.456)
@@ -168,19 +143,19 @@ class TextFormatTest(unittest.TestCase):
message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
message.repeated_string.append(u'\u00fc\ua71f')
self.CompareToGoldenText(
- self.RemoveRedundantZeros(
- text_format.MessageToString(message, as_one_line=True)),
- 'repeated_int64: -9223372036854775808'
- ' repeated_uint64: 18446744073709551615'
- ' repeated_double: 123.456'
- ' repeated_double: 1.23e+22'
- ' repeated_double: 1.23e-18'
- ' repeated_string: '
- '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""'
- ' repeated_string: "\\303\\274\\352\\234\\237"')
-
- def testRoundTripExoticAsOneLine(self):
- message = unittest_pb2.TestAllTypes()
+ self.RemoveRedundantZeros(
+ text_format.MessageToString(message, as_one_line=True)),
+ 'repeated_int64: -9223372036854775808'
+ ' repeated_uint64: 18446744073709551615'
+ ' repeated_double: 123.456'
+ ' repeated_double: 1.23e+22'
+ ' repeated_double: 1.23e-18'
+ ' repeated_string: '
+ '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""'
+ ' repeated_string: "\\303\\274\\352\\234\\237"')
+
+ def testRoundTripExoticAsOneLine(self, message_module):
+ message = message_module.TestAllTypes()
message.repeated_int64.append(-9223372036854775808)
message.repeated_uint64.append(18446744073709551615)
message.repeated_double.append(123.456)
@@ -192,84 +167,353 @@ class TextFormatTest(unittest.TestCase):
# Test as_utf8 = False.
wire_text = text_format.MessageToString(
message, as_one_line=True, as_utf8=False)
- parsed_message = unittest_pb2.TestAllTypes()
- text_format.Merge(wire_text, parsed_message)
+ parsed_message = message_module.TestAllTypes()
+ r = text_format.Parse(wire_text, parsed_message)
+ self.assertIs(r, parsed_message)
self.assertEquals(message, parsed_message)
# Test as_utf8 = True.
wire_text = text_format.MessageToString(
message, as_one_line=True, as_utf8=True)
- parsed_message = unittest_pb2.TestAllTypes()
- text_format.Merge(wire_text, parsed_message)
- self.assertEquals(message, parsed_message)
-
- def testPrintRawUtf8String(self):
- message = unittest_pb2.TestAllTypes()
+ parsed_message = message_module.TestAllTypes()
+ r = text_format.Parse(wire_text, parsed_message)
+ self.assertIs(r, parsed_message)
+ self.assertEquals(message, parsed_message,
+ '\n%s != %s' % (message, parsed_message))
+
+ def testPrintRawUtf8String(self, message_module):
+ message = message_module.TestAllTypes()
message.repeated_string.append(u'\u00fc\ua71f')
- text = text_format.MessageToString(message, as_utf8 = True)
+ text = text_format.MessageToString(message, as_utf8=True)
self.CompareToGoldenText(text, 'repeated_string: "\303\274\352\234\237"\n')
- parsed_message = unittest_pb2.TestAllTypes()
- text_format.Merge(text, parsed_message)
- self.assertEquals(message, parsed_message)
+ parsed_message = message_module.TestAllTypes()
+ text_format.Parse(text, parsed_message)
+ self.assertEquals(message, parsed_message,
+ '\n%s != %s' % (message, parsed_message))
+
+ def testPrintFloatFormat(self, message_module):
+ # Check that float_format argument is passed to sub-message formatting.
+ message = message_module.NestedTestAllTypes()
+ # We use 1.25 as it is a round number in binary. The proto 32-bit float
+ # will not gain additional imprecise digits as a 64-bit Python float and
+ # show up in its str. 32-bit 1.2 is noisy when extended to 64-bit:
+ # >>> struct.unpack('f', struct.pack('f', 1.2))[0]
+ # 1.2000000476837158
+ # >>> struct.unpack('f', struct.pack('f', 1.25))[0]
+ # 1.25
+ message.payload.optional_float = 1.25
+ # Check rounding at 15 significant digits
+ message.payload.optional_double = -.000003456789012345678
+ # Check no decimal point.
+ message.payload.repeated_float.append(-5642)
+ # Check no trailing zeros.
+ message.payload.repeated_double.append(.000078900)
+ formatted_fields = ['optional_float: 1.25',
+ 'optional_double: -3.45678901234568e-6',
+ 'repeated_float: -5642',
+ 'repeated_double: 7.89e-5']
+ text_message = text_format.MessageToString(message, float_format='.15g')
+ self.CompareToGoldenText(
+ self.RemoveRedundantZeros(text_message),
+ 'payload {{\n {}\n {}\n {}\n {}\n}}\n'.format(*formatted_fields))
+ # as_one_line=True is a separate code branch where float_format is passed.
+ text_message = text_format.MessageToString(message, as_one_line=True,
+ float_format='.15g')
+ self.CompareToGoldenText(
+ self.RemoveRedundantZeros(text_message),
+ 'payload {{ {} {} {} {} }}'.format(*formatted_fields))
- def testMessageToString(self):
- message = unittest_pb2.ForeignMessage()
+ def testMessageToString(self, message_module):
+ message = message_module.ForeignMessage()
message.c = 123
self.assertEqual('c: 123\n', str(message))
- def RemoveRedundantZeros(self, text):
- # Some platforms print 1e+5 as 1e+005. This is fine, but we need to remove
- # these zeros in order to match the golden file.
- text = text.replace('e+0','e+').replace('e+0','e+') \
- .replace('e-0','e-').replace('e-0','e-')
- # Floating point fields are printed with .0 suffix even if they are
- # actualy integer numbers.
- text = re.compile('\.0$', re.MULTILINE).sub('', text)
- return text
+ def testParseAllFields(self, message_module):
+ message = message_module.TestAllTypes()
+ test_util.SetAllFields(message)
+ ascii_text = text_format.MessageToString(message)
+
+ parsed_message = message_module.TestAllTypes()
+ text_format.Parse(ascii_text, parsed_message)
+ self.assertEqual(message, parsed_message)
+ if message_module is unittest_pb2:
+ test_util.ExpectAllFieldsSet(self, message)
+
+ def testParseExotic(self, message_module):
+ message = message_module.TestAllTypes()
+ text = ('repeated_int64: -9223372036854775808\n'
+ 'repeated_uint64: 18446744073709551615\n'
+ 'repeated_double: 123.456\n'
+ 'repeated_double: 1.23e+22\n'
+ 'repeated_double: 1.23e-18\n'
+ 'repeated_string: \n'
+ '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n'
+ 'repeated_string: "foo" \'corge\' "grault"\n'
+ 'repeated_string: "\\303\\274\\352\\234\\237"\n'
+ 'repeated_string: "\\xc3\\xbc"\n'
+ 'repeated_string: "\xc3\xbc"\n')
+ text_format.Parse(text, message)
+
+ self.assertEqual(-9223372036854775808, message.repeated_int64[0])
+ self.assertEqual(18446744073709551615, message.repeated_uint64[0])
+ self.assertEqual(123.456, message.repeated_double[0])
+ self.assertEqual(1.23e22, message.repeated_double[1])
+ self.assertEqual(1.23e-18, message.repeated_double[2])
+ self.assertEqual(
+ '\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0])
+ self.assertEqual('foocorgegrault', message.repeated_string[1])
+ self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2])
+ self.assertEqual(u'\u00fc', message.repeated_string[3])
- def testMergeGolden(self):
+ def testParseTrailingCommas(self, message_module):
+ message = message_module.TestAllTypes()
+ text = ('repeated_int64: 100;\n'
+ 'repeated_int64: 200;\n'
+ 'repeated_int64: 300,\n'
+ 'repeated_string: "one",\n'
+ 'repeated_string: "two";\n')
+ text_format.Parse(text, message)
+
+ self.assertEqual(100, message.repeated_int64[0])
+ self.assertEqual(200, message.repeated_int64[1])
+ self.assertEqual(300, message.repeated_int64[2])
+ self.assertEqual(u'one', message.repeated_string[0])
+ self.assertEqual(u'two', message.repeated_string[1])
+
+ def testParseEmptyText(self, message_module):
+ message = message_module.TestAllTypes()
+ text = ''
+ text_format.Parse(text, message)
+ self.assertEquals(message_module.TestAllTypes(), message)
+
+ def testParseInvalidUtf8(self, message_module):
+ message = message_module.TestAllTypes()
+ text = 'repeated_string: "\\xc3\\xc3"'
+ self.assertRaises(text_format.ParseError, text_format.Parse, text, message)
+
+ def testParseSingleWord(self, message_module):
+ message = message_module.TestAllTypes()
+ text = 'foo'
+ self.assertRaisesRegexp(
+ text_format.ParseError,
+ (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+ r'"foo".'),
+ text_format.Parse, text, message)
+
+ def testParseUnknownField(self, message_module):
+ message = message_module.TestAllTypes()
+ text = 'unknown_field: 8\n'
+ self.assertRaisesRegexp(
+ text_format.ParseError,
+ (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+ r'"unknown_field".'),
+ text_format.Parse, text, message)
+
+ def testParseGroupNotClosed(self, message_module):
+ message = message_module.TestAllTypes()
+ text = 'RepeatedGroup: <'
+ self.assertRaisesWithLiteralMatch(
+ text_format.ParseError, '1:16 : Expected ">".',
+ text_format.Parse, text, message)
+
+ text = 'RepeatedGroup: {'
+ self.assertRaisesWithLiteralMatch(
+ text_format.ParseError, '1:16 : Expected "}".',
+ text_format.Parse, text, message)
+
+ def testParseEmptyGroup(self, message_module):
+ message = message_module.TestAllTypes()
+ text = 'OptionalGroup: {}'
+ text_format.Parse(text, message)
+ self.assertTrue(message.HasField('optionalgroup'))
+
+ message.Clear()
+
+ message = message_module.TestAllTypes()
+ text = 'OptionalGroup: <>'
+ text_format.Parse(text, message)
+ self.assertTrue(message.HasField('optionalgroup'))
+
+ def testParseBadEnumValue(self, message_module):
+ message = message_module.TestAllTypes()
+ text = 'optional_nested_enum: BARR'
+ self.assertRaisesRegexp(
+ text_format.ParseError,
+ (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+ r'has no value named BARR.'),
+ text_format.Parse, text, message)
+
+ message = message_module.TestAllTypes()
+ text = 'optional_nested_enum: 100'
+ self.assertRaisesRegexp(
+ text_format.ParseError,
+ (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+ r'has no value with number 100.'),
+ text_format.Parse, text, message)
+
+ def testParseBadIntValue(self, message_module):
+ message = message_module.TestAllTypes()
+ text = 'optional_int32: bork'
+ self.assertRaisesWithLiteralMatch(
+ text_format.ParseError,
+ ('1:17 : Couldn\'t parse integer: bork'),
+ text_format.Parse, text, message)
+
+ def testParseStringFieldUnescape(self, message_module):
+ message = message_module.TestAllTypes()
+ text = r'''repeated_string: "\xf\x62"
+ repeated_string: "\\xf\\x62"
+ repeated_string: "\\\xf\\\x62"
+ repeated_string: "\\\\xf\\\\x62"
+ repeated_string: "\\\\\xf\\\\\x62"
+ repeated_string: "\x5cx20"'''
+ text_format.Parse(text, message)
+
+ SLASH = '\\'
+ self.assertEqual('\x0fb', message.repeated_string[0])
+ self.assertEqual(SLASH + 'xf' + SLASH + 'x62', message.repeated_string[1])
+ self.assertEqual(SLASH + '\x0f' + SLASH + 'b', message.repeated_string[2])
+ self.assertEqual(SLASH + SLASH + 'xf' + SLASH + SLASH + 'x62',
+ message.repeated_string[3])
+ self.assertEqual(SLASH + SLASH + '\x0f' + SLASH + SLASH + 'b',
+ message.repeated_string[4])
+ self.assertEqual(SLASH + 'x20', message.repeated_string[5])
+
+ def testMergeDuplicateScalars(self, message_module):
+ message = message_module.TestAllTypes()
+ text = ('optional_int32: 42 '
+ 'optional_int32: 67')
+ r = text_format.Merge(text, message)
+ self.assertIs(r, message)
+ self.assertEqual(67, message.optional_int32)
+
+ def testMergeDuplicateNestedMessageScalars(self, message_module):
+ message = message_module.TestAllTypes()
+ text = ('optional_nested_message { bb: 1 } '
+ 'optional_nested_message { bb: 2 }')
+ r = text_format.Merge(text, message)
+ self.assertTrue(r is message)
+ self.assertEqual(2, message.optional_nested_message.bb)
+
+ def testParseOneof(self, message_module):
+ m = message_module.TestAllTypes()
+ m.oneof_uint32 = 11
+ m2 = message_module.TestAllTypes()
+ text_format.Parse(text_format.MessageToString(m), m2)
+ self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+
+# These are tests that aren't fundamentally specific to proto2, but are at
+# the moment because of differences between the proto2 and proto3 test schemas.
+# Ideally the schemas would be made more similar so these tests could pass.
+class OnlyWorksWithProto2RightNowTests(TextFormatBase):
+
+ def testParseGolden(self):
golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt'))
parsed_message = unittest_pb2.TestAllTypes()
- text_format.Merge(golden_text, parsed_message)
+ r = text_format.Parse(golden_text, parsed_message)
+ self.assertIs(r, parsed_message)
message = unittest_pb2.TestAllTypes()
test_util.SetAllFields(message)
self.assertEquals(message, parsed_message)
- def testMergeGoldenExtensions(self):
- golden_text = '\n'.join(self.ReadGolden(
- 'text_format_unittest_extensions_data.txt'))
- parsed_message = unittest_pb2.TestAllExtensions()
- text_format.Merge(golden_text, parsed_message)
-
- message = unittest_pb2.TestAllExtensions()
- test_util.SetAllExtensions(message)
- self.assertEquals(message, parsed_message)
+ def testPrintAllFields(self):
+ message = unittest_pb2.TestAllTypes()
+ test_util.SetAllFields(message)
+ self.CompareToGoldenFile(
+ self.RemoveRedundantZeros(text_format.MessageToString(message)),
+ 'text_format_unittest_data_oneof_implemented.txt')
- def testMergeAllFields(self):
+ def testPrintAllFieldsPointy(self):
message = unittest_pb2.TestAllTypes()
test_util.SetAllFields(message)
- ascii_text = text_format.MessageToString(message)
+ self.CompareToGoldenFile(
+ self.RemoveRedundantZeros(
+ text_format.MessageToString(message, pointy_brackets=True)),
+ 'text_format_unittest_data_pointy_oneof.txt')
+
+ def testPrintInIndexOrder(self):
+ message = unittest_pb2.TestFieldOrderings()
+ 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'
+ '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'
+ 'optional_nested_message {\n bb: 1\n oo: 0\n}\n')
+ def testMergeLinesGolden(self):
+ opened = self.ReadGolden('text_format_unittest_data.txt')
parsed_message = unittest_pb2.TestAllTypes()
- text_format.Merge(ascii_text, parsed_message)
+ r = text_format.MergeLines(opened, parsed_message)
+ self.assertIs(r, parsed_message)
+
+ message = unittest_pb2.TestAllTypes()
+ test_util.SetAllFields(message)
self.assertEqual(message, parsed_message)
- test_util.ExpectAllFieldsSet(self, message)
- def testMergeAllExtensions(self):
- message = unittest_pb2.TestAllExtensions()
- test_util.SetAllExtensions(message)
- ascii_text = text_format.MessageToString(message)
+ def testParseLinesGolden(self):
+ opened = self.ReadGolden('text_format_unittest_data.txt')
+ parsed_message = unittest_pb2.TestAllTypes()
+ r = text_format.ParseLines(opened, parsed_message)
+ self.assertIs(r, parsed_message)
- parsed_message = unittest_pb2.TestAllExtensions()
- text_format.Merge(ascii_text, parsed_message)
- self.assertEqual(message, parsed_message)
+ message = unittest_pb2.TestAllTypes()
+ test_util.SetAllFields(message)
+ self.assertEquals(message, parsed_message)
+
+
+# Tests of proto2-only features (MessageSet and extensions).
+class Proto2Tests(TextFormatBase):
+
+ def testPrintMessageSet(self):
+ message = unittest_mset_pb2.TestMessageSetContainer()
+ ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+ ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+ message.message_set.Extensions[ext1].i = 23
+ message.message_set.Extensions[ext2].str = 'foo'
+ self.CompareToGoldenText(
+ text_format.MessageToString(message),
+ 'message_set {\n'
+ ' [protobuf_unittest.TestMessageSetExtension1] {\n'
+ ' i: 23\n'
+ ' }\n'
+ ' [protobuf_unittest.TestMessageSetExtension2] {\n'
+ ' str: \"foo\"\n'
+ ' }\n'
+ '}\n')
- def testMergeMessageSet(self):
+ def testPrintMessageSetAsOneLine(self):
+ message = unittest_mset_pb2.TestMessageSetContainer()
+ ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+ ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+ message.message_set.Extensions[ext1].i = 23
+ message.message_set.Extensions[ext2].str = 'foo'
+ self.CompareToGoldenText(
+ text_format.MessageToString(message, as_one_line=True),
+ 'message_set {'
+ ' [protobuf_unittest.TestMessageSetExtension1] {'
+ ' i: 23'
+ ' }'
+ ' [protobuf_unittest.TestMessageSetExtension2] {'
+ ' str: \"foo\"'
+ ' }'
+ ' }')
+
+ def testParseMessageSet(self):
message = unittest_pb2.TestAllTypes()
text = ('repeated_uint64: 1\n'
'repeated_uint64: 2\n')
- text_format.Merge(text, message)
+ text_format.Parse(text, message)
self.assertEqual(1, message.repeated_uint64[0])
self.assertEqual(2, message.repeated_uint64[1])
@@ -282,144 +526,102 @@ class TextFormatTest(unittest.TestCase):
' str: \"foo\"\n'
' }\n'
'}\n')
- text_format.Merge(text, message)
+ text_format.Parse(text, message)
ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
self.assertEquals(23, message.message_set.Extensions[ext1].i)
self.assertEquals('foo', message.message_set.Extensions[ext2].str)
- def testMergeExotic(self):
- message = unittest_pb2.TestAllTypes()
- text = ('repeated_int64: -9223372036854775808\n'
- 'repeated_uint64: 18446744073709551615\n'
- 'repeated_double: 123.456\n'
- 'repeated_double: 1.23e+22\n'
- 'repeated_double: 1.23e-18\n'
- 'repeated_string: \n'
- '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n'
- 'repeated_string: "foo" \'corge\' "grault"\n'
- 'repeated_string: "\\303\\274\\352\\234\\237"\n'
- 'repeated_string: "\\xc3\\xbc"\n'
- 'repeated_string: "\xc3\xbc"\n')
- text_format.Merge(text, message)
+ def testPrintAllExtensions(self):
+ message = unittest_pb2.TestAllExtensions()
+ test_util.SetAllExtensions(message)
+ self.CompareToGoldenFile(
+ self.RemoveRedundantZeros(text_format.MessageToString(message)),
+ 'text_format_unittest_extensions_data.txt')
- self.assertEqual(-9223372036854775808, message.repeated_int64[0])
- self.assertEqual(18446744073709551615, message.repeated_uint64[0])
- self.assertEqual(123.456, message.repeated_double[0])
- self.assertEqual(1.23e22, message.repeated_double[1])
- self.assertEqual(1.23e-18, message.repeated_double[2])
- self.assertEqual(
- '\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0])
- self.assertEqual('foocorgegrault', message.repeated_string[1])
- self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2])
- self.assertEqual(u'\u00fc', message.repeated_string[3])
+ def testPrintAllExtensionsPointy(self):
+ message = unittest_pb2.TestAllExtensions()
+ test_util.SetAllExtensions(message)
+ self.CompareToGoldenFile(
+ self.RemoveRedundantZeros(text_format.MessageToString(
+ message, pointy_brackets=True)),
+ 'text_format_unittest_extensions_data_pointy.txt')
- def testMergeEmptyText(self):
- message = unittest_pb2.TestAllTypes()
- text = ''
- text_format.Merge(text, message)
- self.assertEquals(unittest_pb2.TestAllTypes(), message)
+ def testParseGoldenExtensions(self):
+ golden_text = '\n'.join(self.ReadGolden(
+ 'text_format_unittest_extensions_data.txt'))
+ parsed_message = unittest_pb2.TestAllExtensions()
+ text_format.Parse(golden_text, parsed_message)
- def testMergeInvalidUtf8(self):
- message = unittest_pb2.TestAllTypes()
- text = 'repeated_string: "\\xc3\\xc3"'
- self.assertRaises(text_format.ParseError, text_format.Merge, text, message)
+ message = unittest_pb2.TestAllExtensions()
+ test_util.SetAllExtensions(message)
+ self.assertEquals(message, parsed_message)
- def testMergeSingleWord(self):
- message = unittest_pb2.TestAllTypes()
- text = 'foo'
- self.assertRaisesWithMessage(
- text_format.ParseError,
- ('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named '
- '"foo".'),
- text_format.Merge, text, message)
+ def testParseAllExtensions(self):
+ message = unittest_pb2.TestAllExtensions()
+ test_util.SetAllExtensions(message)
+ ascii_text = text_format.MessageToString(message)
- def testMergeUnknownField(self):
- message = unittest_pb2.TestAllTypes()
- text = 'unknown_field: 8\n'
- self.assertRaisesWithMessage(
- text_format.ParseError,
- ('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named '
- '"unknown_field".'),
- text_format.Merge, text, message)
+ parsed_message = unittest_pb2.TestAllExtensions()
+ text_format.Parse(ascii_text, parsed_message)
+ self.assertEqual(message, parsed_message)
- def testMergeBadExtension(self):
+ def testParseBadExtension(self):
message = unittest_pb2.TestAllExtensions()
text = '[unknown_extension]: 8\n'
- self.assertRaisesWithMessage(
+ self.assertRaisesWithLiteralMatch(
text_format.ParseError,
'1:2 : Extension "unknown_extension" not registered.',
- text_format.Merge, text, message)
+ text_format.Parse, text, message)
message = unittest_pb2.TestAllTypes()
- self.assertRaisesWithMessage(
+ self.assertRaisesWithLiteralMatch(
text_format.ParseError,
('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
'extensions.'),
- text_format.Merge, text, message)
-
- def testMergeGroupNotClosed(self):
- message = unittest_pb2.TestAllTypes()
- text = 'RepeatedGroup: <'
- self.assertRaisesWithMessage(
- text_format.ParseError, '1:16 : Expected ">".',
- text_format.Merge, text, message)
+ text_format.Parse, text, message)
- text = 'RepeatedGroup: {'
- self.assertRaisesWithMessage(
- text_format.ParseError, '1:16 : Expected "}".',
- text_format.Merge, text, message)
-
- def testMergeEmptyGroup(self):
- message = unittest_pb2.TestAllTypes()
- text = 'OptionalGroup: {}'
+ def testMergeDuplicateExtensionScalars(self):
+ message = unittest_pb2.TestAllExtensions()
+ text = ('[protobuf_unittest.optional_int32_extension]: 42 '
+ '[protobuf_unittest.optional_int32_extension]: 67')
text_format.Merge(text, message)
- self.assertTrue(message.HasField('optionalgroup'))
-
- message.Clear()
+ self.assertEqual(
+ 67,
+ message.Extensions[unittest_pb2.optional_int32_extension])
- message = unittest_pb2.TestAllTypes()
- text = 'OptionalGroup: <>'
- text_format.Merge(text, message)
- self.assertTrue(message.HasField('optionalgroup'))
+ def testParseDuplicateExtensionScalars(self):
+ message = unittest_pb2.TestAllExtensions()
+ text = ('[protobuf_unittest.optional_int32_extension]: 42 '
+ '[protobuf_unittest.optional_int32_extension]: 67')
+ self.assertRaisesWithLiteralMatch(
+ text_format.ParseError,
+ ('1:96 : Message type "protobuf_unittest.TestAllExtensions" '
+ 'should not have multiple '
+ '"protobuf_unittest.optional_int32_extension" extensions.'),
+ text_format.Parse, text, message)
- def testMergeBadEnumValue(self):
+ def testParseDuplicateNestedMessageScalars(self):
message = unittest_pb2.TestAllTypes()
- text = 'optional_nested_enum: BARR'
- self.assertRaisesWithMessage(
+ text = ('optional_nested_message { bb: 1 } '
+ 'optional_nested_message { bb: 2 }')
+ self.assertRaisesWithLiteralMatch(
text_format.ParseError,
- ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
- 'has no value named BARR.'),
- text_format.Merge, text, message)
+ ('1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
+ 'should not have multiple "bb" fields.'),
+ text_format.Parse, text, message)
+ def testParseDuplicateScalars(self):
message = unittest_pb2.TestAllTypes()
- text = 'optional_nested_enum: 100'
- self.assertRaisesWithMessage(
+ text = ('optional_int32: 42 '
+ 'optional_int32: 67')
+ self.assertRaisesWithLiteralMatch(
text_format.ParseError,
- ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
- 'has no value with number 100.'),
- text_format.Merge, text, message)
-
- def assertRaisesWithMessage(self, e_class, e, func, *args, **kwargs):
- """Same as assertRaises, but also compares the exception message."""
- if hasattr(e_class, '__name__'):
- exc_name = e_class.__name__
- else:
- exc_name = str(e_class)
-
- try:
- func(*args, **kwargs)
- except e_class, expr:
- if str(expr) != e:
- msg = '%s raised, but with wrong message: "%s" instead of "%s"'
- raise self.failureException(msg % (exc_name,
- str(expr).encode('string_escape'),
- e.encode('string_escape')))
- return
- else:
- raise self.failureException('%s not raised' % exc_name)
-
-
-class TokenizerTest(unittest.TestCase):
+ ('1:36 : Message type "protobuf_unittest.TestAllTypes" should not '
+ 'have multiple "optional_int32" fields.'),
+ text_format.Parse, text, message)
+
+
+class TokenizerTest(basetest.TestCase):
def testSimpleTokenCases(self):
text = ('identifier1:"string1"\n \n\n'
@@ -427,9 +629,9 @@ class TokenizerTest(unittest.TestCase):
'identifiER_4 : 1.1e+2 ID5:-0.23 ID6:\'aaaa\\\'bbbb\'\n'
'ID7 : "aa\\"bb"\n\n\n\n ID8: {A:inf B:-inf C:true D:false}\n'
'ID9: 22 ID10: -111111111111111111 ID11: -22\n'
- 'ID12: 2222222222222222222 '
- 'false_bool: 0 true_BOOL:t \n true_bool1: 1 false_BOOL1:f ' )
- tokenizer = text_format._Tokenizer(text)
+ 'ID12: 2222222222222222222 ID13: 1.23456f ID14: 1.2e+2f '
+ 'false_bool: 0 true_BOOL:t \n true_bool1: 1 false_BOOL1:f ')
+ tokenizer = text_format._Tokenizer(text.splitlines())
methods = [(tokenizer.ConsumeIdentifier, 'identifier1'),
':',
(tokenizer.ConsumeString, 'string1'),
@@ -456,10 +658,10 @@ class TokenizerTest(unittest.TestCase):
'{',
(tokenizer.ConsumeIdentifier, 'A'),
':',
- (tokenizer.ConsumeFloat, text_format._INFINITY),
+ (tokenizer.ConsumeFloat, float('inf')),
(tokenizer.ConsumeIdentifier, 'B'),
':',
- (tokenizer.ConsumeFloat, -text_format._INFINITY),
+ (tokenizer.ConsumeFloat, -float('inf')),
(tokenizer.ConsumeIdentifier, 'C'),
':',
(tokenizer.ConsumeBool, True),
@@ -479,6 +681,12 @@ class TokenizerTest(unittest.TestCase):
(tokenizer.ConsumeIdentifier, 'ID12'),
':',
(tokenizer.ConsumeUint64, 2222222222222222222),
+ (tokenizer.ConsumeIdentifier, 'ID13'),
+ ':',
+ (tokenizer.ConsumeFloat, 1.23456),
+ (tokenizer.ConsumeIdentifier, 'ID14'),
+ ':',
+ (tokenizer.ConsumeFloat, 1.2e+2),
(tokenizer.ConsumeIdentifier, 'false_bool'),
':',
(tokenizer.ConsumeBool, False),
@@ -509,7 +717,7 @@ class TokenizerTest(unittest.TestCase):
int64_max = (1 << 63) - 1
uint32_max = (1 << 32) - 1
text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
- tokenizer = text_format._Tokenizer(text)
+ tokenizer = text_format._Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint64)
self.assertEqual(-1, tokenizer.ConsumeInt32())
@@ -523,7 +731,7 @@ class TokenizerTest(unittest.TestCase):
self.assertTrue(tokenizer.AtEnd())
text = '-0 -0 0 0'
- tokenizer = text_format._Tokenizer(text)
+ tokenizer = text_format._Tokenizer(text.splitlines())
self.assertEqual(0, tokenizer.ConsumeUint32())
self.assertEqual(0, tokenizer.ConsumeUint64())
self.assertEqual(0, tokenizer.ConsumeUint32())
@@ -532,40 +740,30 @@ class TokenizerTest(unittest.TestCase):
def testConsumeByteString(self):
text = '"string1\''
- tokenizer = text_format._Tokenizer(text)
+ tokenizer = text_format._Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = 'string1"'
- tokenizer = text_format._Tokenizer(text)
+ tokenizer = text_format._Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = '\n"\\xt"'
- tokenizer = text_format._Tokenizer(text)
+ tokenizer = text_format._Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = '\n"\\"'
- tokenizer = text_format._Tokenizer(text)
+ tokenizer = text_format._Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = '\n"\\x"'
- tokenizer = text_format._Tokenizer(text)
+ tokenizer = text_format._Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
def testConsumeBool(self):
text = 'not-a-bool'
- tokenizer = text_format._Tokenizer(text)
+ tokenizer = text_format._Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool)
- def testInfNan(self):
- # Make sure our infinity and NaN definitions are sound.
- self.assertEquals(float, type(text_format._INFINITY))
- self.assertEquals(float, type(text_format._NAN))
- self.assertTrue(text_format._NAN != text_format._NAN)
-
- inf_times_zero = text_format._INFINITY * 0
- self.assertTrue(inf_times_zero != inf_times_zero)
- self.assertTrue(text_format._INFINITY > 0)
-
if __name__ == '__main__':
- unittest.main()
+ basetest.main()
diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py
index 2b3cd4de..76c056c4 100755
--- a/python/google/protobuf/internal/type_checkers.py
+++ b/python/google/protobuf/internal/type_checkers.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -28,6 +28,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#PY25 compatible for GAE.
+#
+# Copyright 2008 Google Inc. All Rights Reserved.
+
"""Provides type checking routines.
This module defines type checking utilities in the forms of dictionaries:
@@ -45,6 +49,9 @@ TYPE_TO_DESERIALIZE_METHOD: A dictionary with field types and deserialization
__author__ = 'robinson@google.com (Will Robinson)'
+import sys ##PY25
+if sys.version < '2.6': bytes = str ##PY25
+from google.protobuf.internal import api_implementation
from google.protobuf.internal import decoder
from google.protobuf.internal import encoder
from google.protobuf.internal import wire_format
@@ -52,22 +59,29 @@ from google.protobuf import descriptor
_FieldDescriptor = descriptor.FieldDescriptor
+def SupportsOpenEnums(field_descriptor):
+ return field_descriptor.containing_type.syntax == "proto3"
-def GetTypeChecker(cpp_type, field_type):
+def GetTypeChecker(field):
"""Returns a type checker for a message field of the specified types.
Args:
- cpp_type: C++ type of the field (see descriptor.py).
- field_type: Protocol message field type (see descriptor.py).
+ field: FieldDescriptor object for this field.
Returns:
An instance of TypeChecker which can be used to verify the types
of values assigned to a field of the specified type.
"""
- if (cpp_type == _FieldDescriptor.CPPTYPE_STRING and
- field_type == _FieldDescriptor.TYPE_STRING):
+ if (field.cpp_type == _FieldDescriptor.CPPTYPE_STRING and
+ field.type == _FieldDescriptor.TYPE_STRING):
return UnicodeValueChecker()
- return _VALUE_CHECKERS[cpp_type]
+ if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
+ if SupportsOpenEnums(field):
+ # When open enums are supported, any int32 can be assigned.
+ return _VALUE_CHECKERS[_FieldDescriptor.CPPTYPE_INT32]
+ else:
+ return EnumValueChecker(field.enum_type)
+ return _VALUE_CHECKERS[field.cpp_type]
# None of the typecheckers below make any attempt to guard against people
@@ -85,10 +99,15 @@ class TypeChecker(object):
self._acceptable_types = acceptable_types
def CheckValue(self, proposed_value):
+ """Type check the provided value and return it.
+
+ The returned value might have been normalized to another type.
+ """
if not isinstance(proposed_value, self._acceptable_types):
message = ('%.1024r has type %s, but expected one of: %s' %
(proposed_value, type(proposed_value), self._acceptable_types))
raise TypeError(message)
+ return proposed_value
# IntValueChecker and its subclasses perform integer type-checks
@@ -104,28 +123,53 @@ class IntValueChecker(object):
raise TypeError(message)
if not self._MIN <= proposed_value <= self._MAX:
raise ValueError('Value out of range: %d' % proposed_value)
+ # We force 32-bit values to int and 64-bit values to long to make
+ # alternate implementations where the distinction is more significant
+ # (e.g. the C++ implementation) simpler.
+ proposed_value = self._TYPE(proposed_value)
+ return proposed_value
+
+
+class EnumValueChecker(object):
+
+ """Checker used for enum fields. Performs type-check and range check."""
+
+ def __init__(self, enum_type):
+ self._enum_type = enum_type
+
+ def CheckValue(self, proposed_value):
+ if not isinstance(proposed_value, (int, long)):
+ message = ('%.1024r has type %s, but expected one of: %s' %
+ (proposed_value, type(proposed_value), (int, long)))
+ raise TypeError(message)
+ if proposed_value not in self._enum_type.values_by_number:
+ raise ValueError('Unknown enum value: %d' % proposed_value)
+ return proposed_value
class UnicodeValueChecker(object):
- """Checker used for string fields."""
+ """Checker used for string fields.
+
+ Always returns a unicode value, even if the input is of type str.
+ """
def CheckValue(self, proposed_value):
- if not isinstance(proposed_value, (str, unicode)):
+ if not isinstance(proposed_value, (bytes, unicode)):
message = ('%.1024r has type %s, but expected one of: %s' %
- (proposed_value, type(proposed_value), (str, unicode)))
+ (proposed_value, type(proposed_value), (bytes, unicode)))
raise TypeError(message)
- # If the value is of type 'str' make sure that it is in 7-bit ASCII
- # encoding.
- if isinstance(proposed_value, str):
+ # If the value is of type 'bytes' make sure that it is valid UTF-8 data.
+ if isinstance(proposed_value, bytes):
try:
- unicode(proposed_value, 'ascii')
+ proposed_value = proposed_value.decode('utf-8')
except UnicodeDecodeError:
- raise ValueError('%.1024r has type str, 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
class Int32ValueChecker(IntValueChecker):
@@ -133,21 +177,25 @@ class Int32ValueChecker(IntValueChecker):
# efficient.
_MIN = -2147483648
_MAX = 2147483647
+ _TYPE = int
class Uint32ValueChecker(IntValueChecker):
_MIN = 0
_MAX = (1 << 32) - 1
+ _TYPE = int
class Int64ValueChecker(IntValueChecker):
_MIN = -(1 << 63)
_MAX = (1 << 63) - 1
+ _TYPE = long
class Uint64ValueChecker(IntValueChecker):
_MIN = 0
_MAX = (1 << 64) - 1
+ _TYPE = long
# Type-checkers for all scalar CPPTYPEs.
@@ -161,8 +209,7 @@ _VALUE_CHECKERS = {
_FieldDescriptor.CPPTYPE_FLOAT: TypeChecker(
float, int, long),
_FieldDescriptor.CPPTYPE_BOOL: TypeChecker(bool, int),
- _FieldDescriptor.CPPTYPE_ENUM: Int32ValueChecker(),
- _FieldDescriptor.CPPTYPE_STRING: TypeChecker(str),
+ _FieldDescriptor.CPPTYPE_STRING: TypeChecker(bytes),
}
diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py
new file mode 100755
index 00000000..59f9ae4c
--- /dev/null
+++ b/python/google/protobuf/internal/unknown_fields_test.py
@@ -0,0 +1,264 @@
+#! /usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# 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.
+
+"""Test for preservation of unknown fields in the pure Python implementation."""
+
+__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 import unittest_proto3_arena_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
+
+
+class UnknownFieldsTest(basetest.TestCase):
+
+ def setUp(self):
+ self.descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+ self.all_fields = unittest_pb2.TestAllTypes()
+ test_util.SetAllFields(self.all_fields)
+ self.all_fields_data = self.all_fields.SerializeToString()
+ self.empty_message = unittest_pb2.TestEmptyMessage()
+ self.empty_message.ParseFromString(self.all_fields_data)
+
+ def testSerialize(self):
+ data = self.empty_message.SerializeToString()
+
+ # Don't use assertEqual because we don't want to dump raw binary data to
+ # stdout.
+ self.assertTrue(data == self.all_fields_data)
+
+ def testSerializeProto3(self):
+ # Verify that proto3 doesn't preserve unknown fields.
+ message = unittest_proto3_arena_pb2.TestEmptyMessage()
+ message.ParseFromString(self.all_fields_data)
+ self.assertEqual(0, len(message.SerializeToString()))
+
+ def testByteSize(self):
+ self.assertEqual(self.all_fields.ByteSize(), self.empty_message.ByteSize())
+
+ def testListFields(self):
+ # Make sure ListFields doesn't return unknown fields.
+ self.assertEqual(0, len(self.empty_message.ListFields()))
+
+ def testSerializeMessageSetWireFormatUnknownExtension(self):
+ # Create a message using the message set wire format with an unknown
+ # message.
+ raw = unittest_mset_pb2.RawMessageSet()
+
+ # Add an unknown extension.
+ item = raw.item.add()
+ item.type_id = 1545009
+ message1 = unittest_mset_pb2.TestMessageSetExtension1()
+ message1.i = 12345
+ item.message = message1.SerializeToString()
+
+ serialized = raw.SerializeToString()
+
+ # Parse message using the message set wire format.
+ proto = unittest_mset_pb2.TestMessageSet()
+ proto.MergeFromString(serialized)
+
+ # Verify that the unknown extension is serialized unchanged
+ reserialized = proto.SerializeToString()
+ new_raw = unittest_mset_pb2.RawMessageSet()
+ new_raw.MergeFromString(reserialized)
+ self.assertEqual(raw, new_raw)
+
+ # C++ implementation for proto2 does not currently take into account unknown
+ # fields when checking equality.
+ #
+ # TODO(haberman): fix this.
+ @basetest.unittest.skipIf(
+ api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
+ 'C++ implementation does not expose unknown fields to Python')
+ def testEquals(self):
+ message = unittest_pb2.TestEmptyMessage()
+ message.ParseFromString(self.all_fields_data)
+ self.assertEqual(self.empty_message, message)
+
+ self.all_fields.ClearField('optional_string')
+ message.ParseFromString(self.all_fields.SerializeToString())
+ self.assertNotEqual(self.empty_message, message)
+
+
+@basetest.unittest.skipIf(
+ api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
+ 'C++ implementation does not expose unknown fields to Python')
+class UnknownFieldsAccessorsTest(basetest.TestCase):
+
+ def setUp(self):
+ self.descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+ self.all_fields = unittest_pb2.TestAllTypes()
+ test_util.SetAllFields(self.all_fields)
+ self.all_fields_data = self.all_fields.SerializeToString()
+ self.empty_message = unittest_pb2.TestEmptyMessage()
+ self.empty_message.ParseFromString(self.all_fields_data)
+ self.unknown_fields = self.empty_message._unknown_fields
+
+ def GetField(self, name):
+ field_descriptor = self.descriptor.fields_by_name[name]
+ wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type]
+ field_tag = encoder.TagBytes(field_descriptor.number, wire_type)
+ result_dict = {}
+ for tag_bytes, value in self.unknown_fields:
+ if tag_bytes == field_tag:
+ decoder = unittest_pb2.TestAllTypes._decoders_by_tag[tag_bytes][0]
+ decoder(value, 0, len(value), self.all_fields, result_dict)
+ return result_dict[field_descriptor]
+
+ def testEnum(self):
+ value = self.GetField('optional_nested_enum')
+ self.assertEqual(self.all_fields.optional_nested_enum, value)
+
+ def testRepeatedEnum(self):
+ value = self.GetField('repeated_nested_enum')
+ self.assertEqual(self.all_fields.repeated_nested_enum, value)
+
+ def testVarint(self):
+ value = self.GetField('optional_int32')
+ self.assertEqual(self.all_fields.optional_int32, value)
+
+ def testFixed32(self):
+ value = self.GetField('optional_fixed32')
+ self.assertEqual(self.all_fields.optional_fixed32, value)
+
+ def testFixed64(self):
+ value = self.GetField('optional_fixed64')
+ self.assertEqual(self.all_fields.optional_fixed64, value)
+
+ def testLengthDelimited(self):
+ value = self.GetField('optional_string')
+ self.assertEqual(self.all_fields.optional_string, value)
+
+ def testGroup(self):
+ value = self.GetField('optionalgroup')
+ self.assertEqual(self.all_fields.optionalgroup, value)
+
+ def testCopyFrom(self):
+ message = unittest_pb2.TestEmptyMessage()
+ message.CopyFrom(self.empty_message)
+ self.assertEqual(self.unknown_fields, message._unknown_fields)
+
+ def testMergeFrom(self):
+ message = unittest_pb2.TestAllTypes()
+ message.optional_int32 = 1
+ message.optional_uint32 = 2
+ source = unittest_pb2.TestEmptyMessage()
+ source.ParseFromString(message.SerializeToString())
+
+ message.ClearField('optional_int32')
+ message.optional_int64 = 3
+ message.optional_uint32 = 4
+ destination = unittest_pb2.TestEmptyMessage()
+ destination.ParseFromString(message.SerializeToString())
+ unknown_fields = destination._unknown_fields[:]
+
+ destination.MergeFrom(source)
+ self.assertEqual(unknown_fields + source._unknown_fields,
+ destination._unknown_fields)
+
+ def testClear(self):
+ self.empty_message.Clear()
+ self.assertEqual(0, len(self.empty_message._unknown_fields))
+
+ def testUnknownExtensions(self):
+ message = unittest_pb2.TestEmptyMessageWithExtensions()
+ message.ParseFromString(self.all_fields_data)
+ self.assertEqual(self.empty_message._unknown_fields,
+ message._unknown_fields)
+
+
+
+@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
+
+ self.message = missing_enum_values_pb2.TestEnumValues()
+ self.message.optional_nested_enum = (
+ missing_enum_values_pb2.TestEnumValues.ZERO)
+ self.message.repeated_nested_enum.extend([
+ missing_enum_values_pb2.TestEnumValues.ZERO,
+ missing_enum_values_pb2.TestEnumValues.ONE,
+ ])
+ self.message.packed_nested_enum.extend([
+ missing_enum_values_pb2.TestEnumValues.ZERO,
+ missing_enum_values_pb2.TestEnumValues.ONE,
+ ])
+ self.message_data = self.message.SerializeToString()
+ self.missing_message = missing_enum_values_pb2.TestMissingEnumValues()
+ self.missing_message.ParseFromString(self.message_data)
+ self.unknown_fields = self.missing_message._unknown_fields
+
+ def GetField(self, name):
+ field_descriptor = self.descriptor.fields_by_name[name]
+ wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type]
+ field_tag = encoder.TagBytes(field_descriptor.number, wire_type)
+ result_dict = {}
+ for tag_bytes, value in self.unknown_fields:
+ if tag_bytes == field_tag:
+ decoder = missing_enum_values_pb2.TestEnumValues._decoders_by_tag[
+ tag_bytes][0]
+ decoder(value, 0, len(value), self.message, result_dict)
+ return result_dict[field_descriptor]
+
+ def testUnknownEnumValue(self):
+ self.assertFalse(self.missing_message.HasField('optional_nested_enum'))
+ value = self.GetField('optional_nested_enum')
+ self.assertEqual(self.message.optional_nested_enum, value)
+
+ def testUnknownRepeatedEnumValue(self):
+ value = self.GetField('repeated_nested_enum')
+ self.assertEqual(self.message.repeated_nested_enum, value)
+
+ def testUnknownPackedEnumValue(self):
+ value = self.GetField('packed_nested_enum')
+ self.assertEqual(self.message.packed_nested_enum, value)
+
+ def testRoundTrip(self):
+ new_message = missing_enum_values_pb2.TestEnumValues()
+ new_message.ParseFromString(self.missing_message.SerializeToString())
+ self.assertEqual(self.message, new_message)
+
+
+if __name__ == '__main__':
+ basetest.main()
diff --git a/python/google/protobuf/internal/wire_format.py b/python/google/protobuf/internal/wire_format.py
index c941fe1a..883f5255 100755
--- a/python/google/protobuf/internal/wire_format.py
+++ b/python/google/protobuf/internal/wire_format.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py
index 76007786..f39035ca 100755
--- a/python/google/protobuf/internal/wire_format_test.py
+++ b/python/google/protobuf/internal/wire_format_test.py
@@ -2,7 +2,7 @@
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -34,12 +34,12 @@
__author__ = 'robinson@google.com (Will Robinson)'
-import unittest
+from google.apputils import basetest
from google.protobuf import message
from google.protobuf.internal import wire_format
-class WireFormatTest(unittest.TestCase):
+class WireFormatTest(basetest.TestCase):
def testPackTag(self):
field_number = 0xabc
@@ -195,7 +195,7 @@ class WireFormatTest(unittest.TestCase):
# Test UTF-8 string byte size calculation.
# 1 byte for tag, 1 byte for length, 8 bytes for content.
self.assertEqual(10, wire_format.StringByteSize(
- 5, unicode('\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82', 'utf-8')))
+ 5, b'\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82'.decode('utf-8')))
class MockMessage(object):
def __init__(self, byte_size):
@@ -250,4 +250,4 @@ class WireFormatTest(unittest.TestCase):
if __name__ == '__main__':
- unittest.main()
+ basetest.main()
diff --git a/python/google/protobuf/message.py b/python/google/protobuf/message.py
index 6f19f85f..de2f5697 100755
--- a/python/google/protobuf/message.py
+++ b/python/google/protobuf/message.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -36,7 +36,6 @@
__author__ = 'robinson@google.com (Will Robinson)'
-
class Error(Exception): pass
class DecodeError(Error): pass
class EncodeError(Error): pass
@@ -73,6 +72,7 @@ class Message(object):
return clone
def __eq__(self, other_msg):
+ """Recursively compares two messages by value and structure."""
raise NotImplementedError
def __ne__(self, other_msg):
@@ -83,9 +83,11 @@ class Message(object):
raise TypeError('unhashable object')
def __str__(self):
+ """Outputs a human-readable representation of the message."""
raise NotImplementedError
def __unicode__(self):
+ """Outputs a human-readable representation of the message."""
raise NotImplementedError
def MergeFrom(self, other_msg):
@@ -174,7 +176,11 @@ class Message(object):
raise NotImplementedError
def ParseFromString(self, serialized):
- """Like MergeFromString(), except we clear the object first."""
+ """Parse serialized protocol buffer data into this message.
+
+ Like MergeFromString(), except we clear the object first and
+ do not return the value that MergeFromString returns.
+ """
self.Clear()
self.MergeFromString(serialized)
@@ -226,12 +232,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):
@@ -266,3 +281,12 @@ class Message(object):
via a previous _SetListener() call.
"""
raise NotImplementedError
+
+ def __getstate__(self):
+ """Support the pickle protocol."""
+ return dict(serialized=self.SerializePartialToString())
+
+ def __setstate__(self, state):
+ """Support the pickle protocol."""
+ self.__init__()
+ self.ParseFromString(state['serialized'])
diff --git a/python/google/protobuf/message_factory.py b/python/google/protobuf/message_factory.py
new file mode 100644
index 00000000..7fd7bec0
--- /dev/null
+++ b/python/google/protobuf/message_factory.py
@@ -0,0 +1,155 @@
+# 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.
+
+#PY25 compatible for GAE.
+#
+# Copyright 2012 Google Inc. All Rights Reserved.
+
+"""Provides a factory class for generating dynamic messages.
+
+The easiest way to use this class is if you have access to the FileDescriptor
+protos containing the messages you want to create you can just do the following:
+
+message_classes = message_factory.GetMessages(iterable_of_file_descriptors)
+my_proto_instance = message_classes['some.proto.package.MessageName']()
+"""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+import sys ##PY25
+from google.protobuf import descriptor_database
+from google.protobuf import descriptor_pool
+from google.protobuf import message
+from google.protobuf import reflection
+
+
+class MessageFactory(object):
+ """Factory for creating Proto2 messages from descriptors in a pool."""
+
+ def __init__(self, pool=None):
+ """Initializes a new factory."""
+ self.pool = (pool or descriptor_pool.DescriptorPool(
+ descriptor_database.DescriptorDatabase()))
+
+ # local cache of all classes built from protobuf descriptors
+ self._classes = {}
+
+ def GetPrototype(self, descriptor):
+ """Builds a proto2 message class based on the passed in descriptor.
+
+ Passing a descriptor with a fully qualified name matching a previous
+ invocation will cause the same class to be returned.
+
+ Args:
+ descriptor: The descriptor to build from.
+
+ Returns:
+ A class describing the passed in descriptor.
+ """
+ if descriptor.full_name not in self._classes:
+ descriptor_name = descriptor.name
+ if sys.version_info[0] < 3: ##PY25
+##!PY25 if str is bytes: # PY2
+ descriptor_name = descriptor.name.encode('ascii', 'ignore')
+ result_class = reflection.GeneratedProtocolMessageType(
+ descriptor_name,
+ (message.Message,),
+ {'DESCRIPTOR': descriptor, '__module__': None})
+ # If module not set, it wrongly points to the reflection.py module.
+ self._classes[descriptor.full_name] = result_class
+ for field in descriptor.fields:
+ if field.message_type:
+ self.GetPrototype(field.message_type)
+ for extension in result_class.DESCRIPTOR.extensions:
+ if extension.containing_type.full_name not in self._classes:
+ self.GetPrototype(extension.containing_type)
+ extended_class = self._classes[extension.containing_type.full_name]
+ extended_class.RegisterExtension(extension)
+ return self._classes[descriptor.full_name]
+
+ def GetMessages(self, files):
+ """Gets all the messages from a specified file.
+
+ This will find and resolve dependencies, failing if the descriptor
+ pool cannot satisfy them.
+
+ Args:
+ files: The file names to extract messages from.
+
+ Returns:
+ A dictionary mapping proto names to the message classes. This will include
+ any dependent messages as well as any messages defined in the same file as
+ a specified message.
+ """
+ result = {}
+ for file_name in files:
+ file_desc = self.pool.FindFileByName(file_name)
+ for name, msg in file_desc.message_types_by_name.iteritems():
+ if file_desc.package:
+ full_name = '.'.join([file_desc.package, name])
+ else:
+ full_name = msg.name
+ result[full_name] = self.GetPrototype(
+ self.pool.FindMessageTypeByName(full_name))
+
+ # While the extension FieldDescriptors are created by the descriptor pool,
+ # the python classes created in the factory need them to be registered
+ # explicitly, which is done below.
+ #
+ # The call to RegisterExtension will specifically check if the
+ # extension was already registered on the object and either
+ # ignore the registration if the original was the same, or raise
+ # an error if they were different.
+
+ for name, extension in file_desc.extensions_by_name.iteritems():
+ if extension.containing_type.full_name not in self._classes:
+ self.GetPrototype(extension.containing_type)
+ extended_class = self._classes[extension.containing_type.full_name]
+ extended_class.RegisterExtension(extension)
+ return result
+
+
+_FACTORY = MessageFactory()
+
+
+def GetMessages(file_protos):
+ """Builds a dictionary of all the messages available in a set of files.
+
+ Args:
+ file_protos: A sequence of file protos to build messages out of.
+
+ Returns:
+ A dictionary mapping proto names to the message classes. This will include
+ any dependent messages as well as any messages defined in the same file as
+ a specified message.
+ """
+ for file_proto in file_protos:
+ _FACTORY.pool.Add(file_proto)
+ return _FACTORY.GetMessages([file_proto.name for file_proto in file_protos])
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/README b/python/google/protobuf/pyext/README
new file mode 100644
index 00000000..6d61cb45
--- /dev/null
+++ b/python/google/protobuf/pyext/README
@@ -0,0 +1,6 @@
+This is the 'v2' C++ implementation for python proto2.
+
+It is active when:
+
+PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2
diff --git a/python/google/protobuf/pyext/__init__.py b/python/google/protobuf/pyext/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/python/google/protobuf/pyext/__init__.py
diff --git a/python/google/protobuf/pyext/cpp_message.py b/python/google/protobuf/pyext/cpp_message.py
new file mode 100644
index 00000000..037bb72c
--- /dev/null
+++ b/python/google/protobuf/pyext/cpp_message.py
@@ -0,0 +1,57 @@
+# 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.
+
+"""Protocol message implementation hooks for C++ implementation.
+
+Contains helper functions used to create protocol message classes from
+Descriptor objects at runtime backed by the protocol buffer C++ API.
+"""
+
+__author__ = 'tibell@google.com (Johan Tibell)'
+
+from google.protobuf.pyext import _message
+from google.protobuf import message
+
+
+def NewMessage(bases, message_descriptor, dictionary):
+ """Creates a new protocol message *class*."""
+ new_bases = []
+ for base in bases:
+ if base is message.Message:
+ # _message.Message must come before message.Message as it
+ # overrides methods in that class.
+ new_bases.append(_message.Message)
+ new_bases.append(base)
+ return tuple(new_bases)
+
+
+def InitMessage(message_descriptor, cls):
+ """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
new file mode 100644
index 00000000..e77d0bb9
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -0,0 +1,1471 @@
+// 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: petar@google.com (Petar Petrov)
+
+#include <Python.h>
+#include <frameobject.h>
+#include <string>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_containers.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#define C(str) const_cast<char*>(str)
+
+#if PY_MAJOR_VERSION >= 3
+ #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
+ #define PyString_Check PyUnicode_Check
+ #define PyString_InternFromString PyUnicode_InternFromString
+ #define PyInt_FromLong PyLong_FromLong
+ #define PyInt_FromSize_t PyLong_FromSize_t
+ #if PY_VERSION_HEX < 0x03030000
+ #error "Python 3.0 - 3.2 are not supported."
+ #endif
+ #define PyString_AsStringAndSize(ob, charpp, sizep) \
+ (PyUnicode_Check(ob)? \
+ ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
+ PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+PyObject* PyString_FromCppString(const string& str) {
+ return PyString_FromStringAndSize(str.c_str(), str.size());
+}
+
+// Check that the calling Python code is the global scope of a _pb2.py module.
+// This function is used to support the current code generated by the proto
+// compiler, which creates descriptors, then update some properties.
+// For example:
+// message_descriptor = Descriptor(
+// name='Message',
+// fields = [FieldDescriptor(name='field')]
+// message_descriptor.fields[0].containing_type = message_descriptor
+//
+// This code is still executed, but the descriptors now have no other storage
+// than the (const) C++ pointer, and are immutable.
+// So we let this code pass, by simply ignoring the new value.
+//
+// From user code, descriptors still look immutable.
+//
+// TODO(amauryfa): Change the proto2 compiler to remove the assignments, and
+// remove this hack.
+bool _CalledFromGeneratedFile(int stacklevel) {
+ PyThreadState *state = PyThreadState_GET();
+ if (state == NULL) {
+ return false;
+ }
+ PyFrameObject* frame = state->frame;
+ if (frame == NULL) {
+ return false;
+ }
+ while (stacklevel-- > 0) {
+ frame = frame->f_back;
+ if (frame == NULL) {
+ return false;
+ }
+ }
+ if (frame->f_globals != frame->f_locals) {
+ // Not at global module scope
+ return false;
+ }
+
+ if (frame->f_code->co_filename == NULL) {
+ return false;
+ }
+ char* filename;
+ Py_ssize_t filename_size;
+ if (PyString_AsStringAndSize(frame->f_code->co_filename,
+ &filename, &filename_size) < 0) {
+ // filename is not a string.
+ PyErr_Clear();
+ return false;
+ }
+ if (filename_size < 7) {
+ // filename is too short.
+ return false;
+ }
+ if (strcmp(&filename[filename_size - 7], "_pb2.py") != 0) {
+ // Filename is not ending with _pb2.
+ return false;
+ }
+ return true;
+}
+
+// If the calling code is not a _pb2.py file, raise AttributeError.
+// To be used in attribute setters.
+static int CheckCalledFromGeneratedFile(const char* attr_name) {
+ if (_CalledFromGeneratedFile(0)) {
+ return 0;
+ }
+ PyErr_Format(PyExc_AttributeError,
+ "attribute is not writable: %s", attr_name);
+ return -1;
+}
+
+
+#ifndef PyVarObject_HEAD_INIT
+#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
+#endif
+#ifndef Py_TYPE
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+
+
+// Helper functions for descriptor objects.
+
+// Converts options into a Python protobuf, and cache the result.
+//
+// This is a bit tricky because options can contain extension fields defined in
+// the same proto file. In this case the options parsed from the serialized_pb
+// have unkown fields, and we need to parse them again.
+//
+// Always returns a new reference.
+template<class DescriptorClass>
+static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
+ hash_map<const void*, PyObject*>* descriptor_options =
+ GetDescriptorPool()->descriptor_options;
+ // First search in the cache.
+ if (descriptor_options->find(descriptor) != descriptor_options->end()) {
+ PyObject *value = (*descriptor_options)[descriptor];
+ Py_INCREF(value);
+ return value;
+ }
+
+ // Build the Options object: get its Python class, and make a copy of the C++
+ // read-only instance.
+ const Message& options(descriptor->options());
+ const Descriptor *message_type = options.GetDescriptor();
+ PyObject* message_class(cdescriptor_pool::GetMessageClass(
+ GetDescriptorPool(), message_type));
+ if (message_class == NULL) {
+ PyErr_Format(PyExc_TypeError, "Could not retrieve class for Options: %s",
+ message_type->full_name().c_str());
+ return NULL;
+ }
+ ScopedPyObjectPtr value(PyEval_CallObject(message_class, NULL));
+ if (value == NULL) {
+ return NULL;
+ }
+ CMessage* cmsg = reinterpret_cast<CMessage*>(value.get());
+
+ const Reflection* reflection = options.GetReflection();
+ const UnknownFieldSet& unknown_fields(reflection->GetUnknownFields(options));
+ if (unknown_fields.empty()) {
+ cmsg->message->CopyFrom(options);
+ } else {
+ // Reparse options string! XXX call cmessage::MergeFromString
+ string serialized;
+ options.SerializeToString(&serialized);
+ io::CodedInputStream input(
+ reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
+ input.SetExtensionRegistry(GetDescriptorPool()->pool,
+ cmessage::GetMessageFactory());
+ bool success = cmsg->message->MergePartialFromCodedStream(&input);
+ if (!success) {
+ PyErr_Format(PyExc_ValueError, "Error parsing Options message");
+ return NULL;
+ }
+ }
+
+ // Cache the result.
+ Py_INCREF(value);
+ (*GetDescriptorPool()->descriptor_options)[descriptor] = value.get();
+
+ return value.release();
+}
+
+// Copy the C++ descriptor to a Python message.
+// The Python message is an instance of descriptor_pb2.DescriptorProto
+// or similar.
+template<class DescriptorProtoClass, class DescriptorClass>
+static PyObject* CopyToPythonProto(const DescriptorClass *descriptor,
+ PyObject *target) {
+ const Descriptor* self_descriptor =
+ DescriptorProtoClass::default_instance().GetDescriptor();
+ CMessage* message = reinterpret_cast<CMessage*>(target);
+ if (!PyObject_TypeCheck(target, &CMessage_Type) ||
+ message->message->GetDescriptor() != self_descriptor) {
+ PyErr_Format(PyExc_TypeError, "Not a %s message",
+ self_descriptor->full_name().c_str());
+ return NULL;
+ }
+ cmessage::AssureWritable(message);
+ DescriptorProtoClass* descriptor_message =
+ static_cast<DescriptorProtoClass*>(message->message);
+ descriptor->CopyTo(descriptor_message);
+ Py_RETURN_NONE;
+}
+
+// All Descriptors classes share the same memory layout.
+typedef struct PyBaseDescriptor {
+ PyObject_HEAD
+
+ // Pointer to the C++ proto2 descriptor.
+ // Like all descriptors, it is owned by the global DescriptorPool.
+ const void* descriptor;
+} PyBaseDescriptor;
+
+
+// FileDescriptor structure "inherits" from the base descriptor.
+typedef struct PyFileDescriptor {
+ PyBaseDescriptor base;
+
+ // The cached version of serialized pb. Either NULL, or a Bytes string.
+ // We own the reference.
+ PyObject *serialized_pb;
+} PyFileDescriptor;
+
+
+namespace descriptor {
+
+// Creates or retrieve a Python descriptor of the specified type.
+// Objects are interned: the same descriptor will return the same object if it
+// was kept alive.
+// Always return a new reference.
+PyObject* NewInternedDescriptor(PyTypeObject* type, const void* descriptor) {
+ if (descriptor == NULL) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ // See if the object is in the map of interned descriptors
+ hash_map<const void*, PyObject*>::iterator it =
+ GetDescriptorPool()->interned_descriptors->find(descriptor);
+ if (it != GetDescriptorPool()->interned_descriptors->end()) {
+ GOOGLE_DCHECK(Py_TYPE(it->second) == type);
+ Py_INCREF(it->second);
+ return it->second;
+ }
+ // Create a new descriptor object
+ PyBaseDescriptor* py_descriptor = PyObject_New(
+ PyBaseDescriptor, type);
+ if (py_descriptor == NULL) {
+ return NULL;
+ }
+ py_descriptor->descriptor = descriptor;
+ // and cache it.
+ GetDescriptorPool()->interned_descriptors->insert(
+ std::make_pair(descriptor, reinterpret_cast<PyObject*>(py_descriptor)));
+
+ return reinterpret_cast<PyObject*>(py_descriptor);
+}
+
+static void Dealloc(PyBaseDescriptor* self) {
+ // Remove from interned dictionary
+ GetDescriptorPool()->interned_descriptors->erase(self->descriptor);
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+static PyGetSetDef Getters[] = {
+ {NULL}
+};
+
+PyTypeObject PyBaseDescriptor_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ // Keep the fully qualified _message symbol in a line for opensource.
+ "google.protobuf.internal._message."
+ "DescriptorBase", // tp_name
+ sizeof(PyBaseDescriptor), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)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
+ "Descriptors base class", // 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
+ Getters, // tp_getset
+};
+
+} // namespace descriptor
+
+const void* PyDescriptor_AsVoidPtr(PyObject* obj) {
+ if (!PyObject_TypeCheck(obj, &descriptor::PyBaseDescriptor_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Not a BaseDescriptor");
+ return NULL;
+ }
+ return reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor;
+}
+
+namespace message_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const Descriptor* _GetDescriptor(PyBaseDescriptor* self) {
+ return reinterpret_cast<const Descriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
+ return PyFileDescriptor_New(_GetDescriptor(self)->file());
+}
+
+static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) {
+ PyObject* concrete_class(cdescriptor_pool::GetMessageClass(
+ GetDescriptorPool(), _GetDescriptor(self)));
+ Py_XINCREF(concrete_class);
+ return concrete_class;
+}
+
+static int SetConcreteClass(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ // This attribute is also set from reflection.py. Check that it's actually a
+ // no-op.
+ if (value != cdescriptor_pool::GetMessageClass(
+ GetDescriptorPool(), _GetDescriptor(self))) {
+ PyErr_SetString(PyExc_AttributeError, "Cannot change _concrete_class");
+ }
+ return 0;
+}
+
+static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) {
+ return NewMessageFieldsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetFieldsByNumber(PyBaseDescriptor* self, void *closure) {
+ return NewMessageFieldsByNumber(_GetDescriptor(self));
+}
+
+static PyObject* GetFieldsSeq(PyBaseDescriptor* self, void *closure) {
+ return NewMessageFieldsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetNestedTypesByName(PyBaseDescriptor* self, void *closure) {
+ return NewMessageNestedTypesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetNestedTypesSeq(PyBaseDescriptor* self, void *closure) {
+ return NewMessageNestedTypesSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetExtensionsByName(PyBaseDescriptor* self, void *closure) {
+ return NewMessageExtensionsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetExtensions(PyBaseDescriptor* self, void *closure) {
+ return NewMessageExtensionsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumsSeq(PyBaseDescriptor* self, void *closure) {
+ return NewMessageEnumsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumTypesByName(PyBaseDescriptor* self, void *closure) {
+ return NewMessageEnumsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumValuesByName(PyBaseDescriptor* self, void *closure) {
+ return NewMessageEnumValuesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetOneofsByName(PyBaseDescriptor* self, void *closure) {
+ return NewMessageOneofsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetOneofsSeq(PyBaseDescriptor* self, void *closure) {
+ return NewMessageOneofsSeq(_GetDescriptor(self));
+}
+
+static PyObject* IsExtendable(PyBaseDescriptor *self, void *closure) {
+ if (_GetDescriptor(self)->extension_range_count() > 0) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+static PyObject* GetExtensionRanges(PyBaseDescriptor *self, void *closure) {
+ const Descriptor* descriptor = _GetDescriptor(self);
+ PyObject* range_list = PyList_New(descriptor->extension_range_count());
+
+ for (int i = 0; i < descriptor->extension_range_count(); i++) {
+ const Descriptor::ExtensionRange* range = descriptor->extension_range(i);
+ PyObject* start = PyInt_FromLong(range->start);
+ PyObject* end = PyInt_FromLong(range->end);
+ PyList_SetItem(range_list, i, PyTuple_Pack(2, start, end));
+ }
+
+ return range_list;
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+ const Descriptor* containing_type =
+ _GetDescriptor(self)->containing_type();
+ if (containing_type) {
+ return PyMessageDescriptor_New(containing_type);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static int SetContainingType(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("containing_type");
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+ const MessageOptions& options(_GetDescriptor(self)->options());
+ if (&options != &MessageOptions::default_instance()) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+ return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("_options");
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+ return CopyToPythonProto<DescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyObject* EnumValueName(PyBaseDescriptor *self, PyObject *args) {
+ const char *enum_name;
+ int number;
+ if (!PyArg_ParseTuple(args, "si", &enum_name, &number))
+ return NULL;
+ const EnumDescriptor *enum_type =
+ _GetDescriptor(self)->FindEnumTypeByName(enum_name);
+ if (enum_type == NULL) {
+ PyErr_SetString(PyExc_KeyError, enum_name);
+ return NULL;
+ }
+ const EnumValueDescriptor *enum_value =
+ enum_type->FindValueByNumber(number);
+ if (enum_value == NULL) {
+ PyErr_Format(PyExc_KeyError, "%d", number);
+ return NULL;
+ }
+ return PyString_FromCppString(enum_value->name());
+}
+
+static PyObject* GetSyntax(PyBaseDescriptor *self, void *closure) {
+ return PyString_InternFromString(
+ FileDescriptor::SyntaxName(_GetDescriptor(self)->file()->syntax()));
+}
+
+static PyGetSetDef Getters[] = {
+ { C("name"), (getter)GetName, NULL, "Last name", NULL},
+ { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
+ { C("_concrete_class"), (getter)GetConcreteClass, (setter)SetConcreteClass, "concrete class", NULL},
+ { C("file"), (getter)GetFile, NULL, "File descriptor", NULL},
+
+ { C("fields"), (getter)GetFieldsSeq, NULL, "Fields sequence", NULL},
+ { C("fields_by_name"), (getter)GetFieldsByName, NULL, "Fields by name", NULL},
+ { C("fields_by_number"), (getter)GetFieldsByNumber, NULL, "Fields by number", NULL},
+ { C("nested_types"), (getter)GetNestedTypesSeq, NULL, "Nested types sequence", NULL},
+ { C("nested_types_by_name"), (getter)GetNestedTypesByName, NULL, "Nested types by name", NULL},
+ { C("extensions"), (getter)GetExtensions, NULL, "Extensions Sequence", NULL},
+ { C("extensions_by_name"), (getter)GetExtensionsByName, NULL, "Extensions by name", NULL},
+ { C("extension_ranges"), (getter)GetExtensionRanges, NULL, "Extension ranges", NULL},
+ { C("enum_types"), (getter)GetEnumsSeq, NULL, "Enum sequence", NULL},
+ { C("enum_types_by_name"), (getter)GetEnumTypesByName, NULL, "Enum types by name", NULL},
+ { C("enum_values_by_name"), (getter)GetEnumValuesByName, NULL, "Enum values by name", NULL},
+ { C("oneofs_by_name"), (getter)GetOneofsByName, NULL, "Oneofs by name", NULL},
+ { C("oneofs"), (getter)GetOneofsSeq, NULL, "Oneofs by name", NULL},
+ { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL},
+ { C("is_extendable"), (getter)IsExtendable, (setter)NULL, NULL, NULL},
+ { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
+ { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+ { C("syntax"), (getter)GetSyntax, (setter)NULL, "Syntax", NULL},
+ {NULL}
+};
+
+static PyMethodDef Methods[] = {
+ { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+ { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+ { "EnumValueName", (PyCFunction)EnumValueName, METH_VARARGS, },
+ {NULL}
+};
+
+} // namespace message_descriptor
+
+PyTypeObject PyMessageDescriptor_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ // Keep the fully qualified _message symbol in a line for opensource.
+ C("google.protobuf.internal._message."
+ "MessageDescriptor"), // tp_name
+ sizeof(PyBaseDescriptor), // tp_basicsize
+ 0, // tp_itemsize
+ 0, // 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
+ message_descriptor::Methods, // tp_methods
+ 0, // tp_members
+ message_descriptor::Getters, // tp_getset
+ &descriptor::PyBaseDescriptor_Type, // tp_base
+};
+
+PyObject* PyMessageDescriptor_New(
+ const Descriptor* message_descriptor) {
+ return descriptor::NewInternedDescriptor(
+ &PyMessageDescriptor_Type, message_descriptor);
+}
+
+const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj) {
+ if (!PyObject_TypeCheck(obj, &PyMessageDescriptor_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Not a MessageDescriptor");
+ return NULL;
+ }
+ return reinterpret_cast<const Descriptor*>(
+ reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace field_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const FieldDescriptor* _GetDescriptor(
+ PyBaseDescriptor *self) {
+ return reinterpret_cast<const FieldDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->type());
+}
+
+static PyObject* GetCppType(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->cpp_type());
+}
+
+static PyObject* GetLabel(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->label());
+}
+
+static PyObject* GetNumber(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->number());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetID(PyBaseDescriptor *self, void *closure) {
+ return PyLong_FromVoidPtr(self);
+}
+
+static PyObject* IsExtension(PyBaseDescriptor *self, void *closure) {
+ return PyBool_FromLong(_GetDescriptor(self)->is_extension());
+}
+
+static PyObject* HasDefaultValue(PyBaseDescriptor *self, void *closure) {
+ return PyBool_FromLong(_GetDescriptor(self)->has_default_value());
+}
+
+static PyObject* GetDefaultValue(PyBaseDescriptor *self, void *closure) {
+ PyObject *result;
+
+ switch (_GetDescriptor(self)->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: {
+ int32 value = _GetDescriptor(self)->default_value_int32();
+ result = PyInt_FromLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_INT64: {
+ int64 value = _GetDescriptor(self)->default_value_int64();
+ result = PyLong_FromLongLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT32: {
+ uint32 value = _GetDescriptor(self)->default_value_uint32();
+ result = PyInt_FromSize_t(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ uint64 value = _GetDescriptor(self)->default_value_uint64();
+ result = PyLong_FromUnsignedLongLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ float value = _GetDescriptor(self)->default_value_float();
+ result = PyFloat_FromDouble(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ double value = _GetDescriptor(self)->default_value_double();
+ result = PyFloat_FromDouble(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_BOOL: {
+ bool value = _GetDescriptor(self)->default_value_bool();
+ result = PyBool_FromLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING: {
+ string value = _GetDescriptor(self)->default_value_string();
+ result = ToStringObject(_GetDescriptor(self), value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ const EnumValueDescriptor* value =
+ _GetDescriptor(self)->default_value_enum();
+ result = PyInt_FromLong(value->number());
+ break;
+ }
+ default:
+ PyErr_Format(PyExc_NotImplementedError, "default value for %s",
+ _GetDescriptor(self)->full_name().c_str());
+ return NULL;
+ }
+ return result;
+}
+
+static PyObject* GetCDescriptor(PyObject *self, void *closure) {
+ Py_INCREF(self);
+ return self;
+}
+
+static PyObject *GetEnumType(PyBaseDescriptor *self, void *closure) {
+ const EnumDescriptor* enum_type = _GetDescriptor(self)->enum_type();
+ if (enum_type) {
+ return PyEnumDescriptor_New(enum_type);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static int SetEnumType(PyBaseDescriptor *self, PyObject *value, void *closure) {
+ return CheckCalledFromGeneratedFile("enum_type");
+}
+
+static PyObject *GetMessageType(PyBaseDescriptor *self, void *closure) {
+ const Descriptor* message_type = _GetDescriptor(self)->message_type();
+ if (message_type) {
+ return PyMessageDescriptor_New(message_type);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static int SetMessageType(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("message_type");
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+ const Descriptor* containing_type =
+ _GetDescriptor(self)->containing_type();
+ if (containing_type) {
+ return PyMessageDescriptor_New(containing_type);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static int SetContainingType(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("containing_type");
+}
+
+static PyObject* GetExtensionScope(PyBaseDescriptor *self, void *closure) {
+ const Descriptor* extension_scope =
+ _GetDescriptor(self)->extension_scope();
+ if (extension_scope) {
+ return PyMessageDescriptor_New(extension_scope);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static PyObject* GetContainingOneof(PyBaseDescriptor *self, void *closure) {
+ const OneofDescriptor* containing_oneof =
+ _GetDescriptor(self)->containing_oneof();
+ if (containing_oneof) {
+ return PyOneofDescriptor_New(containing_oneof);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static int SetContainingOneof(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("containing_oneof");
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+ const FieldOptions& options(_GetDescriptor(self)->options());
+ if (&options != &FieldOptions::default_instance()) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+ return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("_options");
+}
+
+
+static PyGetSetDef Getters[] = {
+ { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
+ { C("name"), (getter)GetName, NULL, "Unqualified name", NULL},
+ { C("type"), (getter)GetType, NULL, "C++ Type", NULL},
+ { C("cpp_type"), (getter)GetCppType, NULL, "C++ Type", NULL},
+ { C("label"), (getter)GetLabel, NULL, "Label", NULL},
+ { C("number"), (getter)GetNumber, NULL, "Number", NULL},
+ { C("index"), (getter)GetIndex, NULL, "Index", NULL},
+ { C("default_value"), (getter)GetDefaultValue, NULL, "Default Value", NULL},
+ { C("has_default_value"), (getter)HasDefaultValue, NULL, NULL, NULL},
+ { C("is_extension"), (getter)IsExtension, NULL, "ID", NULL},
+ { C("id"), (getter)GetID, NULL, "ID", NULL},
+ { C("_cdescriptor"), (getter)GetCDescriptor, NULL, "HAACK REMOVE ME", NULL},
+
+ { C("message_type"), (getter)GetMessageType, (setter)SetMessageType, "Message type", NULL},
+ { C("enum_type"), (getter)GetEnumType, (setter)SetEnumType, "Enum type", NULL},
+ { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL},
+ { C("extension_scope"), (getter)GetExtensionScope, (setter)NULL, "Extension scope", NULL},
+ { C("containing_oneof"), (getter)GetContainingOneof, (setter)SetContainingOneof, "Containing oneof", NULL},
+ { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
+ { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+ {NULL}
+};
+
+static PyMethodDef Methods[] = {
+ { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+ {NULL}
+};
+
+} // namespace field_descriptor
+
+PyTypeObject PyFieldDescriptor_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ C("google.protobuf.internal."
+ "_message.FieldDescriptor"), // tp_name
+ sizeof(PyBaseDescriptor), // tp_basicsize
+ 0, // tp_itemsize
+ 0, // 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 Field Descriptor"), // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ field_descriptor::Methods, // tp_methods
+ 0, // tp_members
+ field_descriptor::Getters, // tp_getset
+ &descriptor::PyBaseDescriptor_Type, // tp_base
+};
+
+PyObject* PyFieldDescriptor_New(
+ const FieldDescriptor* field_descriptor) {
+ return descriptor::NewInternedDescriptor(
+ &PyFieldDescriptor_Type, field_descriptor);
+}
+
+const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj) {
+ if (!PyObject_TypeCheck(obj, &PyFieldDescriptor_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Not a FieldDescriptor");
+ return NULL;
+ }
+ return reinterpret_cast<const FieldDescriptor*>(
+ reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace enum_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const EnumDescriptor* _GetDescriptor(
+ PyBaseDescriptor *self) {
+ return reinterpret_cast<const EnumDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
+ return PyFileDescriptor_New(_GetDescriptor(self)->file());
+}
+
+static PyObject* GetEnumvaluesByName(PyBaseDescriptor* self, void *closure) {
+ return NewEnumValuesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumvaluesByNumber(PyBaseDescriptor* self, void *closure) {
+ return NewEnumValuesByNumber(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumvaluesSeq(PyBaseDescriptor* self, void *closure) {
+ return NewEnumValuesSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+ const Descriptor* containing_type =
+ _GetDescriptor(self)->containing_type();
+ if (containing_type) {
+ return PyMessageDescriptor_New(containing_type);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static int SetContainingType(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("containing_type");
+}
+
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+ const EnumOptions& options(_GetDescriptor(self)->options());
+ if (&options != &EnumOptions::default_instance()) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+ return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("_options");
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+ return CopyToPythonProto<EnumDescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyMethodDef Methods[] = {
+ { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+ { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+ {NULL}
+};
+
+static PyGetSetDef Getters[] = {
+ { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
+ { C("name"), (getter)GetName, NULL, "last name", NULL},
+ { C("file"), (getter)GetFile, NULL, "File descriptor", NULL},
+ { C("values"), (getter)GetEnumvaluesSeq, NULL, "values", NULL},
+ { C("values_by_name"), (getter)GetEnumvaluesByName, NULL, "Enumvalues by name", NULL},
+ { C("values_by_number"), (getter)GetEnumvaluesByNumber, NULL, "Enumvalues by number", NULL},
+
+ { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL},
+ { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
+ { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+ {NULL}
+};
+
+} // namespace enum_descriptor
+
+PyTypeObject PyEnumDescriptor_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ // Keep the fully qualified _message symbol in a line for opensource.
+ C("google.protobuf.internal._message."
+ "EnumDescriptor"), // tp_name
+ sizeof(PyBaseDescriptor), // tp_basicsize
+ 0, // tp_itemsize
+ 0, // 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 Enum Descriptor"), // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ enum_descriptor::Methods, // tp_getset
+ 0, // tp_members
+ enum_descriptor::Getters, // tp_getset
+ &descriptor::PyBaseDescriptor_Type, // tp_base
+};
+
+PyObject* PyEnumDescriptor_New(
+ const EnumDescriptor* enum_descriptor) {
+ return descriptor::NewInternedDescriptor(
+ &PyEnumDescriptor_Type, enum_descriptor);
+}
+
+namespace enumvalue_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const EnumValueDescriptor* _GetDescriptor(
+ PyBaseDescriptor *self) {
+ return reinterpret_cast<const EnumValueDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetNumber(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->number());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
+ return PyEnumDescriptor_New(_GetDescriptor(self)->type());
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+ const EnumValueOptions& options(_GetDescriptor(self)->options());
+ if (&options != &EnumValueOptions::default_instance()) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+ return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("_options");
+}
+
+
+static PyGetSetDef Getters[] = {
+ { C("name"), (getter)GetName, NULL, "name", NULL},
+ { C("number"), (getter)GetNumber, NULL, "number", NULL},
+ { C("index"), (getter)GetIndex, NULL, "index", NULL},
+ { C("type"), (getter)GetType, NULL, "index", NULL},
+
+ { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
+ { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+ {NULL}
+};
+
+static PyMethodDef Methods[] = {
+ { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+ {NULL}
+};
+
+} // namespace enumvalue_descriptor
+
+PyTypeObject PyEnumValueDescriptor_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ C("google.protobuf.internal."
+ "_message.EnumValueDescriptor"), // tp_name
+ sizeof(PyBaseDescriptor), // tp_basicsize
+ 0, // tp_itemsize
+ 0, // 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 EnumValue Descriptor"), // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ enumvalue_descriptor::Methods, // tp_methods
+ 0, // tp_members
+ enumvalue_descriptor::Getters, // tp_getset
+ &descriptor::PyBaseDescriptor_Type, // tp_base
+};
+
+PyObject* PyEnumValueDescriptor_New(
+ const EnumValueDescriptor* enumvalue_descriptor) {
+ return descriptor::NewInternedDescriptor(
+ &PyEnumValueDescriptor_Type, enumvalue_descriptor);
+}
+
+namespace file_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const FileDescriptor* _GetDescriptor(PyFileDescriptor *self) {
+ return reinterpret_cast<const FileDescriptor*>(self->base.descriptor);
+}
+
+static void Dealloc(PyFileDescriptor* self) {
+ Py_XDECREF(self->serialized_pb);
+ descriptor::Dealloc(&self->base);
+}
+
+static PyObject* GetName(PyFileDescriptor *self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetPackage(PyFileDescriptor *self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->package());
+}
+
+static PyObject* GetSerializedPb(PyFileDescriptor *self, void *closure) {
+ PyObject *serialized_pb = self->serialized_pb;
+ if (serialized_pb != NULL) {
+ Py_INCREF(serialized_pb);
+ return serialized_pb;
+ }
+ FileDescriptorProto file_proto;
+ _GetDescriptor(self)->CopyTo(&file_proto);
+ string contents;
+ file_proto.SerializePartialToString(&contents);
+ self->serialized_pb = PyBytes_FromStringAndSize(
+ contents.c_str(), contents.size());
+ if (self->serialized_pb == NULL) {
+ return NULL;
+ }
+ Py_INCREF(self->serialized_pb);
+ return self->serialized_pb;
+}
+
+static PyObject* GetMessageTypesByName(PyFileDescriptor* self, void *closure) {
+ return NewFileMessageTypesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumTypesByName(PyFileDescriptor* self, void *closure) {
+ return NewFileEnumTypesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetExtensionsByName(PyFileDescriptor* self, void *closure) {
+ return NewFileExtensionsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetDependencies(PyFileDescriptor* self, void *closure) {
+ return NewFileDependencies(_GetDescriptor(self));
+}
+
+static PyObject* GetPublicDependencies(PyFileDescriptor* self, void *closure) {
+ return NewFilePublicDependencies(_GetDescriptor(self));
+}
+
+static PyObject* GetHasOptions(PyFileDescriptor *self, void *closure) {
+ const FileOptions& options(_GetDescriptor(self)->options());
+ if (&options != &FileOptions::default_instance()) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+static int SetHasOptions(PyFileDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyFileDescriptor *self) {
+ return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyFileDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("_options");
+}
+
+static PyObject* GetSyntax(PyFileDescriptor *self, void *closure) {
+ return PyString_InternFromString(
+ FileDescriptor::SyntaxName(_GetDescriptor(self)->syntax()));
+}
+
+static PyObject* CopyToProto(PyFileDescriptor *self, PyObject *target) {
+ return CopyToPythonProto<FileDescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyGetSetDef Getters[] = {
+ { C("name"), (getter)GetName, NULL, "name", NULL},
+ { C("package"), (getter)GetPackage, NULL, "package", NULL},
+ { C("serialized_pb"), (getter)GetSerializedPb, NULL, NULL, NULL},
+ { C("message_types_by_name"), (getter)GetMessageTypesByName, NULL, "Messages by name", NULL},
+ { C("enum_types_by_name"), (getter)GetEnumTypesByName, NULL, "Enums by name", NULL},
+ { C("extensions_by_name"), (getter)GetExtensionsByName, NULL, "Extensions by name", NULL},
+ { C("dependencies"), (getter)GetDependencies, NULL, "Dependencies", NULL},
+ { C("public_dependencies"), (getter)GetPublicDependencies, NULL, "Dependencies", NULL},
+
+ { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
+ { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+ { C("syntax"), (getter)GetSyntax, (setter)NULL, "Syntax", NULL},
+ {NULL}
+};
+
+static PyMethodDef Methods[] = {
+ { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+ { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+ {NULL}
+};
+
+} // namespace file_descriptor
+
+PyTypeObject PyFileDescriptor_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ C("google.protobuf.internal."
+ "_message.FileDescriptor"), // tp_name
+ sizeof(PyFileDescriptor), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)file_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 File Descriptor"), // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ file_descriptor::Methods, // tp_methods
+ 0, // tp_members
+ file_descriptor::Getters, // tp_getset
+ &descriptor::PyBaseDescriptor_Type, // 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
+};
+
+PyObject* PyFileDescriptor_New(const FileDescriptor* file_descriptor) {
+ return descriptor::NewInternedDescriptor(
+ &PyFileDescriptor_Type, file_descriptor);
+}
+
+PyObject* PyFileDescriptor_NewWithPb(
+ const FileDescriptor* file_descriptor, PyObject *serialized_pb) {
+ PyObject* py_descriptor = PyFileDescriptor_New(file_descriptor);
+ if (py_descriptor == NULL) {
+ return NULL;
+ }
+ if (serialized_pb != NULL) {
+ PyFileDescriptor* cfile_descriptor =
+ reinterpret_cast<PyFileDescriptor*>(py_descriptor);
+ Py_XINCREF(serialized_pb);
+ cfile_descriptor->serialized_pb = serialized_pb;
+ }
+
+ return py_descriptor;
+}
+
+namespace oneof_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const OneofDescriptor* _GetDescriptor(
+ PyBaseDescriptor *self) {
+ return reinterpret_cast<const OneofDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetFields(PyBaseDescriptor* self, void *closure) {
+ return NewOneofFieldsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+ const Descriptor* containing_type =
+ _GetDescriptor(self)->containing_type();
+ if (containing_type) {
+ return PyMessageDescriptor_New(containing_type);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static PyGetSetDef Getters[] = {
+ { C("name"), (getter)GetName, NULL, "Name", NULL},
+ { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
+ { C("index"), (getter)GetIndex, NULL, "Index", NULL},
+
+ { C("containing_type"), (getter)GetContainingType, NULL, "Containing type", NULL},
+ { C("fields"), (getter)GetFields, NULL, "Fields", NULL},
+ {NULL}
+};
+
+} // namespace oneof_descriptor
+
+PyTypeObject PyOneofDescriptor_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ C("google.protobuf.internal."
+ "_message.OneofDescriptor"), // tp_name
+ sizeof(PyBaseDescriptor), // tp_basicsize
+ 0, // tp_itemsize
+ 0, // 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 Oneof 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
+ oneof_descriptor::Getters, // tp_getset
+ &descriptor::PyBaseDescriptor_Type, // tp_base
+};
+
+PyObject* PyOneofDescriptor_New(
+ const OneofDescriptor* oneof_descriptor) {
+ return descriptor::NewInternedDescriptor(
+ &PyOneofDescriptor_Type, oneof_descriptor);
+}
+
+// Add a enum values to a type dictionary.
+static bool AddEnumValues(PyTypeObject *type,
+ const EnumDescriptor* enum_descriptor) {
+ for (int i = 0; i < enum_descriptor->value_count(); ++i) {
+ const EnumValueDescriptor* value = enum_descriptor->value(i);
+ ScopedPyObjectPtr obj(PyInt_FromLong(value->number()));
+ if (obj == NULL) {
+ return false;
+ }
+ if (PyDict_SetItemString(type->tp_dict, value->name().c_str(), obj) < 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool AddIntConstant(PyTypeObject *type, const char* name, int value) {
+ ScopedPyObjectPtr obj(PyInt_FromLong(value));
+ if (PyDict_SetItemString(type->tp_dict, name, obj) < 0) {
+ return false;
+ }
+ return true;
+}
+
+
+bool InitDescriptor() {
+ if (PyType_Ready(&PyMessageDescriptor_Type) < 0)
+ return false;
+
+ if (PyType_Ready(&PyFieldDescriptor_Type) < 0)
+ return false;
+
+ if (!AddEnumValues(&PyFieldDescriptor_Type,
+ FieldDescriptorProto::Label_descriptor())) {
+ return false;
+ }
+ if (!AddEnumValues(&PyFieldDescriptor_Type,
+ FieldDescriptorProto::Type_descriptor())) {
+ return false;
+ }
+#define ADD_FIELDDESC_CONSTANT(NAME) AddIntConstant( \
+ &PyFieldDescriptor_Type, #NAME, FieldDescriptor::NAME)
+ if (!ADD_FIELDDESC_CONSTANT(CPPTYPE_INT32) ||
+ !ADD_FIELDDESC_CONSTANT(CPPTYPE_INT64) ||
+ !ADD_FIELDDESC_CONSTANT(CPPTYPE_UINT32) ||
+ !ADD_FIELDDESC_CONSTANT(CPPTYPE_UINT64) ||
+ !ADD_FIELDDESC_CONSTANT(CPPTYPE_DOUBLE) ||
+ !ADD_FIELDDESC_CONSTANT(CPPTYPE_FLOAT) ||
+ !ADD_FIELDDESC_CONSTANT(CPPTYPE_BOOL) ||
+ !ADD_FIELDDESC_CONSTANT(CPPTYPE_ENUM) ||
+ !ADD_FIELDDESC_CONSTANT(CPPTYPE_STRING) ||
+ !ADD_FIELDDESC_CONSTANT(CPPTYPE_MESSAGE)) {
+ return false;
+ }
+#undef ADD_FIELDDESC_CONSTANT
+
+ if (PyType_Ready(&PyEnumDescriptor_Type) < 0)
+ return false;
+
+ if (PyType_Ready(&PyEnumValueDescriptor_Type) < 0)
+ return false;
+
+ if (PyType_Ready(&PyFileDescriptor_Type) < 0)
+ return false;
+
+ if (PyType_Ready(&PyOneofDescriptor_Type) < 0)
+ return false;
+
+ if (!InitDescriptorMappingTypes())
+ return false;
+
+ return true;
+}
+
+} // namespace python
+} // namespace protobuf
+} // namespace google
diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h
new file mode 100644
index 00000000..ba6e7298
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor.h
@@ -0,0 +1,92 @@
+// 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: petar@google.com (Petar Petrov)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__
+
+#include <Python.h>
+
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+extern PyTypeObject PyMessageDescriptor_Type;
+extern PyTypeObject PyFieldDescriptor_Type;
+extern PyTypeObject PyEnumDescriptor_Type;
+extern PyTypeObject PyEnumValueDescriptor_Type;
+extern PyTypeObject PyFileDescriptor_Type;
+extern PyTypeObject PyOneofDescriptor_Type;
+
+// Return a new reference to a Descriptor object.
+// The C++ pointer is usually borrowed from the global DescriptorPool.
+// In any case, it must stay alive as long as the Python object.
+PyObject* PyMessageDescriptor_New(const Descriptor* descriptor);
+PyObject* PyFieldDescriptor_New(const FieldDescriptor* descriptor);
+PyObject* PyEnumDescriptor_New(const EnumDescriptor* descriptor);
+PyObject* PyEnumValueDescriptor_New(const EnumValueDescriptor* descriptor);
+PyObject* PyOneofDescriptor_New(const OneofDescriptor* descriptor);
+PyObject* PyFileDescriptor_New(const FileDescriptor* file_descriptor);
+
+// Alternate constructor of PyFileDescriptor, used when we already have a
+// serialized FileDescriptorProto that can be cached.
+// Returns a new reference.
+PyObject* PyFileDescriptor_NewWithPb(const FileDescriptor* file_descriptor,
+ PyObject* serialized_pb);
+
+// Return the C++ descriptor pointer.
+// This function checks the parameter type; on error, return NULL with a Python
+// exception set.
+const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj);
+const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj);
+
+// Returns the raw C++ pointer.
+const void* PyDescriptor_AsVoidPtr(PyObject* obj);
+
+// Check that the calling Python code is the global scope of a _pb2.py module.
+// This function is used to support the current code generated by the proto
+// compiler, which insists on modifying descriptors after they have been
+// created.
+//
+// stacklevel indicates which Python frame should be the _pb2.py module.
+//
+// Don't use this function outside descriptor classes.
+bool _CalledFromGeneratedFile(int stacklevel);
+
+bool InitDescriptor();
+
+} // namespace python
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
new file mode 100644
index 00000000..06edebf8
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -0,0 +1,1564 @@
+// 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.
+
+// Mappings and Sequences of descriptors.
+// Used by Descriptor.fields_by_name, EnumDescriptor.values...
+//
+// They avoid the allocation of a full dictionary or a full list: they simply
+// store a pointer to the parent descriptor, use the C++ Descriptor methods (see
+// google/protobuf/descriptor.h) to retrieve other descriptors, and create
+// Python objects on the fly.
+//
+// The containers fully conform to abc.Mapping and abc.Sequence, and behave just
+// like read-only dictionaries and lists.
+//
+// Because the interface of C++ Descriptors is quite regular, this file actually
+// defines only three types, the exact behavior of a container is controlled by
+// a DescriptorContainerDef structure, which contains functions that uses the
+// public Descriptor API.
+//
+// Note: This DescriptorContainerDef is similar to the "virtual methods table"
+// that a C++ compiler generates for a class. We have to make it explicit
+// because the Python API is based on C, and does not play well with C++
+// inheritance.
+
+#include <Python.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/pyext/descriptor_containers.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#if PY_MAJOR_VERSION >= 3
+ #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
+ #define PyString_FromFormat PyUnicode_FromFormat
+ #define PyInt_FromLong PyLong_FromLong
+ #if PY_VERSION_HEX < 0x03030000
+ #error "Python 3.0 - 3.2 are not supported."
+ #endif
+ #define PyString_AsStringAndSize(ob, charpp, sizep) \
+ (PyUnicode_Check(ob)? \
+ ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
+ PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+struct PyContainer;
+
+typedef int (*CountMethod)(PyContainer* self);
+typedef const void* (*GetByIndexMethod)(PyContainer* self, int index);
+typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name);
+typedef const void* (*GetByNumberMethod)(PyContainer* self, int index);
+typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor);
+typedef const string& (*GetItemNameMethod)(const void* descriptor);
+typedef int (*GetItemNumberMethod)(const void* descriptor);
+typedef int (*GetItemIndexMethod)(const void* descriptor);
+
+struct DescriptorContainerDef {
+ const char* mapping_name;
+ // Returns the number of items in the container.
+ CountMethod count_fn;
+ // Retrieve item by index (usually the order of declaration in the proto file)
+ // Used by sequences, but also iterators. 0 <= index < Count().
+ GetByIndexMethod get_by_index_fn;
+ // Retrieve item by name (usually a call to some 'FindByName' method).
+ // Used by "by_name" mappings.
+ GetByNameMethod get_by_name_fn;
+ // Retrieve item by declared number (field tag, or enum value).
+ // Used by "by_number" mappings.
+ GetByNumberMethod get_by_number_fn;
+ // Converts a item C++ descriptor to a Python object. Returns a new reference.
+ NewObjectFromItemMethod new_object_from_item_fn;
+ // Retrieve the name of an item. Used by iterators on "by_name" mappings.
+ GetItemNameMethod get_item_name_fn;
+ // Retrieve the number of an item. Used by iterators on "by_number" mappings.
+ GetItemNumberMethod get_item_number_fn;
+ // Retrieve the index of an item for the container type.
+ // Used by "__contains__".
+ // If not set, "x in sequence" will do a linear search.
+ GetItemIndexMethod get_item_index_fn;
+};
+
+struct PyContainer {
+ PyObject_HEAD
+
+ // The proto2 descriptor this container belongs to the global DescriptorPool.
+ const void* descriptor;
+
+ // A pointer to a static structure with function pointers that control the
+ // behavior of the container. Very similar to the table of virtual functions
+ // of a C++ class.
+ const DescriptorContainerDef* container_def;
+
+ // The kind of container: list, or dict by name or value.
+ enum ContainerKind {
+ KIND_SEQUENCE,
+ KIND_BYNAME,
+ KIND_BYNUMBER,
+ } kind;
+};
+
+struct PyContainerIterator {
+ PyObject_HEAD
+
+ // The container we are iterating over. Own a reference.
+ PyContainer* container;
+
+ // The current index in the iterator.
+ int index;
+
+ // The kind of container: list, or dict by name or value.
+ enum IterKind {
+ KIND_ITERKEY,
+ KIND_ITERVALUE,
+ KIND_ITERITEM,
+ KIND_ITERVALUE_REVERSED, // For sequences
+ } kind;
+};
+
+namespace descriptor {
+
+// Returns the C++ item descriptor for a given Python key.
+// When the descriptor is found, return true and set *item.
+// When the descriptor is not found, return true, but set *item to NULL.
+// On error, returns false with an exception set.
+static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) {
+ switch (self->kind) {
+ case PyContainer::KIND_BYNAME:
+ {
+ char* name;
+ Py_ssize_t name_size;
+ if (PyString_AsStringAndSize(key, &name, &name_size) < 0) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ // Not a string, cannot be in the container.
+ PyErr_Clear();
+ *item = NULL;
+ return true;
+ }
+ return false;
+ }
+ *item = self->container_def->get_by_name_fn(
+ self, string(name, name_size));
+ return true;
+ }
+ case PyContainer::KIND_BYNUMBER:
+ {
+ Py_ssize_t number = PyNumber_AsSsize_t(key, NULL);
+ if (number == -1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ // Not a number, cannot be in the container.
+ PyErr_Clear();
+ *item = NULL;
+ return true;
+ }
+ return false;
+ }
+ *item = self->container_def->get_by_number_fn(self, number);
+ return true;
+ }
+ default:
+ PyErr_SetNone(PyExc_NotImplementedError);
+ return false;
+ }
+}
+
+// Returns the key of the object at the given index.
+// Used when iterating over mappings.
+static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) {
+ const void* item = self->container_def->get_by_index_fn(self, index);
+ switch (self->kind) {
+ case PyContainer::KIND_BYNAME:
+ {
+ const string& name(self->container_def->get_item_name_fn(item));
+ return PyString_FromStringAndSize(name.c_str(), name.size());
+ }
+ case PyContainer::KIND_BYNUMBER:
+ {
+ int value = self->container_def->get_item_number_fn(item);
+ return PyInt_FromLong(value);
+ }
+ default:
+ PyErr_SetNone(PyExc_NotImplementedError);
+ return NULL;
+ }
+}
+
+// Returns the object at the given index.
+// Also used when iterating over mappings.
+static PyObject* _NewObj_ByIndex(PyContainer* self, Py_ssize_t index) {
+ return self->container_def->new_object_from_item_fn(
+ self->container_def->get_by_index_fn(self, index));
+}
+
+static Py_ssize_t Length(PyContainer* self) {
+ return self->container_def->count_fn(self);
+}
+
+// The DescriptorMapping type.
+
+static PyObject* Subscript(PyContainer* self, PyObject* key) {
+ const void* item = NULL;
+ if (!_GetItemByKey(self, key, &item)) {
+ return NULL;
+ }
+ if (!item) {
+ PyErr_SetObject(PyExc_KeyError, key);
+ return NULL;
+ }
+ return self->container_def->new_object_from_item_fn(item);
+}
+
+static int AssSubscript(PyContainer* self, PyObject* key, PyObject* value) {
+ if (_CalledFromGeneratedFile(0)) {
+ return 0;
+ }
+ PyErr_Format(PyExc_TypeError,
+ "'%.200s' object does not support item assignment",
+ Py_TYPE(self)->tp_name);
+ return -1;
+}
+
+static PyMappingMethods MappingMappingMethods = {
+ (lenfunc)Length, // mp_length
+ (binaryfunc)Subscript, // mp_subscript
+ (objobjargproc)AssSubscript, // mp_ass_subscript
+};
+
+static int Contains(PyContainer* self, PyObject* key) {
+ const void* item = NULL;
+ if (!_GetItemByKey(self, key, &item)) {
+ return -1;
+ }
+ if (item) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static PyObject* ContainerRepr(PyContainer* self) {
+ const char* kind = "";
+ switch (self->kind) {
+ case PyContainer::KIND_SEQUENCE:
+ kind = "sequence";
+ break;
+ case PyContainer::KIND_BYNAME:
+ kind = "mapping by name";
+ break;
+ case PyContainer::KIND_BYNUMBER:
+ kind = "mapping by number";
+ break;
+ }
+ return PyString_FromFormat(
+ "<%s %s>", self->container_def->mapping_name, kind);
+}
+
+extern PyTypeObject DescriptorMapping_Type;
+extern PyTypeObject DescriptorSequence_Type;
+
+// A sequence container can only be equal to another sequence container, or (for
+// backward compatibility) to a list containing the same items.
+// Returns 1 if equal, 0 if unequal, -1 on error.
+static int DescriptorSequence_Equal(PyContainer* self, PyObject* other) {
+ // Check the identity of C++ pointers.
+ if (PyObject_TypeCheck(other, &DescriptorSequence_Type)) {
+ PyContainer* other_container = reinterpret_cast<PyContainer*>(other);
+ if (self->descriptor == other_container->descriptor &&
+ self->container_def == other_container->container_def &&
+ self->kind == other_container->kind) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ // If other is a list
+ if (PyList_Check(other)) {
+ // return list(self) == other
+ int size = Length(self);
+ if (size != PyList_Size(other)) {
+ return false;
+ }
+ for (int index = 0; index < size; index++) {
+ ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
+ if (value1 == NULL) {
+ return -1;
+ }
+ PyObject* value2 = PyList_GetItem(other, index);
+ if (value2 == NULL) {
+ return -1;
+ }
+ int cmp = PyObject_RichCompareBool(value1, value2, Py_EQ);
+ if (cmp != 1) // error or not equal
+ return cmp;
+ }
+ // All items were found and equal
+ return 1;
+ }
+
+ // Any other object is different.
+ return 0;
+}
+
+// A mapping container can only be equal to another mapping container, or (for
+// backward compatibility) to a dict containing the same items.
+// Returns 1 if equal, 0 if unequal, -1 on error.
+static int DescriptorMapping_Equal(PyContainer* self, PyObject* other) {
+ // Check the identity of C++ pointers.
+ if (PyObject_TypeCheck(other, &DescriptorMapping_Type)) {
+ PyContainer* other_container = reinterpret_cast<PyContainer*>(other);
+ if (self->descriptor == other_container->descriptor &&
+ self->container_def == other_container->container_def &&
+ self->kind == other_container->kind) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ // If other is a dict
+ if (PyDict_Check(other)) {
+ // equivalent to dict(self.items()) == other
+ int size = Length(self);
+ if (size != PyDict_Size(other)) {
+ return false;
+ }
+ for (int index = 0; index < size; index++) {
+ ScopedPyObjectPtr key(_NewKey_ByIndex(self, index));
+ if (key == NULL) {
+ return -1;
+ }
+ ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
+ if (value1 == NULL) {
+ return -1;
+ }
+ PyObject* value2 = PyDict_GetItem(other, key);
+ if (value2 == NULL) {
+ // Not found in the other dictionary
+ return 0;
+ }
+ int cmp = PyObject_RichCompareBool(value1, value2, Py_EQ);
+ if (cmp != 1) // error or not equal
+ return cmp;
+ }
+ // All items were found and equal
+ return 1;
+ }
+
+ // Any other object is different.
+ return 0;
+}
+
+static PyObject* RichCompare(PyContainer* self, PyObject* other, int opid) {
+ if (opid != Py_EQ && opid != Py_NE) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ int result;
+
+ if (self->kind == PyContainer::KIND_SEQUENCE) {
+ result = DescriptorSequence_Equal(self, other);
+ } else {
+ result = DescriptorMapping_Equal(self, other);
+ }
+ if (result < 0) {
+ return NULL;
+ }
+ if (result ^ (opid == Py_NE)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+static PySequenceMethods MappingSequenceMethods = {
+ 0, // sq_length
+ 0, // sq_concat
+ 0, // sq_repeat
+ 0, // sq_item
+ 0, // sq_slice
+ 0, // sq_ass_item
+ 0, // sq_ass_slice
+ (objobjproc)Contains, // sq_contains
+};
+
+static PyObject* Get(PyContainer* self, PyObject* args) {
+ PyObject* key;
+ PyObject* default_value = Py_None;
+ if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) {
+ return NULL;
+ }
+
+ const void* item;
+ if (!_GetItemByKey(self, key, &item)) {
+ return NULL;
+ }
+ if (item == NULL) {
+ Py_INCREF(default_value);
+ return default_value;
+ }
+ return self->container_def->new_object_from_item_fn(item);
+}
+
+static PyObject* Keys(PyContainer* self, PyObject* args) {
+ Py_ssize_t count = Length(self);
+ ScopedPyObjectPtr list(PyList_New(count));
+ if (list == NULL) {
+ return NULL;
+ }
+ for (Py_ssize_t index = 0; index < count; ++index) {
+ PyObject* key = _NewKey_ByIndex(self, index);
+ if (key == NULL) {
+ return NULL;
+ }
+ PyList_SET_ITEM(list.get(), index, key);
+ }
+ return list.release();
+}
+
+static PyObject* Values(PyContainer* self, PyObject* args) {
+ Py_ssize_t count = Length(self);
+ ScopedPyObjectPtr list(PyList_New(count));
+ if (list == NULL) {
+ return NULL;
+ }
+ for (Py_ssize_t index = 0; index < count; ++index) {
+ PyObject* value = _NewObj_ByIndex(self, index);
+ if (value == NULL) {
+ return NULL;
+ }
+ PyList_SET_ITEM(list.get(), index, value);
+ }
+ return list.release();
+}
+
+static PyObject* Items(PyContainer* self, PyObject* args) {
+ Py_ssize_t count = Length(self);
+ ScopedPyObjectPtr list(PyList_New(count));
+ if (list == NULL) {
+ return NULL;
+ }
+ for (Py_ssize_t index = 0; index < count; ++index) {
+ ScopedPyObjectPtr obj(PyTuple_New(2));
+ if (obj == NULL) {
+ return NULL;
+ }
+ PyObject* key = _NewKey_ByIndex(self, index);
+ if (key == NULL) {
+ return NULL;
+ }
+ PyTuple_SET_ITEM(obj.get(), 0, key);
+ PyObject* value = _NewObj_ByIndex(self, index);
+ if (value == NULL) {
+ return NULL;
+ }
+ PyTuple_SET_ITEM(obj.get(), 1, value);
+ PyList_SET_ITEM(list.get(), index, obj.release());
+ }
+ return list.release();
+}
+
+static PyObject* NewContainerIterator(PyContainer* mapping,
+ PyContainerIterator::IterKind kind);
+
+static PyObject* Iter(PyContainer* self) {
+ return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY);
+}
+static PyObject* IterKeys(PyContainer* self, PyObject* args) {
+ return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY);
+}
+static PyObject* IterValues(PyContainer* self, PyObject* args) {
+ return NewContainerIterator(self, PyContainerIterator::KIND_ITERVALUE);
+}
+static PyObject* IterItems(PyContainer* self, PyObject* args) {
+ return NewContainerIterator(self, PyContainerIterator::KIND_ITERITEM);
+}
+
+static PyMethodDef MappingMethods[] = {
+ { "get", (PyCFunction)Get, METH_VARARGS, },
+ { "keys", (PyCFunction)Keys, METH_NOARGS, },
+ { "values", (PyCFunction)Values, METH_NOARGS, },
+ { "items", (PyCFunction)Items, METH_NOARGS, },
+ { "iterkeys", (PyCFunction)IterKeys, METH_NOARGS, },
+ { "itervalues", (PyCFunction)IterValues, METH_NOARGS, },
+ { "iteritems", (PyCFunction)IterItems, METH_NOARGS, },
+ {NULL}
+};
+
+PyTypeObject DescriptorMapping_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "DescriptorMapping", // tp_name
+ sizeof(PyContainer), // tp_basicsize
+ 0, // tp_itemsize
+ 0, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ (reprfunc)ContainerRepr, // tp_repr
+ 0, // tp_as_number
+ &MappingSequenceMethods, // tp_as_sequence
+ &MappingMappingMethods, // 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
+ 0, // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ (richcmpfunc)RichCompare, // tp_richcompare
+ 0, // tp_weaklistoffset
+ (getiterfunc)Iter, // tp_iter
+ 0, // tp_iternext
+ MappingMethods, // tp_methods
+ 0, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ 0, // tp_init
+ 0, // tp_alloc
+ 0, // tp_new
+ 0, // tp_free
+};
+
+// The DescriptorSequence type.
+
+static PyObject* GetItem(PyContainer* self, Py_ssize_t index) {
+ if (index < 0) {
+ index += Length(self);
+ }
+ if (index < 0 || index >= Length(self)) {
+ PyErr_SetString(PyExc_IndexError, "index out of range");
+ return NULL;
+ }
+ return _NewObj_ByIndex(self, index);
+}
+
+// Returns the position of the item in the sequence, of -1 if not found.
+// This function never fails.
+int Find(PyContainer* self, PyObject* item) {
+ // The item can only be in one position: item.index.
+ // Check that self[item.index] == item, it's faster than a linear search.
+ //
+ // This assumes that sequences are only defined by syntax of the .proto file:
+ // a specific item belongs to only one sequence, depending on its position in
+ // the .proto file definition.
+ const void* descriptor_ptr = PyDescriptor_AsVoidPtr(item);
+ if (descriptor_ptr == NULL) {
+ // Not a descriptor, it cannot be in the list.
+ return -1;
+ }
+ if (self->container_def->get_item_index_fn) {
+ int index = self->container_def->get_item_index_fn(descriptor_ptr);
+ if (index < 0 || index >= Length(self)) {
+ // This index is not from this collection.
+ return -1;
+ }
+ if (self->container_def->get_by_index_fn(self, index) != descriptor_ptr) {
+ // The descriptor at this index is not the same.
+ return -1;
+ }
+ // self[item.index] == item, so return the index.
+ return index;
+ } else {
+ // Fall back to linear search.
+ int length = Length(self);
+ for (int index=0; index < length; index++) {
+ if (self->container_def->get_by_index_fn(self, index) == descriptor_ptr) {
+ return index;
+ }
+ }
+ // Not found
+ return -1;
+ }
+}
+
+// Implements list.index(): the position of the item is in the sequence.
+static PyObject* Index(PyContainer* self, PyObject* item) {
+ int position = Find(self, item);
+ if (position < 0) {
+ // Not found
+ PyErr_SetNone(PyExc_ValueError);
+ return NULL;
+ } else {
+ return PyInt_FromLong(position);
+ }
+}
+// Implements "list.__contains__()": is the object in the sequence.
+static int SeqContains(PyContainer* self, PyObject* item) {
+ int position = Find(self, item);
+ if (position < 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+// Implements list.count(): number of occurrences of the item in the sequence.
+// An item can only appear once in a sequence. If it exists, return 1.
+static PyObject* Count(PyContainer* self, PyObject* item) {
+ int position = Find(self, item);
+ if (position < 0) {
+ return PyInt_FromLong(0);
+ } else {
+ return PyInt_FromLong(1);
+ }
+}
+
+static PyObject* Append(PyContainer* self, PyObject* args) {
+ if (_CalledFromGeneratedFile(0)) {
+ Py_RETURN_NONE;
+ }
+ PyErr_Format(PyExc_TypeError,
+ "'%.200s' object is not a mutable sequence",
+ Py_TYPE(self)->tp_name);
+ return NULL;
+}
+
+static PyObject* Reversed(PyContainer* self, PyObject* args) {
+ return NewContainerIterator(self,
+ PyContainerIterator::KIND_ITERVALUE_REVERSED);
+}
+
+static PyMethodDef SeqMethods[] = {
+ { "index", (PyCFunction)Index, METH_O, },
+ { "count", (PyCFunction)Count, METH_O, },
+ { "append", (PyCFunction)Append, METH_O, },
+ { "__reversed__", (PyCFunction)Reversed, METH_NOARGS, },
+ {NULL}
+};
+
+static PySequenceMethods SeqSequenceMethods = {
+ (lenfunc)Length, // sq_length
+ 0, // sq_concat
+ 0, // sq_repeat
+ (ssizeargfunc)GetItem, // sq_item
+ 0, // sq_slice
+ 0, // sq_ass_item
+ 0, // sq_ass_slice
+ (objobjproc)SeqContains, // sq_contains
+};
+
+PyTypeObject DescriptorSequence_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "DescriptorSequence", // tp_name
+ sizeof(PyContainer), // tp_basicsize
+ 0, // tp_itemsize
+ 0, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ (reprfunc)ContainerRepr, // tp_repr
+ 0, // tp_as_number
+ &SeqSequenceMethods, // 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
+ 0, // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ (richcmpfunc)RichCompare, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ SeqMethods, // tp_methods
+ 0, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ 0, // tp_init
+ 0, // tp_alloc
+ 0, // tp_new
+ 0, // tp_free
+};
+
+static PyObject* NewMappingByName(
+ DescriptorContainerDef* container_def, const void* descriptor) {
+ PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+ if (self == NULL) {
+ return NULL;
+ }
+ self->descriptor = descriptor;
+ self->container_def = container_def;
+ self->kind = PyContainer::KIND_BYNAME;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+static PyObject* NewMappingByNumber(
+ DescriptorContainerDef* container_def, const void* descriptor) {
+ if (container_def->get_by_number_fn == NULL ||
+ container_def->get_item_number_fn == NULL) {
+ PyErr_SetNone(PyExc_NotImplementedError);
+ return NULL;
+ }
+ PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+ if (self == NULL) {
+ return NULL;
+ }
+ self->descriptor = descriptor;
+ self->container_def = container_def;
+ self->kind = PyContainer::KIND_BYNUMBER;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+static PyObject* NewSequence(
+ DescriptorContainerDef* container_def, const void* descriptor) {
+ PyContainer* self = PyObject_New(PyContainer, &DescriptorSequence_Type);
+ if (self == NULL) {
+ return NULL;
+ }
+ self->descriptor = descriptor;
+ self->container_def = container_def;
+ self->kind = PyContainer::KIND_SEQUENCE;
+ return reinterpret_cast<PyObject*>(self);
+}
+
+// Implement iterators over PyContainers.
+
+static void Iterator_Dealloc(PyContainerIterator* self) {
+ Py_CLEAR(self->container);
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+static PyObject* Iterator_Next(PyContainerIterator* self) {
+ int count = self->container->container_def->count_fn(self->container);
+ if (self->index >= count) {
+ // Return NULL with no exception to indicate the end.
+ return NULL;
+ }
+ int index = self->index;
+ self->index += 1;
+ switch (self->kind) {
+ case PyContainerIterator::KIND_ITERKEY:
+ return _NewKey_ByIndex(self->container, index);
+ case PyContainerIterator::KIND_ITERVALUE:
+ return _NewObj_ByIndex(self->container, index);
+ case PyContainerIterator::KIND_ITERVALUE_REVERSED:
+ return _NewObj_ByIndex(self->container, count - index - 1);
+ case PyContainerIterator::KIND_ITERITEM:
+ {
+ PyObject* obj = PyTuple_New(2);
+ if (obj == NULL) {
+ return NULL;
+ }
+ PyObject* key = _NewKey_ByIndex(self->container, index);
+ if (key == NULL) {
+ Py_DECREF(obj);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(obj, 0, key);
+ PyObject* value = _NewObj_ByIndex(self->container, index);
+ if (value == NULL) {
+ Py_DECREF(obj);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(obj, 1, value);
+ return obj;
+ }
+ default:
+ PyErr_SetNone(PyExc_NotImplementedError);
+ return NULL;
+ }
+}
+
+static PyTypeObject ContainerIterator_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "DescriptorContainerIterator", // tp_name
+ sizeof(PyContainerIterator), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)Iterator_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
+ 0, // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ PyObject_SelfIter, // tp_iter
+ (iternextfunc)Iterator_Next, // tp_iternext
+ 0, // tp_methods
+ 0, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ 0, // tp_init
+ 0, // tp_alloc
+ 0, // tp_new
+ 0, // tp_free
+};
+
+static PyObject* NewContainerIterator(PyContainer* container,
+ PyContainerIterator::IterKind kind) {
+ PyContainerIterator* self = PyObject_New(PyContainerIterator,
+ &ContainerIterator_Type);
+ if (self == NULL) {
+ return NULL;
+ }
+ Py_INCREF(container);
+ self->container = container;
+ self->kind = kind;
+ self->index = 0;
+
+ return reinterpret_cast<PyObject*>(self);
+}
+
+} // namespace descriptor
+
+// Now define the real collections!
+
+namespace message_descriptor {
+
+typedef const Descriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+ return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace fields {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->field_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindFieldByName(name);
+}
+
+static ItemDescriptor GetByNumber(PyContainer* self, int number) {
+ return GetDescriptor(self)->FindFieldByNumber(number);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->field(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyFieldDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemNumber(ItemDescriptor item) {
+ return item->number();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "MessageFields",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)GetByNumber,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)GetItemNumber,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace fields
+
+PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByName(&fields::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageFieldsSeq(ParentDescriptor descriptor) {
+ return descriptor::NewSequence(&fields::ContainerDef, descriptor);
+}
+
+namespace nested_types {
+
+typedef const Descriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->nested_type_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindNestedTypeByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->nested_type(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyMessageDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "MessageNestedTypes",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace nested_types
+
+PyObject* NewMessageNestedTypesSeq(ParentDescriptor descriptor) {
+ return descriptor::NewSequence(&nested_types::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageNestedTypesByName(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByName(&nested_types::ContainerDef, descriptor);
+}
+
+namespace enums {
+
+typedef const EnumDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->enum_type_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindEnumTypeByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->enum_type(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyEnumDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "MessageNestedEnums",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace enums
+
+PyObject* NewMessageEnumsByName(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageEnumsSeq(ParentDescriptor descriptor) {
+ return descriptor::NewSequence(&enums::ContainerDef, descriptor);
+}
+
+namespace enumvalues {
+
+// This is the "enum_values_by_name" mapping, which collects values from all
+// enum types in a message.
+//
+// Note that the behavior of the C++ descriptor is different: it will search and
+// return the first value that matches the name, whereas the Python
+// implementation retrieves the last one.
+
+typedef const EnumValueDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ int count = 0;
+ for (int i = 0; i < GetDescriptor(self)->enum_type_count(); ++i) {
+ count += GetDescriptor(self)->enum_type(i)->value_count();
+ }
+ return count;
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindEnumValueByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ // This is not optimal, but the number of enums *types* in a given message
+ // is small. This function is only used when iterating over the mapping.
+ const EnumDescriptor* enum_type = NULL;
+ int enum_type_count = GetDescriptor(self)->enum_type_count();
+ for (int i = 0; i < enum_type_count; ++i) {
+ enum_type = GetDescriptor(self)->enum_type(i);
+ int enum_value_count = enum_type->value_count();
+ if (index < enum_value_count) {
+ // Found it!
+ break;
+ }
+ index -= enum_value_count;
+ }
+ // The next statement cannot overflow, because this function is only called by
+ // internal iterators which ensure that 0 <= index < Count().
+ return enum_type->value(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyEnumValueDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "MessageEnumValues",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)NULL,
+};
+
+} // namespace enumvalues
+
+PyObject* NewMessageEnumValuesByName(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor);
+}
+
+namespace extensions {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->extension_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindExtensionByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->extension(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyFieldDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "MessageExtensions",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace extensions
+
+PyObject* NewMessageExtensionsByName(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageExtensionsSeq(ParentDescriptor descriptor) {
+ return descriptor::NewSequence(&extensions::ContainerDef, descriptor);
+}
+
+namespace oneofs {
+
+typedef const OneofDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->oneof_decl_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindOneofByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->oneof_decl(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyOneofDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "MessageOneofs",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace oneofs
+
+PyObject* NewMessageOneofsByName(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByName(&oneofs::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageOneofsSeq(ParentDescriptor descriptor) {
+ return descriptor::NewSequence(&oneofs::ContainerDef, descriptor);
+}
+
+} // namespace message_descriptor
+
+namespace enum_descriptor {
+
+typedef const EnumDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+ return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace enumvalues {
+
+typedef const EnumValueDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->value_count();
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->value(index);
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindValueByName(name);
+}
+
+static ItemDescriptor GetByNumber(PyContainer* self, int number) {
+ return GetDescriptor(self)->FindValueByNumber(number);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyEnumValueDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemNumber(ItemDescriptor item) {
+ return item->number();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "EnumValues",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)GetByNumber,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)GetItemNumber,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace enumvalues
+
+PyObject* NewEnumValuesByName(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor);
+}
+
+PyObject* NewEnumValuesByNumber(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByNumber(&enumvalues::ContainerDef, descriptor);
+}
+
+PyObject* NewEnumValuesSeq(ParentDescriptor descriptor) {
+ return descriptor::NewSequence(&enumvalues::ContainerDef, descriptor);
+}
+
+} // namespace enum_descriptor
+
+namespace oneof_descriptor {
+
+typedef const OneofDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+ return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace fields {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->field_count();
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->field(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyFieldDescriptor_New(item);
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index_in_oneof();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "OneofFields",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)NULL,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)NULL,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace fields
+
+PyObject* NewOneofFieldsSeq(ParentDescriptor descriptor) {
+ return descriptor::NewSequence(&fields::ContainerDef, descriptor);
+}
+
+} // namespace oneof_descriptor
+
+namespace file_descriptor {
+
+typedef const FileDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+ return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace messages {
+
+typedef const Descriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->message_type_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindMessageTypeByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->message_type(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyMessageDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "FileMessages",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace messages
+
+PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor) {
+ return descriptor::NewMappingByName(&messages::ContainerDef, descriptor);
+}
+
+namespace enums {
+
+typedef const EnumDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->enum_type_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindEnumTypeByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->enum_type(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyEnumDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "FileEnums",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace enums
+
+PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor) {
+ return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
+}
+
+namespace extensions {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->extension_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindExtensionByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->extension(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyFieldDescriptor_New(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "FileExtensions",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace extensions
+
+PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor) {
+ return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
+}
+
+namespace dependencies {
+
+typedef const FileDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->dependency_count();
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->dependency(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyFileDescriptor_New(item);
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "FileDependencies",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)NULL,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)NULL,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)NULL,
+};
+
+} // namespace dependencies
+
+PyObject* NewFileDependencies(const FileDescriptor* descriptor) {
+ return descriptor::NewSequence(&dependencies::ContainerDef, descriptor);
+}
+
+namespace public_dependencies {
+
+typedef const FileDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->public_dependency_count();
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->public_dependency(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyFileDescriptor_New(item);
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "FilePublicDependencies",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)NULL,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)NULL,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)NULL,
+};
+
+} // namespace public_dependencies
+
+PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor) {
+ return descriptor::NewSequence(&public_dependencies::ContainerDef,
+ descriptor);
+}
+
+} // namespace file_descriptor
+
+
+// Register all implementations
+
+bool InitDescriptorMappingTypes() {
+ if (PyType_Ready(&descriptor::DescriptorMapping_Type) < 0)
+ return false;
+ if (PyType_Ready(&descriptor::DescriptorSequence_Type) < 0)
+ return false;
+ if (PyType_Ready(&descriptor::ContainerIterator_Type) < 0)
+ return false;
+ return true;
+}
+
+} // namespace python
+} // namespace protobuf
+} // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h
new file mode 100644
index 00000000..d81537de
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_containers.h
@@ -0,0 +1,95 @@
+// 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.
+
+// Mappings and Sequences of descriptors.
+// They implement containers like fields_by_name, EnumDescriptor.values...
+// See descriptor_containers.cc for more description.
+#include <Python.h>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class FileDescriptor;
+class EnumDescriptor;
+class OneofDescriptor;
+
+namespace python {
+
+// Initialize the various types and objects.
+bool InitDescriptorMappingTypes();
+
+// Each function below returns a Mapping, or a Sequence of descriptors.
+// They all return a new reference.
+
+namespace message_descriptor {
+PyObject* NewMessageFieldsByName(const Descriptor* descriptor);
+PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor);
+PyObject* NewMessageFieldsSeq(const Descriptor* descriptor);
+
+PyObject* NewMessageNestedTypesSeq(const Descriptor* descriptor);
+PyObject* NewMessageNestedTypesByName(const Descriptor* descriptor);
+
+PyObject* NewMessageEnumsByName(const Descriptor* descriptor);
+PyObject* NewMessageEnumsSeq(const Descriptor* descriptor);
+PyObject* NewMessageEnumValuesByName(const Descriptor* descriptor);
+
+PyObject* NewMessageExtensionsByName(const Descriptor* descriptor);
+PyObject* NewMessageExtensionsSeq(const Descriptor* descriptor);
+
+PyObject* NewMessageOneofsByName(const Descriptor* descriptor);
+PyObject* NewMessageOneofsSeq(const Descriptor* descriptor);
+} // namespace message_descriptor
+
+namespace enum_descriptor {
+PyObject* NewEnumValuesByName(const EnumDescriptor* descriptor);
+PyObject* NewEnumValuesByNumber(const EnumDescriptor* descriptor);
+PyObject* NewEnumValuesSeq(const EnumDescriptor* descriptor);
+} // namespace enum_descriptor
+
+namespace oneof_descriptor {
+PyObject* NewOneofFieldsSeq(const OneofDescriptor* descriptor);
+} // namespace oneof_descriptor
+
+namespace file_descriptor {
+PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileDependencies(const FileDescriptor* descriptor);
+PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor);
+} // namespace file_descriptor
+
+
+} // namespace python
+} // namespace protobuf
+} // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
new file mode 100644
index 00000000..bc3077bc
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -0,0 +1,370 @@
+// 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.
+
+// Implements the DescriptorPool, which collects all descriptors.
+
+#include <Python.h>
+
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#define C(str) const_cast<char*>(str)
+
+#if PY_MAJOR_VERSION >= 3
+ #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
+ #if PY_VERSION_HEX < 0x03030000
+ #error "Python 3.0 - 3.2 are not supported."
+ #endif
+ #define PyString_AsStringAndSize(ob, charpp, sizep) \
+ (PyUnicode_Check(ob)? \
+ ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
+ PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace cdescriptor_pool {
+
+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 DescriptorPool(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();
+ cdescriptor_pool->interned_descriptors =
+ new hash_map<const void*, PyObject *>();
+ cdescriptor_pool->descriptor_options =
+ new hash_map<const void*, PyObject *>();
+
+ return cdescriptor_pool;
+}
+
+static void Dealloc(PyDescriptorPool* self) {
+ typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
+ for (iterator it = self->classes_by_descriptor->begin();
+ it != self->classes_by_descriptor->end(); ++it) {
+ Py_DECREF(it->second);
+ }
+ delete self->classes_by_descriptor;
+ delete self->interned_descriptors; // its references were borrowed.
+ for (hash_map<const void*, PyObject*>::iterator it =
+ self->descriptor_options->begin();
+ it != self->descriptor_options->end(); ++it) {
+ Py_DECREF(it->second);
+ }
+ delete self->descriptor_options;
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* arg) {
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+ return NULL;
+ }
+
+ const Descriptor* message_descriptor =
+ self->pool->FindMessageTypeByName(string(name, name_size));
+
+ if (message_descriptor == NULL) {
+ PyErr_Format(PyExc_TypeError, "Couldn't find message %.200s", name);
+ return NULL;
+ }
+
+ return PyMessageDescriptor_New(message_descriptor);
+}
+
+// Add a message class to our database.
+const Descriptor* RegisterMessageClass(
+ PyDescriptorPool* self, PyObject *message_class, PyObject* descriptor) {
+ ScopedPyObjectPtr full_message_name(
+ PyObject_GetAttrString(descriptor, "full_name"));
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(full_message_name, &name, &name_size) < 0) {
+ return NULL;
+ }
+ const Descriptor *message_descriptor =
+ self->pool->FindMessageTypeByName(string(name, name_size));
+ if (!message_descriptor) {
+ PyErr_Format(PyExc_TypeError, "Could not find C++ descriptor for '%s'",
+ name);
+ return NULL;
+ }
+ Py_INCREF(message_class);
+ typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
+ std::pair<iterator, bool> ret = self->classes_by_descriptor->insert(
+ std::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;
+ }
+ return message_descriptor;
+}
+
+// Retrieve the message class added to our database.
+PyObject *GetMessageClass(PyDescriptorPool* self,
+ const Descriptor *message_descriptor) {
+ typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
+ iterator 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* arg) {
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+ return NULL;
+ }
+
+ const FieldDescriptor* field_descriptor =
+ self->pool->FindFieldByName(string(name, name_size));
+ if (field_descriptor == NULL) {
+ PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
+ name);
+ return NULL;
+ }
+
+ return PyFieldDescriptor_New(field_descriptor);
+}
+
+PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) {
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+ return NULL;
+ }
+
+ const FieldDescriptor* field_descriptor =
+ self->pool->FindExtensionByName(string(name, name_size));
+ if (field_descriptor == NULL) {
+ PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s", name);
+ return NULL;
+ }
+
+ return PyFieldDescriptor_New(field_descriptor);
+}
+
+PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) {
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+ return NULL;
+ }
+
+ const EnumDescriptor* enum_descriptor =
+ self->pool->FindEnumTypeByName(string(name, name_size));
+ if (enum_descriptor == NULL) {
+ PyErr_Format(PyExc_TypeError, "Couldn't find enum %.200s", name);
+ return NULL;
+ }
+
+ return PyEnumDescriptor_New(enum_descriptor);
+}
+
+PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+ return NULL;
+ }
+
+ const OneofDescriptor* oneof_descriptor =
+ self->pool->FindOneofByName(string(name, name_size));
+ if (oneof_descriptor == NULL) {
+ PyErr_Format(PyExc_TypeError, "Couldn't find oneof %.200s", name);
+ return NULL;
+ }
+
+ return PyOneofDescriptor_New(oneof_descriptor);
+}
+
+static PyMethodDef Methods[] = {
+ { C("FindFieldByName"),
+ (PyCFunction)FindFieldByName,
+ METH_O,
+ C("Searches for a field descriptor by full name.") },
+ { C("FindExtensionByName"),
+ (PyCFunction)FindExtensionByName,
+ METH_O,
+ C("Searches for extension descriptor by full name.") },
+ {NULL}
+};
+
+} // namespace cdescriptor_pool
+
+PyTypeObject PyDescriptorPool_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ C("google.protobuf.internal."
+ "_message.DescriptorPool"), // tp_name
+ sizeof(PyDescriptorPool), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)cdescriptor_pool::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 Descriptor Pool"), // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ cdescriptor_pool::Methods, // tp_methods
+ 0, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ 0, // tp_init
+ 0, // tp_alloc
+ 0, // tp_new
+ PyObject_Del, // tp_free
+};
+
+// The code below loads new Descriptors from a serialized FileDescriptorProto.
+
+
+// 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.
+class BuildFileErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+ BuildFileErrorCollector() : error_message(""), had_errors(false) {}
+
+ void AddError(const string& filename, const string& element_name,
+ const Message* descriptor, ErrorLocation location,
+ const string& message) {
+ // Replicates the logging behavior that happens in the C++ implementation
+ // when an error collector is not passed in.
+ if (!had_errors) {
+ error_message +=
+ ("Invalid proto descriptor for file \"" + filename + "\":\n");
+ }
+ // As this only happens on failure and will result in the program not
+ // running at all, no effort is made to optimize this string manipulation.
+ error_message += (" " + element_name + ": " + message + "\n");
+ }
+
+ string error_message;
+ bool had_errors;
+};
+
+PyObject* Python_BuildFile(PyObject* ignored, PyObject* serialized_pb) {
+ char* message_type;
+ Py_ssize_t message_len;
+
+ if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
+ return NULL;
+ }
+
+ FileDescriptorProto file_proto;
+ if (!file_proto.ParseFromArray(message_type, message_len)) {
+ PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
+ 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.
+ const FileDescriptor* generated_file =
+ DescriptorPool::generated_pool()->FindFileByName(file_proto.name());
+ if (generated_file != NULL) {
+ return PyFileDescriptor_NewWithPb(generated_file, serialized_pb);
+ }
+
+ BuildFileErrorCollector error_collector;
+ const FileDescriptor* descriptor =
+ GetDescriptorPool()->pool->BuildFileCollectingErrors(file_proto,
+ &error_collector);
+ if (descriptor == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "Couldn't build proto file into descriptor pool!\n%s",
+ error_collector.error_message.c_str());
+ return NULL;
+ }
+
+ return PyFileDescriptor_NewWithPb(descriptor, serialized_pb);
+}
+
+static PyDescriptorPool* global_cdescriptor_pool = NULL;
+
+bool InitDescriptorPool() {
+ if (PyType_Ready(&PyDescriptorPool_Type) < 0)
+ return false;
+
+ global_cdescriptor_pool = cdescriptor_pool::NewDescriptorPool();
+ if (global_cdescriptor_pool == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+PyDescriptorPool* GetDescriptorPool() {
+ return global_cdescriptor_pool;
+}
+
+} // namespace python
+} // namespace protobuf
+} // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h
new file mode 100644
index 00000000..4e494b89
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_pool.h
@@ -0,0 +1,152 @@
+// 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_PYTHON_CPP_DESCRIPTOR_POOL_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__
+
+#include <Python.h>
+
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// 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
+
+ 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<const Descriptor*, PyObject*> ClassesByMessageMap;
+ ClassesByMessageMap* classes_by_descriptor;
+
+ // Store interned descriptors, so that the same C++ descriptor yields the same
+ // Python object. Objects are not immortal: this map does not own the
+ // references, and items are deleted when the last reference to the object is
+ // released.
+ // This is enough to support the "is" operator on live objects.
+ // All descriptors are stored here.
+ hash_map<const void*, PyObject*>* interned_descriptors;
+
+ // Cache the options for any kind of descriptor.
+ // Descriptor pointers are owned by the DescriptorPool above.
+ // Python objects are owned by the map.
+ hash_map<const void*, PyObject*>* descriptor_options;
+} PyDescriptorPool;
+
+
+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 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 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 message by name. Returns a PyMessageDescriptor corresponding to
+// the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* name);
+
+// Looks up a field by name. Returns a PyFieldDescriptor corresponding to
+// the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* name);
+
+// Looks up an extension by name. Returns a PyFieldDescriptor corresponding
+// to the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg);
+
+// Looks up an enum type by name. Returns a PyEnumDescriptor corresponding
+// to the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg);
+
+// Looks up a oneof by name. Returns a COneofDescriptor corresponding
+// to the oneof on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg);
+
+} // namespace cdescriptor_pool
+
+// Implement the Python "_BuildFile" method, it takes a serialized
+// FileDescriptorProto, and adds it to the C++ DescriptorPool.
+// It returns a new FileDescriptor object, or NULL when an exception is raised.
+PyObject* Python_BuildFile(PyObject* ignored, PyObject* args);
+
+// Retrieve the global descriptor pool owned by the _message module.
+PyDescriptorPool* GetDescriptorPool();
+
+// Initialize objects used by this module.
+bool InitDescriptorPool();
+
+} // namespace python
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__
diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc
new file mode 100644
index 00000000..8e38fc42
--- /dev/null
+++ b/python/google/protobuf/pyext/extension_dict.cc
@@ -0,0 +1,309 @@
+// 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: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#include <google/protobuf/pyext/extension_dict.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/repeated_composite_container.h>
+#include <google/protobuf/pyext/repeated_scalar_container.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/stubs/shared_ptr.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace extension_dict {
+
+// TODO(tibell): Always use self->message for clarity, just like in
+// RepeatedCompositeContainer.
+static Message* GetMessage(ExtensionDict* self) {
+ if (self->parent != NULL) {
+ return self->parent->message;
+ } else {
+ return self->message;
+ }
+}
+
+PyObject* len(ExtensionDict* self) {
+#if PY_MAJOR_VERSION >= 3
+ return PyLong_FromLong(PyDict_Size(self->values));
+#else
+ return PyInt_FromLong(PyDict_Size(self->values));
+#endif
+}
+
+// TODO(tibell): Use VisitCompositeField.
+int ReleaseExtension(ExtensionDict* self,
+ PyObject* extension,
+ const FieldDescriptor* descriptor) {
+ if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+ if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (repeated_composite_container::Release(
+ reinterpret_cast<RepeatedCompositeContainer*>(
+ extension)) < 0) {
+ return -1;
+ }
+ } else {
+ if (repeated_scalar_container::Release(
+ reinterpret_cast<RepeatedScalarContainer*>(
+ extension)) < 0) {
+ return -1;
+ }
+ }
+ } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (cmessage::ReleaseSubMessage(
+ GetMessage(self), descriptor,
+ reinterpret_cast<CMessage*>(extension)) < 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+PyObject* subscript(ExtensionDict* self, PyObject* key) {
+ const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
+ if (descriptor == NULL) {
+ return 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);
+ }
+
+ PyObject* value = PyDict_GetItem(self->values, key);
+ if (value != NULL) {
+ Py_INCREF(value);
+ return value;
+ }
+
+ if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
+ descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ PyObject* sub_message = cmessage::InternalGetSubMessage(
+ self->parent, descriptor);
+ if (sub_message == NULL) {
+ return NULL;
+ }
+ PyDict_SetItem(self->values, key, sub_message);
+ return sub_message;
+ }
+
+ if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+ if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ 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;
+ }
+ PyDict_SetItem(self->values, key, py_container);
+ return py_container;
+ } else {
+ PyObject* py_container = repeated_scalar_container::NewContainer(
+ self->parent, descriptor);
+ if (py_container == NULL) {
+ return NULL;
+ }
+ PyDict_SetItem(self->values, key, py_container);
+ return py_container;
+ }
+ }
+ PyErr_SetString(PyExc_ValueError, "control reached unexpected line");
+ return NULL;
+}
+
+int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value) {
+ const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
+ if (descriptor == NULL) {
+ return -1;
+ }
+ if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) {
+ return -1;
+ }
+
+ if (descriptor->label() != FieldDescriptor::LABEL_OPTIONAL ||
+ descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ PyErr_SetString(PyExc_TypeError, "Extension is repeated and/or composite "
+ "type");
+ return -1;
+ }
+ cmessage::AssureWritable(self->parent);
+ if (cmessage::InternalSetScalar(self->parent, descriptor, value) < 0) {
+ return -1;
+ }
+ // TODO(tibell): We shouldn't write scalars to the cache.
+ PyDict_SetItem(self->values, key, value);
+ return 0;
+}
+
+PyObject* ClearExtension(ExtensionDict* self, PyObject* extension) {
+ const FieldDescriptor* descriptor =
+ cmessage::GetExtensionDescriptor(extension);
+ if (descriptor == NULL) {
+ return NULL;
+ }
+ PyObject* value = PyDict_GetItem(self->values, extension);
+ if (value != NULL) {
+ if (ReleaseExtension(self, value, descriptor) < 0) {
+ return NULL;
+ }
+ }
+ if (cmessage::ClearFieldByDescriptor(self->parent, descriptor) == NULL) {
+ return NULL;
+ }
+ if (PyDict_DelItem(self->values, extension) < 0) {
+ PyErr_Clear();
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject* HasExtension(ExtensionDict* self, PyObject* extension) {
+ const FieldDescriptor* descriptor =
+ cmessage::GetExtensionDescriptor(extension);
+ if (descriptor == NULL) {
+ return NULL;
+ }
+ PyObject* result = cmessage::HasFieldByDescriptor(self->parent, descriptor);
+ return result;
+}
+
+PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name) {
+ ScopedPyObjectPtr extensions_by_name(PyObject_GetAttrString(
+ reinterpret_cast<PyObject*>(self->parent), "_extensions_by_name"));
+ if (extensions_by_name == NULL) {
+ return NULL;
+ }
+ PyObject* result = PyDict_GetItem(extensions_by_name, name);
+ if (result == NULL) {
+ Py_RETURN_NONE;
+ } else {
+ Py_INCREF(result);
+ return result;
+ }
+}
+
+ExtensionDict* NewExtensionDict(CMessage *parent) {
+ ExtensionDict* self = reinterpret_cast<ExtensionDict*>(
+ 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 self;
+}
+
+void dealloc(ExtensionDict* self) {
+ Py_CLEAR(self->values);
+ self->owner.reset();
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+static PyMappingMethods MpMethods = {
+ (lenfunc)len, /* mp_length */
+ (binaryfunc)subscript, /* mp_subscript */
+ (objobjargproc)ass_subscript,/* mp_ass_subscript */
+};
+
+#define EDMETHOD(name, args, doc) { #name, (PyCFunction)name, args, doc }
+static PyMethodDef Methods[] = {
+ EDMETHOD(ClearExtension, METH_O, "Clears an extension from the object."),
+ EDMETHOD(HasExtension, METH_O, "Checks if the object has an extension."),
+ EDMETHOD(_FindExtensionByName, METH_O,
+ "Finds an extension by name."),
+ { NULL, NULL }
+};
+
+} // namespace extension_dict
+
+PyTypeObject ExtensionDict_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "google.protobuf.internal."
+ "cpp._message.ExtensionDict", // tp_name
+ sizeof(ExtensionDict), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)extension_dict::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
+ &extension_dict::MpMethods, // 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
+ "An extension dict", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ extension_dict::Methods, // tp_methods
+ 0, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ 0, // tp_init
+};
+
+} // namespace python
+} // namespace protobuf
+} // namespace google
diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h
new file mode 100644
index 00000000..7e1049f1
--- /dev/null
+++ b/python/google/protobuf/pyext/extension_dict.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.
+
+// Author: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__
+
+#include <Python.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class FieldDescriptor;
+
+using internal::shared_ptr;
+
+namespace python {
+
+struct CMessage;
+
+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<Message> 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;
+
+extern PyTypeObject ExtensionDict_Type;
+
+namespace extension_dict {
+
+// 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.
+//
+// Returns a new reference.
+PyObject* len(ExtensionDict* self);
+
+// Releases extensions referenced outside this dictionary to keep outside
+// references alive.
+//
+// Returns 0 on success, -1 on failure.
+int ReleaseExtension(ExtensionDict* self,
+ PyObject* extension,
+ const FieldDescriptor* descriptor);
+
+// Gets an extension from the dict for the given extension descriptor.
+//
+// Returns a new reference.
+PyObject* subscript(ExtensionDict* self, PyObject* key);
+
+// Assigns a value to an extension in the dict. Can only be used for singular
+// simple types.
+//
+// Returns 0 on success, -1 on failure.
+int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value);
+
+// Clears an extension from the dict. Will release the extension if there
+// is still an external reference left to it.
+//
+// Returns None on success.
+PyObject* ClearExtension(ExtensionDict* self,
+ PyObject* extension);
+
+// Checks if the dict has an extension.
+//
+// Returns a new python boolean reference.
+PyObject* HasExtension(ExtensionDict* self, PyObject* extension);
+
+// Gets an extension from the dict given the extension name as opposed to
+// descriptor.
+//
+// Returns a new reference.
+PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name);
+
+} // namespace extension_dict
+} // namespace python
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
new file mode 100644
index 00000000..a2b357b2
--- /dev/null
+++ b/python/google/protobuf/pyext/message.cc
@@ -0,0 +1,2575 @@
+// 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: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#include <google/protobuf/pyext/message.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <vector>
+#include <structmember.h> // A Python header file.
+
+#ifndef PyVarObject_HEAD_INIT
+#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
+#endif
+#ifndef Py_TYPE
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/extension_dict.h>
+#include <google/protobuf/pyext/repeated_composite_container.h>
+#include <google/protobuf/pyext/repeated_scalar_container.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#if PY_MAJOR_VERSION >= 3
+ #define PyInt_Check PyLong_Check
+ #define PyInt_AsLong PyLong_AsLong
+ #define PyInt_FromLong PyLong_FromLong
+ #define PyInt_FromSize_t PyLong_FromSize_t
+ #define PyString_Check PyUnicode_Check
+ #define PyString_FromString PyUnicode_FromString
+ #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
+ #if PY_VERSION_HEX < 0x03030000
+ #error "Python 3.0 - 3.2 are not supported."
+ #else
+ #define PyString_AsString(ob) \
+ (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob))
+ #define PyString_AsStringAndSize(ob, charpp, sizep) \
+ (PyUnicode_Check(ob)? \
+ ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
+ PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+ #endif
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// Forward declarations
+namespace cmessage {
+static const FieldDescriptor* GetFieldDescriptor(
+ CMessage* self, PyObject* name);
+static const Descriptor* GetMessageDescriptor(PyTypeObject* cls);
+static string GetMessageName(CMessage* self);
+int InternalReleaseFieldByDescriptor(
+ const FieldDescriptor* field_descriptor,
+ PyObject* composite_field,
+ Message* parent_message);
+} // namespace cmessage
+
+// ---------------------------------------------------------------------
+// Visiting the composite children of a CMessage
+
+struct ChildVisitor {
+ // Returns 0 on success, -1 on failure.
+ int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
+ return 0;
+ }
+
+ // Returns 0 on success, -1 on failure.
+ int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) {
+ return 0;
+ }
+
+ // Returns 0 on success, -1 on failure.
+ int VisitCMessage(CMessage* cmessage,
+ const FieldDescriptor* field_descriptor) {
+ return 0;
+ }
+};
+
+// Apply a function to a composite field. Does nothing if child is of
+// non-composite type.
+template<class Visitor>
+static int VisitCompositeField(const FieldDescriptor* descriptor,
+ PyObject* child,
+ Visitor visitor) {
+ if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+ if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ RepeatedCompositeContainer* container =
+ reinterpret_cast<RepeatedCompositeContainer*>(child);
+ if (visitor.VisitRepeatedCompositeContainer(container) == -1)
+ return -1;
+ } else {
+ RepeatedScalarContainer* container =
+ reinterpret_cast<RepeatedScalarContainer*>(child);
+ if (visitor.VisitRepeatedScalarContainer(container) == -1)
+ return -1;
+ }
+ } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ CMessage* cmsg = reinterpret_cast<CMessage*>(child);
+ if (visitor.VisitCMessage(cmsg, descriptor) == -1)
+ return -1;
+ }
+ // The ExtensionDict might contain non-composite fields, which we
+ // skip here.
+ return 0;
+}
+
+// Visit each composite field and extension field of this CMessage.
+// Returns -1 on error and 0 on success.
+template<class Visitor>
+int ForEachCompositeField(CMessage* self, Visitor visitor) {
+ Py_ssize_t pos = 0;
+ PyObject* key;
+ PyObject* field;
+
+ // Visit normal fields.
+ if (self->composite_fields) {
+ // Never use self->message in this function, it may be already freed.
+ const Descriptor* message_descriptor =
+ cmessage::GetMessageDescriptor(Py_TYPE(self));
+ while (PyDict_Next(self->composite_fields, &pos, &key, &field)) {
+ Py_ssize_t key_str_size;
+ char *key_str_data;
+ if (PyString_AsStringAndSize(key, &key_str_data, &key_str_size) != 0)
+ return -1;
+ const string key_str(key_str_data, key_str_size);
+ const FieldDescriptor* descriptor =
+ message_descriptor->FindFieldByName(key_str);
+ if (descriptor != NULL) {
+ if (VisitCompositeField(descriptor, field, visitor) == -1)
+ return -1;
+ }
+ }
+ }
+
+ // Visit extension fields.
+ if (self->extensions != NULL) {
+ pos = 0;
+ while (PyDict_Next(self->extensions->values, &pos, &key, &field)) {
+ const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
+ if (descriptor == NULL)
+ return -1;
+ if (VisitCompositeField(descriptor, field, visitor) == -1)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+// ---------------------------------------------------------------------
+
+static DynamicMessageFactory* message_factory;
+
+// Constants used for integer type range checking.
+PyObject* kPythonZero;
+PyObject* kint32min_py;
+PyObject* kint32max_py;
+PyObject* kuint32max_py;
+PyObject* kint64min_py;
+PyObject* kint64max_py;
+PyObject* kuint64max_py;
+
+PyObject* EnumTypeWrapper_class;
+PyObject* EncodeError_class;
+PyObject* DecodeError_class;
+PyObject* PickleError_class;
+
+// Constant PyString values used for GetAttr/GetItem.
+static PyObject* kDESCRIPTOR;
+static PyObject* k_cdescriptor;
+static PyObject* kfull_name;
+static PyObject* k_extensions_by_name;
+static PyObject* k_extensions_by_number;
+
+/* Is 64bit */
+void FormatTypeError(PyObject* arg, char* expected_types) {
+ PyObject* repr = PyObject_Repr(arg);
+ if (repr) {
+ PyErr_Format(PyExc_TypeError,
+ "%.100s has type %.100s, but expected one of: %s",
+ PyString_AsString(repr),
+ Py_TYPE(arg)->tp_name,
+ expected_types);
+ Py_DECREF(repr);
+ }
+}
+
+template<class T>
+bool CheckAndGetInteger(
+ PyObject* arg, T* value, PyObject* min, PyObject* max) {
+ bool is_long = PyLong_Check(arg);
+#if PY_MAJOR_VERSION < 3
+ if (!PyInt_Check(arg) && !is_long) {
+ FormatTypeError(arg, "int, long");
+ return false;
+ }
+ if (PyObject_Compare(min, arg) > 0 || PyObject_Compare(max, arg) < 0) {
+#else
+ if (!is_long) {
+ FormatTypeError(arg, "int");
+ return false;
+ }
+ if (PyObject_RichCompareBool(min, arg, Py_LE) != 1 ||
+ PyObject_RichCompareBool(max, arg, Py_GE) != 1) {
+#endif
+ PyObject *s = PyObject_Str(arg);
+ if (s) {
+ PyErr_Format(PyExc_ValueError,
+ "Value out of range: %s",
+ PyString_AsString(s));
+ Py_DECREF(s);
+ }
+ return false;
+ }
+#if PY_MAJOR_VERSION < 3
+ if (!is_long) {
+ *value = static_cast<T>(PyInt_AsLong(arg));
+ } else // NOLINT
+#endif
+ {
+ if (min == kPythonZero) {
+ *value = static_cast<T>(PyLong_AsUnsignedLongLong(arg));
+ } else {
+ *value = static_cast<T>(PyLong_AsLongLong(arg));
+ }
+ }
+ return true;
+}
+
+// These are referenced by repeated_scalar_container, and must
+// be explicitly instantiated.
+template bool CheckAndGetInteger<int32>(
+ PyObject*, int32*, PyObject*, PyObject*);
+template bool CheckAndGetInteger<int64>(
+ PyObject*, int64*, PyObject*, PyObject*);
+template bool CheckAndGetInteger<uint32>(
+ PyObject*, uint32*, PyObject*, PyObject*);
+template bool CheckAndGetInteger<uint64>(
+ PyObject*, uint64*, PyObject*, PyObject*);
+
+bool CheckAndGetDouble(PyObject* arg, double* value) {
+ if (!PyInt_Check(arg) && !PyLong_Check(arg) &&
+ !PyFloat_Check(arg)) {
+ FormatTypeError(arg, "int, long, float");
+ return false;
+ }
+ *value = PyFloat_AsDouble(arg);
+ return true;
+}
+
+bool CheckAndGetFloat(PyObject* arg, float* value) {
+ double double_value;
+ if (!CheckAndGetDouble(arg, &double_value)) {
+ return false;
+ }
+ *value = static_cast<float>(double_value);
+ return true;
+}
+
+bool CheckAndGetBool(PyObject* arg, bool* value) {
+ if (!PyInt_Check(arg) && !PyBool_Check(arg) && !PyLong_Check(arg)) {
+ FormatTypeError(arg, "int, long, bool");
+ return false;
+ }
+ *value = static_cast<bool>(PyInt_AsLong(arg));
+ return true;
+}
+
+bool CheckAndSetString(
+ PyObject* arg, Message* message,
+ const FieldDescriptor* descriptor,
+ const Reflection* reflection,
+ bool append,
+ int index) {
+ GOOGLE_DCHECK(descriptor->type() == FieldDescriptor::TYPE_STRING ||
+ descriptor->type() == FieldDescriptor::TYPE_BYTES);
+ if (descriptor->type() == FieldDescriptor::TYPE_STRING) {
+ if (!PyBytes_Check(arg) && !PyUnicode_Check(arg)) {
+ FormatTypeError(arg, "bytes, unicode");
+ return false;
+ }
+
+ if (PyBytes_Check(arg)) {
+ 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 valid UTF-8 "
+ "encoding. Non-UTF-8 strings must be converted to "
+ "unicode objects before being added.",
+ PyString_AsString(repr));
+ Py_DECREF(repr);
+ return false;
+ } else {
+ Py_DECREF(unicode);
+ }
+ }
+ } else if (!PyBytes_Check(arg)) {
+ FormatTypeError(arg, "bytes");
+ return false;
+ }
+
+ PyObject* encoded_string = NULL;
+ if (descriptor->type() == FieldDescriptor::TYPE_STRING) {
+ if (PyBytes_Check(arg)) {
+ // The bytes were already validated as correctly encoded UTF-8 above.
+ encoded_string = arg; // Already encoded.
+ Py_INCREF(encoded_string);
+ } else {
+ encoded_string = PyUnicode_AsEncodedObject(arg, "utf-8", NULL);
+ }
+ } else {
+ // In this case field type is "bytes".
+ encoded_string = arg;
+ Py_INCREF(encoded_string);
+ }
+
+ if (encoded_string == NULL) {
+ return false;
+ }
+
+ char* value;
+ Py_ssize_t value_len;
+ if (PyBytes_AsStringAndSize(encoded_string, &value, &value_len) < 0) {
+ Py_DECREF(encoded_string);
+ return false;
+ }
+
+ string value_string(value, value_len);
+ if (append) {
+ reflection->AddString(message, descriptor, value_string);
+ } else if (index < 0) {
+ reflection->SetString(message, descriptor, value_string);
+ } else {
+ reflection->SetRepeatedString(message, descriptor, index, value_string);
+ }
+ Py_DECREF(encoded_string);
+ return true;
+}
+
+PyObject* ToStringObject(const FieldDescriptor* descriptor, string value) {
+ if (descriptor->type() != FieldDescriptor::TYPE_STRING) {
+ return PyBytes_FromStringAndSize(value.c_str(), value.length());
+ }
+
+ PyObject* result = PyUnicode_DecodeUTF8(value.c_str(), value.length(), NULL);
+ // If the string can't be decoded in UTF-8, just return a string object that
+ // contains the raw bytes. This can't happen if the value was assigned using
+ // the members of the Python message object, but can happen if the values were
+ // parsed from the wire (binary).
+ if (result == NULL) {
+ PyErr_Clear();
+ result = PyBytes_FromStringAndSize(value.c_str(), value.length());
+ }
+ return result;
+}
+
+bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
+ const 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;
+}
+
+namespace cmessage {
+
+DynamicMessageFactory* GetMessageFactory() {
+ return message_factory;
+}
+
+static int MaybeReleaseOverlappingOneofField(
+ CMessage* cmessage,
+ const FieldDescriptor* field) {
+#ifdef GOOGLE_PROTOBUF_HAS_ONEOF
+ Message* message = cmessage->message;
+ const Reflection* reflection = message->GetReflection();
+ if (!field->containing_oneof() ||
+ !reflection->HasOneof(*message, field->containing_oneof()) ||
+ reflection->HasField(*message, field)) {
+ // No other field in this oneof, no need to release.
+ return 0;
+ }
+
+ const OneofDescriptor* oneof = field->containing_oneof();
+ const FieldDescriptor* existing_field =
+ reflection->GetOneofFieldDescriptor(*message, oneof);
+ if (existing_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Non-message fields don't need to be released.
+ return 0;
+ }
+ const char* field_name = existing_field->name().c_str();
+ PyObject* child_message = cmessage->composite_fields ?
+ PyDict_GetItemString(cmessage->composite_fields, field_name) : NULL;
+ if (child_message == NULL) {
+ // No python reference to this field so no need to release.
+ return 0;
+ }
+
+ if (InternalReleaseFieldByDescriptor(
+ existing_field, child_message, message) < 0) {
+ return -1;
+ }
+ return PyDict_DelItemString(cmessage->composite_fields, field_name);
+#else
+ return 0;
+#endif
+}
+
+// ---------------------------------------------------------------------
+// Making a message writable
+
+static Message* GetMutableMessage(
+ CMessage* parent,
+ const FieldDescriptor* parent_field) {
+ Message* parent_message = parent->message;
+ const Reflection* reflection = parent_message->GetReflection();
+ if (MaybeReleaseOverlappingOneofField(parent, parent_field) < 0) {
+ return NULL;
+ }
+ return reflection->MutableMessage(
+ parent_message, parent_field, message_factory);
+}
+
+struct FixupMessageReference : public ChildVisitor {
+ // message must outlive this object.
+ explicit FixupMessageReference(Message* message) :
+ message_(message) {}
+
+ int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
+ container->message = message_;
+ return 0;
+ }
+
+ int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) {
+ container->message = message_;
+ return 0;
+ }
+
+ private:
+ Message* message_;
+};
+
+int AssureWritable(CMessage* self) {
+ if (self == NULL || !self->read_only) {
+ return 0;
+ }
+
+ if (self->parent == NULL) {
+ // If parent is NULL but we are trying to modify a read-only message, this
+ // is a reference to a constant default instance that needs to be replaced
+ // with a mutable top-level message.
+ const Message* prototype = message_factory->GetPrototype(
+ self->message->GetDescriptor());
+ self->message = prototype->New();
+ self->owner.reset(self->message);
+ } else {
+ // Otherwise, we need a mutable child message.
+ if (AssureWritable(self->parent) == -1)
+ return -1;
+
+ // Make self->message writable.
+ Message* parent_message = self->parent->message;
+ Message* mutable_message = GetMutableMessage(
+ self->parent,
+ self->parent_field_descriptor);
+ if (mutable_message == NULL) {
+ return -1;
+ }
+ self->message = mutable_message;
+ }
+ self->read_only = false;
+
+ // When a CMessage is made writable its Message pointer is updated
+ // to point to a new mutable Message. When that happens we need to
+ // update any references to the old, read-only CMessage. There are
+ // three places such references occur: RepeatedScalarContainer,
+ // RepeatedCompositeContainer, and ExtensionDict.
+ if (self->extensions != NULL)
+ self->extensions->message = self->message;
+ if (ForEachCompositeField(self, FixupMessageReference(self->message)) == -1)
+ return -1;
+
+ return 0;
+}
+
+// --- Globals:
+
+// Retrieve the C++ Descriptor of a message class.
+// On error, returns NULL with an exception set.
+static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
+ ScopedPyObjectPtr descriptor(PyObject_GetAttr(
+ reinterpret_cast<PyObject*>(cls), kDESCRIPTOR));
+ if (descriptor == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
+ return NULL;
+ }
+ if (!PyObject_TypeCheck(descriptor, &PyMessageDescriptor_Type)) {
+ PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s",
+ descriptor->ob_type->tp_name);
+ return NULL;
+ }
+ return PyMessageDescriptor_AsDescriptor(descriptor);
+}
+
+// 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 FieldDescriptor* GetFieldDescriptor(
+ CMessage* self, PyObject* name) {
+ const Descriptor *message_descriptor = self->message->GetDescriptor();
+ char* field_name;
+ Py_ssize_t size;
+ if (PyString_AsStringAndSize(name, &field_name, &size) < 0) {
+ return NULL;
+ }
+ const FieldDescriptor *field_descriptor =
+ message_descriptor->FindFieldByName(string(field_name, size));
+ if (field_descriptor == NULL) {
+ // Note: No exception is set!
+ return NULL;
+ }
+ return field_descriptor;
+}
+
+// Retrieve a C++ FieldDescriptor for an extension handle.
+const FieldDescriptor* GetExtensionDescriptor(PyObject* extension) {
+ ScopedPyObjectPtr cdescriptor;
+ if (!PyObject_TypeCheck(extension, &PyFieldDescriptor_Type)) {
+ // Most callers consider extensions as a plain dictionary. We should
+ // allow input which is not a field descriptor, and simply pretend it does
+ // not exist.
+ PyErr_SetObject(PyExc_KeyError, extension);
+ return NULL;
+ }
+ return PyFieldDescriptor_AsDescriptor(extension);
+}
+
+// If cmessage_list is not NULL, this function releases values into the
+// container CMessages instead of just removing. Repeated composite container
+// needs to do this to make sure CMessages stay alive if they're still
+// referenced after deletion. Repeated scalar container doesn't need to worry.
+int InternalDeleteRepeatedField(
+ Message* message,
+ const FieldDescriptor* field_descriptor,
+ PyObject* slice,
+ PyObject* cmessage_list) {
+ Py_ssize_t length, from, to, step, slice_length;
+ const Reflection* reflection = message->GetReflection();
+ int min, max;
+ length = reflection->FieldSize(*message, field_descriptor);
+
+ if (PyInt_Check(slice) || PyLong_Check(slice)) {
+ from = to = PyLong_AsLong(slice);
+ if (from < 0) {
+ from = to = length + from;
+ }
+ step = 1;
+ min = max = from;
+
+ // Range check.
+ if (from < 0 || from >= length) {
+ PyErr_Format(PyExc_IndexError, "list assignment index out of range");
+ return -1;
+ }
+ } else if (PySlice_Check(slice)) {
+ from = to = step = slice_length = 0;
+ PySlice_GetIndicesEx(
+#if PY_MAJOR_VERSION < 3
+ reinterpret_cast<PySliceObject*>(slice),
+#else
+ slice,
+#endif
+ length, &from, &to, &step, &slice_length);
+ if (from < to) {
+ min = from;
+ max = to - 1;
+ } else {
+ min = to + 1;
+ max = from;
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError, "list indices must be integers");
+ return -1;
+ }
+
+ Py_ssize_t i = from;
+ std::vector<bool> to_delete(length, false);
+ while (i >= min && i <= max) {
+ to_delete[i] = true;
+ i += step;
+ }
+
+ to = 0;
+ for (i = 0; i < length; ++i) {
+ if (!to_delete[i]) {
+ if (i != to) {
+ reflection->SwapElements(message, field_descriptor, i, to);
+ if (cmessage_list != NULL) {
+ // If a list of cmessages is passed in (i.e. from a repeated
+ // composite container), swap those as well to correspond to the
+ // swaps in the underlying message so they're in the right order
+ // when we start releasing.
+ PyObject* tmp = PyList_GET_ITEM(cmessage_list, i);
+ PyList_SET_ITEM(cmessage_list, i,
+ PyList_GET_ITEM(cmessage_list, to));
+ PyList_SET_ITEM(cmessage_list, to, tmp);
+ }
+ }
+ ++to;
+ }
+ }
+
+ while (i > to) {
+ if (cmessage_list == NULL) {
+ reflection->RemoveLast(message, field_descriptor);
+ } else {
+ CMessage* last_cmessage = reinterpret_cast<CMessage*>(
+ PyList_GET_ITEM(cmessage_list, PyList_GET_SIZE(cmessage_list) - 1));
+ repeated_composite_container::ReleaseLastTo(
+ field_descriptor, message, last_cmessage);
+ if (PySequence_DelItem(cmessage_list, -1) < 0) {
+ return -1;
+ }
+ }
+ --i;
+ }
+
+ return 0;
+}
+
+// Initializes fields of a message. Used in constructors.
+int InitAttributes(CMessage* self, PyObject* kwargs) {
+ if (kwargs == NULL) {
+ return 0;
+ }
+
+ Py_ssize_t pos = 0;
+ PyObject* name;
+ PyObject* value;
+ while (PyDict_Next(kwargs, &pos, &name, &value)) {
+ if (!PyString_Check(name)) {
+ PyErr_SetString(PyExc_ValueError, "Field name must be a string");
+ return -1;
+ }
+ const FieldDescriptor* descriptor = GetFieldDescriptor(self, name);
+ if (descriptor == NULL) {
+ PyErr_Format(PyExc_ValueError, "Protocol message has no \"%s\" field.",
+ PyString_AsString(name));
+ return -1;
+ }
+ if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+ ScopedPyObjectPtr container(GetAttr(self, name));
+ if (container == NULL) {
+ return -1;
+ }
+ if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (repeated_composite_container::Extend(
+ reinterpret_cast<RepeatedCompositeContainer*>(container.get()),
+ value)
+ == NULL) {
+ return -1;
+ }
+ } else {
+ if (repeated_scalar_container::Extend(
+ reinterpret_cast<RepeatedScalarContainer*>(container.get()),
+ value) ==
+ NULL) {
+ return -1;
+ }
+ }
+ } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ ScopedPyObjectPtr message(GetAttr(self, name));
+ if (message == NULL) {
+ return -1;
+ }
+ if (MergeFrom(reinterpret_cast<CMessage*>(message.get()),
+ value) == NULL) {
+ return -1;
+ }
+ } else {
+ if (SetAttr(self, name, value) < 0) {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+// Allocates an incomplete Python Message: the caller must fill self->message,
+// self->owner and eventually self->parent.
+CMessage* NewEmptyMessage(PyObject* type, const Descriptor *descriptor) {
+ CMessage* self = reinterpret_cast<CMessage*>(
+ PyType_GenericAlloc(reinterpret_cast<PyTypeObject*>(type), 0));
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->message = NULL;
+ self->parent = NULL;
+ self->parent_field_descriptor = NULL;
+ self->read_only = false;
+ self->extensions = NULL;
+
+ self->composite_fields = NULL;
+
+ // 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;
+ }
+
+ return self;
+}
+
+// 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 Descriptor* message_descriptor = GetMessageDescriptor(type);
+ if (message_descriptor == NULL) {
+ return NULL;
+ }
+ const Message* default_message =
+ message_factory->GetPrototype(message_descriptor);
+ if (default_message == NULL) {
+ PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str());
+ return NULL;
+ }
+
+ CMessage* self = NewEmptyMessage(reinterpret_cast<PyObject*>(type),
+ message_descriptor);
+ if (self == NULL) {
+ return NULL;
+ }
+ self->message = default_message->New();
+ self->owner.reset(self->message);
+
+ return reinterpret_cast<PyObject*>(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 InitAttributes(self, kwargs);
+}
+
+// ---------------------------------------------------------------------
+// Deallocating a CMessage
+//
+// Deallocating a CMessage requires that we clear any weak references
+// from children to the message being deallocated.
+
+// Clear the weak reference from the child to the parent.
+struct ClearWeakReferences : public ChildVisitor {
+ int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
+ container->parent = NULL;
+ // The elements in the container have the same parent as the
+ // container itself, so NULL out that pointer as well.
+ const Py_ssize_t n = PyList_GET_SIZE(container->child_messages);
+ for (Py_ssize_t i = 0; i < n; ++i) {
+ CMessage* child_cmessage = reinterpret_cast<CMessage*>(
+ PyList_GET_ITEM(container->child_messages, i));
+ child_cmessage->parent = NULL;
+ }
+ return 0;
+ }
+
+ int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) {
+ container->parent = NULL;
+ return 0;
+ }
+
+ int VisitCMessage(CMessage* cmessage,
+ const FieldDescriptor* field_descriptor) {
+ cmessage->parent = NULL;
+ return 0;
+ }
+};
+
+static void Dealloc(CMessage* self) {
+ // Null out all weak references from children to this message.
+ GOOGLE_CHECK_EQ(0, ForEachCompositeField(self, ClearWeakReferences()));
+
+ Py_CLEAR(self->extensions);
+ Py_CLEAR(self->composite_fields);
+ self->owner.reset();
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+// ---------------------------------------------------------------------
+
+
+PyObject* IsInitialized(CMessage* self, PyObject* args) {
+ PyObject* errors = NULL;
+ if (PyArg_ParseTuple(args, "|O", &errors) < 0) {
+ return NULL;
+ }
+ if (self->message->IsInitialized()) {
+ Py_RETURN_TRUE;
+ }
+ if (errors != NULL) {
+ ScopedPyObjectPtr initialization_errors(
+ FindInitializationErrors(self));
+ if (initialization_errors == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr extend_name(PyString_FromString("extend"));
+ if (extend_name == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr result(PyObject_CallMethodObjArgs(
+ errors,
+ extend_name.get(),
+ initialization_errors.get(),
+ NULL));
+ if (result == NULL) {
+ return NULL;
+ }
+ }
+ Py_RETURN_FALSE;
+}
+
+PyObject* HasFieldByDescriptor(
+ CMessage* self, const FieldDescriptor* field_descriptor) {
+ Message* message = self->message;
+ if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
+ return NULL;
+ }
+ if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+ PyErr_SetString(PyExc_KeyError,
+ "Field is repeated. A singular method is required.");
+ return NULL;
+ }
+ bool has_field =
+ message->GetReflection()->HasField(*message, field_descriptor);
+ return PyBool_FromLong(has_field ? 1 : 0);
+}
+
+const FieldDescriptor* FindFieldWithOneofs(
+ const Message* message, const string& field_name, bool* in_oneof) {
+ *in_oneof = false;
+ const Descriptor* descriptor = message->GetDescriptor();
+ const FieldDescriptor* field_descriptor =
+ descriptor->FindFieldByName(field_name);
+ if (field_descriptor != NULL) {
+ return field_descriptor;
+ }
+ const OneofDescriptor* oneof_desc =
+ descriptor->FindOneofByName(field_name);
+ if (oneof_desc != NULL) {
+ *in_oneof = true;
+ return message->GetReflection()->GetOneofFieldDescriptor(*message,
+ oneof_desc);
+ }
+ return NULL;
+}
+
+bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
+ if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+ PyErr_Format(PyExc_ValueError,
+ "Protocol message has no singular \"%s\" field.",
+ field_descriptor->name().c_str());
+ return false;
+ }
+
+ if (field_descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+ // HasField() for a oneof *itself* isn't supported.
+ if (in_oneof) {
+ PyErr_Format(PyExc_ValueError,
+ "Can't test oneof field \"%s\" for presence in proto3, use "
+ "WhichOneof instead.",
+ field_descriptor->containing_oneof()->name().c_str());
+ return false;
+ }
+
+ // ...but HasField() for fields *in* a oneof is supported.
+ if (field_descriptor->containing_oneof() != NULL) {
+ return true;
+ }
+
+ if (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+ PyErr_Format(
+ PyExc_ValueError,
+ "Can't test non-submessage field \"%s\" for presence in proto3.",
+ field_descriptor->name().c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+PyObject* HasField(CMessage* self, PyObject* arg) {
+ char* field_name;
+ Py_ssize_t size;
+#if PY_MAJOR_VERSION < 3
+ if (PyString_AsStringAndSize(arg, &field_name, &size) < 0) {
+ return NULL;
+ }
+#else
+ field_name = PyUnicode_AsUTF8AndSize(arg, &size);
+ if (!field_name) {
+ return NULL;
+ }
+#endif
+
+ Message* message = self->message;
+ bool is_in_oneof;
+ const FieldDescriptor* field_descriptor =
+ FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof);
+ if (field_descriptor == NULL) {
+ if (!is_in_oneof) {
+ PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
+ return NULL;
+ } else {
+ Py_RETURN_FALSE;
+ }
+ }
+
+ if (!CheckHasPresence(field_descriptor, is_in_oneof)) {
+ return NULL;
+ }
+
+ if (message->GetReflection()->HasField(*message, field_descriptor)) {
+ Py_RETURN_TRUE;
+ }
+ if (!message->GetReflection()->SupportsUnknownEnumValues() &&
+ field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+ // Special case: Python HasField() differs in semantics from C++
+ // slightly: we return HasField('enum_field') == true if there is
+ // an unknown enum value present. To implement this we have to
+ // look in the UnknownFieldSet.
+ const UnknownFieldSet& unknown_field_set =
+ message->GetReflection()->GetUnknownFields(*message);
+ for (int i = 0; i < unknown_field_set.field_count(); ++i) {
+ if (unknown_field_set.field(i).number() == field_descriptor->number()) {
+ Py_RETURN_TRUE;
+ }
+ }
+ }
+ Py_RETURN_FALSE;
+}
+
+PyObject* ClearExtension(CMessage* self, PyObject* arg) {
+ if (self->extensions != NULL) {
+ return extension_dict::ClearExtension(self->extensions, arg);
+ }
+ PyErr_SetString(PyExc_TypeError, "Message is not extendable");
+ return NULL;
+}
+
+PyObject* HasExtension(CMessage* self, PyObject* arg) {
+ if (self->extensions != NULL) {
+ return extension_dict::HasExtension(self->extensions, arg);
+ }
+ PyErr_SetString(PyExc_TypeError, "Message is not extendable");
+ return NULL;
+}
+
+// ---------------------------------------------------------------------
+// Releasing messages
+//
+// The Python API's ClearField() and Clear() methods behave
+// differently than their C++ counterparts. While the C++ versions
+// clears the children the Python versions detaches the children,
+// without touching their content. This impedance mismatch causes
+// some complexity in the implementation, which is captured in this
+// section.
+//
+// When a CMessage field is cleared we need to:
+//
+// * Release the Message used as the backing store for the CMessage
+// from its parent.
+//
+// * Change the owner field of the released CMessage and all of its
+// children to point to the newly released Message.
+//
+// * Clear the weak references from the released CMessage to the
+// parent.
+//
+// When a RepeatedCompositeContainer field is cleared we need to:
+//
+// * Release all the Message used as the backing store for the
+// CMessages stored in the container.
+//
+// * Change the owner field of all the released CMessage and all of
+// their children to point to the newly released Messages.
+//
+// * Clear the weak references from the released container to the
+// parent.
+
+struct SetOwnerVisitor : public ChildVisitor {
+ // new_owner must outlive this object.
+ explicit SetOwnerVisitor(const shared_ptr<Message>& new_owner)
+ : new_owner_(new_owner) {}
+
+ int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
+ repeated_composite_container::SetOwner(container, new_owner_);
+ return 0;
+ }
+
+ int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) {
+ repeated_scalar_container::SetOwner(container, new_owner_);
+ return 0;
+ }
+
+ int VisitCMessage(CMessage* cmessage,
+ const FieldDescriptor* field_descriptor) {
+ return SetOwner(cmessage, new_owner_);
+ }
+
+ private:
+ const shared_ptr<Message>& new_owner_;
+};
+
+// Change the owner of this CMessage and all its children, recursively.
+int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner) {
+ self->owner = new_owner;
+ if (ForEachCompositeField(self, SetOwnerVisitor(new_owner)) == -1)
+ return -1;
+ return 0;
+}
+
+// Releases the message specified by 'field' and returns the
+// pointer. If the field does not exist a new message is created using
+// 'descriptor'. The caller takes ownership of the returned pointer.
+Message* ReleaseMessage(Message* message,
+ const Descriptor* descriptor,
+ const FieldDescriptor* field_descriptor) {
+ Message* released_message = message->GetReflection()->ReleaseMessage(
+ message, field_descriptor, message_factory);
+ // ReleaseMessage will return NULL which differs from
+ // child_cmessage->message, if the field does not exist. In this case,
+ // the latter points to the default instance via a const_cast<>, so we
+ // have to reset it to a new mutable object since we are taking ownership.
+ if (released_message == NULL) {
+ const Message* prototype = message_factory->GetPrototype(descriptor);
+ GOOGLE_DCHECK(prototype != NULL);
+ released_message = prototype->New();
+ }
+
+ return released_message;
+}
+
+int ReleaseSubMessage(Message* message,
+ const FieldDescriptor* field_descriptor,
+ CMessage* child_cmessage) {
+ // Release the Message
+ shared_ptr<Message> released_message(ReleaseMessage(
+ message, child_cmessage->message->GetDescriptor(), field_descriptor));
+ child_cmessage->message = released_message.get();
+ child_cmessage->owner.swap(released_message);
+ child_cmessage->parent = NULL;
+ child_cmessage->parent_field_descriptor = NULL;
+ child_cmessage->read_only = false;
+ return ForEachCompositeField(child_cmessage,
+ SetOwnerVisitor(child_cmessage->owner));
+}
+
+struct ReleaseChild : public ChildVisitor {
+ // message must outlive this object.
+ explicit ReleaseChild(Message* parent_message) :
+ parent_message_(parent_message) {}
+
+ int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
+ return repeated_composite_container::Release(
+ reinterpret_cast<RepeatedCompositeContainer*>(container));
+ }
+
+ int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) {
+ return repeated_scalar_container::Release(
+ reinterpret_cast<RepeatedScalarContainer*>(container));
+ }
+
+ int VisitCMessage(CMessage* cmessage,
+ const FieldDescriptor* field_descriptor) {
+ return ReleaseSubMessage(parent_message_, field_descriptor,
+ reinterpret_cast<CMessage*>(cmessage));
+ }
+
+ Message* parent_message_;
+};
+
+int InternalReleaseFieldByDescriptor(
+ const FieldDescriptor* field_descriptor,
+ PyObject* composite_field,
+ Message* parent_message) {
+ return VisitCompositeField(
+ field_descriptor,
+ composite_field,
+ ReleaseChild(parent_message));
+}
+
+PyObject* ClearFieldByDescriptor(
+ CMessage* self,
+ const FieldDescriptor* descriptor) {
+ if (!CheckFieldBelongsToMessage(descriptor, self->message)) {
+ return NULL;
+ }
+ AssureWritable(self);
+ self->message->GetReflection()->ClearField(self->message, descriptor);
+ Py_RETURN_NONE;
+}
+
+PyObject* ClearField(CMessage* self, PyObject* arg) {
+ if (!PyString_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "field name must be a string");
+ return NULL;
+ }
+#if PY_MAJOR_VERSION < 3
+ const char* field_name = PyString_AS_STRING(arg);
+ Py_ssize_t size = PyString_GET_SIZE(arg);
+#else
+ Py_ssize_t size;
+ const char* field_name = PyUnicode_AsUTF8AndSize(arg, &size);
+#endif
+ AssureWritable(self);
+ Message* message = self->message;
+ ScopedPyObjectPtr arg_in_oneof;
+ bool is_in_oneof;
+ const FieldDescriptor* field_descriptor =
+ FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof);
+ if (field_descriptor == NULL) {
+ if (!is_in_oneof) {
+ PyErr_Format(PyExc_ValueError,
+ "Protocol message has no \"%s\" field.", field_name);
+ return NULL;
+ } else {
+ Py_RETURN_NONE;
+ }
+ } else if (is_in_oneof) {
+ const string& name = field_descriptor->name();
+ arg_in_oneof.reset(PyString_FromStringAndSize(name.c_str(), name.size()));
+ arg = arg_in_oneof.get();
+ }
+
+ PyObject* composite_field = self->composite_fields ?
+ PyDict_GetItem(self->composite_fields, arg) : NULL;
+
+ // Only release the field if there's a possibility that there are
+ // references to it.
+ if (composite_field != NULL) {
+ if (InternalReleaseFieldByDescriptor(field_descriptor,
+ composite_field, message) < 0) {
+ return NULL;
+ }
+ PyDict_DelItem(self->composite_fields, arg);
+ }
+ message->GetReflection()->ClearField(message, field_descriptor);
+ if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+ !message->GetReflection()->SupportsUnknownEnumValues()) {
+ UnknownFieldSet* unknown_field_set =
+ message->GetReflection()->MutableUnknownFields(message);
+ unknown_field_set->DeleteByNumber(field_descriptor->number());
+ }
+
+ Py_RETURN_NONE;
+}
+
+PyObject* Clear(CMessage* self) {
+ AssureWritable(self);
+ if (ForEachCompositeField(self, ReleaseChild(self->message)) == -1)
+ return NULL;
+
+ // The old ExtensionDict still aliases this CMessage, but all its
+ // fields have been released.
+ if (self->extensions != NULL) {
+ Py_CLEAR(self->extensions);
+ ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self);
+ if (extension_dict == NULL) {
+ return NULL;
+ }
+ self->extensions = extension_dict;
+ }
+ if (self->composite_fields) {
+ PyDict_Clear(self->composite_fields);
+ }
+ self->message->Clear();
+ Py_RETURN_NONE;
+}
+
+// ---------------------------------------------------------------------
+
+static string GetMessageName(CMessage* self) {
+ if (self->parent_field_descriptor != NULL) {
+ return self->parent_field_descriptor->full_name();
+ } else {
+ return self->message->GetDescriptor()->full_name();
+ }
+}
+
+static PyObject* SerializeToString(CMessage* self, PyObject* args) {
+ if (!self->message->IsInitialized()) {
+ ScopedPyObjectPtr errors(FindInitializationErrors(self));
+ if (errors == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr comma(PyString_FromString(","));
+ if (comma == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr joined(
+ PyObject_CallMethod(comma.get(), "join", "O", errors.get()));
+ if (joined == NULL) {
+ return NULL;
+ }
+
+ // TODO(haberman): this is a (hopefully temporary) hack. The unit testing
+ // infrastructure reloads all pure-Python modules for every test, but not
+ // C++ modules (because that's generally impossible:
+ // http://bugs.python.org/issue1144263). But if we cache EncodeError, we'll
+ // return the EncodeError from a previous load of the module, which won't
+ // match a user's attempt to catch EncodeError. So we have to look it up
+ // again every time.
+ ScopedPyObjectPtr message_module(PyImport_ImportModule(
+ "google.protobuf.message"));
+ if (message_module.get() == NULL) {
+ return NULL;
+ }
+
+ ScopedPyObjectPtr encode_error(
+ PyObject_GetAttrString(message_module, "EncodeError"));
+ if (encode_error.get() == NULL) {
+ return NULL;
+ }
+ PyErr_Format(encode_error.get(),
+ "Message %s is missing required fields: %s",
+ GetMessageName(self).c_str(), PyString_AsString(joined));
+ return NULL;
+ }
+ int size = self->message->ByteSize();
+ if (size <= 0) {
+ return PyBytes_FromString("");
+ }
+ PyObject* result = PyBytes_FromStringAndSize(NULL, size);
+ if (result == NULL) {
+ return NULL;
+ }
+ char* buffer = PyBytes_AS_STRING(result);
+ self->message->SerializeWithCachedSizesToArray(
+ reinterpret_cast<uint8*>(buffer));
+ return result;
+}
+
+static PyObject* SerializePartialToString(CMessage* self) {
+ string contents;
+ self->message->SerializePartialToString(&contents);
+ return PyBytes_FromStringAndSize(contents.c_str(), contents.size());
+}
+
+// Formats proto fields for ascii dumps using python formatting functions where
+// appropriate.
+class PythonFieldValuePrinter : public TextFormat::FieldValuePrinter {
+ public:
+ PythonFieldValuePrinter() : float_holder_(PyFloat_FromDouble(0)) {}
+
+ // Python has some differences from C++ when printing floating point numbers.
+ //
+ // 1) Trailing .0 is always printed.
+ // 2) Outputted is rounded to 12 digits.
+ //
+ // We override floating point printing with the C-API function for printing
+ // Python floats to ensure consistency.
+ string PrintFloat(float value) const { return PrintDouble(value); }
+ string PrintDouble(double value) const {
+ reinterpret_cast<PyFloatObject*>(float_holder_.get())->ob_fval = value;
+ ScopedPyObjectPtr s(PyObject_Str(float_holder_.get()));
+ if (s == NULL) return string();
+#if PY_MAJOR_VERSION < 3
+ char *cstr = PyBytes_AS_STRING(static_cast<PyObject*>(s));
+#else
+ char *cstr = PyUnicode_AsUTF8(s);
+#endif
+ return string(cstr);
+ }
+
+ private:
+ // Holder for a python float object which we use to allow us to use
+ // the Python API for printing doubles. We initialize once and then
+ // directly modify it for every float printed to save on allocations
+ // and refcounting.
+ ScopedPyObjectPtr float_holder_;
+};
+
+static PyObject* ToStr(CMessage* self) {
+ TextFormat::Printer printer;
+ // Passes ownership
+ printer.SetDefaultFieldValuePrinter(new PythonFieldValuePrinter());
+ printer.SetHideUnknownFields(true);
+ string output;
+ if (!printer.PrintToString(*self->message, &output)) {
+ PyErr_SetString(PyExc_ValueError, "Unable to convert message to str");
+ return NULL;
+ }
+ return PyString_FromString(output.c_str());
+}
+
+PyObject* MergeFrom(CMessage* self, PyObject* arg) {
+ CMessage* other_message;
+ if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Must be a message");
+ return NULL;
+ }
+
+ other_message = reinterpret_cast<CMessage*>(arg);
+ if (other_message->message->GetDescriptor() !=
+ self->message->GetDescriptor()) {
+ PyErr_Format(PyExc_TypeError,
+ "Tried to merge from a message with a different type. "
+ "to: %s, from: %s",
+ self->message->GetDescriptor()->full_name().c_str(),
+ other_message->message->GetDescriptor()->full_name().c_str());
+ return NULL;
+ }
+ AssureWritable(self);
+
+ // TODO(tibell): Message::MergeFrom might turn some child Messages
+ // into mutable messages, invalidating the message field in the
+ // corresponding CMessages. We should run a FixupMessageReferences
+ // pass here.
+
+ self->message->MergeFrom(*other_message->message);
+ Py_RETURN_NONE;
+}
+
+static PyObject* CopyFrom(CMessage* self, PyObject* arg) {
+ CMessage* other_message;
+ if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Must be a message");
+ return NULL;
+ }
+
+ other_message = reinterpret_cast<CMessage*>(arg);
+
+ if (self == other_message) {
+ Py_RETURN_NONE;
+ }
+
+ if (other_message->message->GetDescriptor() !=
+ self->message->GetDescriptor()) {
+ PyErr_Format(PyExc_TypeError,
+ "Tried to copy from a message with a different type. "
+ "to: %s, from: %s",
+ self->message->GetDescriptor()->full_name().c_str(),
+ other_message->message->GetDescriptor()->full_name().c_str());
+ return NULL;
+ }
+
+ AssureWritable(self);
+
+ // CopyFrom on the message will not clean up self->composite_fields,
+ // which can leave us in an inconsistent state, so clear it out here.
+ Clear(self);
+
+ self->message->CopyFrom(*other_message->message);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
+ const void* data;
+ Py_ssize_t data_length;
+ if (PyObject_AsReadBuffer(arg, &data, &data_length) < 0) {
+ return NULL;
+ }
+
+ AssureWritable(self);
+ io::CodedInputStream input(
+ reinterpret_cast<const uint8*>(data), data_length);
+ input.SetExtensionRegistry(GetDescriptorPool()->pool, message_factory);
+ bool success = self->message->MergePartialFromCodedStream(&input);
+ if (success) {
+ return PyInt_FromLong(input.CurrentPosition());
+ } else {
+ PyErr_Format(DecodeError_class, "Error parsing message");
+ return NULL;
+ }
+}
+
+static PyObject* ParseFromString(CMessage* self, PyObject* arg) {
+ if (Clear(self) == NULL) {
+ return NULL;
+ }
+ return MergeFromString(self, arg);
+}
+
+static PyObject* ByteSize(CMessage* self, PyObject* args) {
+ return PyLong_FromLong(self->message->ByteSize());
+}
+
+static PyObject* RegisterExtension(PyObject* cls,
+ PyObject* extension_handle) {
+ ScopedPyObjectPtr message_descriptor(PyObject_GetAttr(cls, kDESCRIPTOR));
+ if (message_descriptor == NULL) {
+ return NULL;
+ }
+
+ const FieldDescriptor* descriptor =
+ GetExtensionDescriptor(extension_handle);
+ if (descriptor == NULL) {
+ return NULL;
+ }
+ const Descriptor* cmessage_descriptor = GetMessageDescriptor(
+ reinterpret_cast<PyTypeObject*>(cls));
+
+ if (cmessage_descriptor != descriptor->containing_type()) {
+ if (PyObject_SetAttrString(extension_handle, "containing_type",
+ message_descriptor) < 0) {
+ return NULL;
+ }
+ }
+
+ ScopedPyObjectPtr extensions_by_name(
+ PyObject_GetAttr(cls, k_extensions_by_name));
+ if (extensions_by_name == NULL) {
+ PyErr_SetString(PyExc_TypeError, "no extensions_by_name on class");
+ return NULL;
+ }
+ ScopedPyObjectPtr full_name(PyObject_GetAttr(extension_handle, kfull_name));
+ if (full_name == NULL) {
+ return NULL;
+ }
+
+ // If the extension was already registered, check that it is the same.
+ PyObject* existing_extension = PyDict_GetItem(extensions_by_name, full_name);
+ if (existing_extension != NULL) {
+ const FieldDescriptor* existing_extension_descriptor =
+ GetExtensionDescriptor(existing_extension);
+ if (existing_extension_descriptor != descriptor) {
+ PyErr_SetString(PyExc_ValueError, "Double registration of Extensions");
+ return NULL;
+ }
+ // Nothing else to do.
+ Py_RETURN_NONE;
+ }
+
+ if (PyDict_SetItem(extensions_by_name, full_name, extension_handle) < 0) {
+ return NULL;
+ }
+
+ // Also store a mapping from extension number to implementing class.
+ ScopedPyObjectPtr extensions_by_number(
+ PyObject_GetAttr(cls, k_extensions_by_number));
+ if (extensions_by_number == NULL) {
+ PyErr_SetString(PyExc_TypeError, "no extensions_by_number on class");
+ return NULL;
+ }
+ ScopedPyObjectPtr number(PyObject_GetAttrString(extension_handle, "number"));
+ if (number == NULL) {
+ return NULL;
+ }
+ if (PyDict_SetItem(extensions_by_number, number, extension_handle) < 0) {
+ return NULL;
+ }
+
+ // Check if it's a message set
+ if (descriptor->is_extension() &&
+ descriptor->containing_type()->options().message_set_wire_format() &&
+ descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
+ descriptor->message_type() == descriptor->extension_scope() &&
+ descriptor->label() == FieldDescriptor::LABEL_OPTIONAL) {
+ ScopedPyObjectPtr message_name(PyString_FromStringAndSize(
+ descriptor->message_type()->full_name().c_str(),
+ descriptor->message_type()->full_name().size()));
+ if (message_name == NULL) {
+ return NULL;
+ }
+ PyDict_SetItem(extensions_by_name, message_name, extension_handle);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject* SetInParent(CMessage* self, PyObject* args) {
+ AssureWritable(self);
+ Py_RETURN_NONE;
+}
+
+static PyObject* WhichOneof(CMessage* self, PyObject* arg) {
+ Py_ssize_t name_size;
+ char *name_data;
+ if (PyString_AsStringAndSize(arg, &name_data, &name_size) < 0)
+ return NULL;
+ string oneof_name = string(name_data, name_size);
+ const OneofDescriptor* oneof_desc =
+ self->message->GetDescriptor()->FindOneofByName(oneof_name);
+ if (oneof_desc == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Protocol message has no oneof \"%s\" field.",
+ oneof_name.c_str());
+ return NULL;
+ }
+ const FieldDescriptor* field_in_oneof =
+ self->message->GetReflection()->GetOneofFieldDescriptor(
+ *self->message, oneof_desc);
+ if (field_in_oneof == NULL) {
+ Py_RETURN_NONE;
+ } else {
+ const string& name = field_in_oneof->name();
+ return PyString_FromStringAndSize(name.c_str(), name.size());
+ }
+}
+
+static PyObject* ListFields(CMessage* self) {
+ vector<const FieldDescriptor*> fields;
+ self->message->GetReflection()->ListFields(*self->message, &fields);
+
+ // Normally, the list will be exactly the size of the fields.
+ ScopedPyObjectPtr all_fields(PyList_New(fields.size()));
+ if (all_fields == NULL) {
+ return NULL;
+ }
+
+ // When there are unknown extensions, the py list will *not* contain
+ // the field information. Thus the actual size of the py list will be
+ // smaller than the size of fields. Set the actual size at the end.
+ Py_ssize_t actual_size = 0;
+ for (Py_ssize_t i = 0; i < fields.size(); ++i) {
+ ScopedPyObjectPtr t(PyTuple_New(2));
+ if (t == NULL) {
+ return NULL;
+ }
+
+ if (fields[i]->is_extension()) {
+ ScopedPyObjectPtr extension_field(PyFieldDescriptor_New(fields[i]));
+ if (extension_field == NULL) {
+ return NULL;
+ }
+ // With C++ descriptors, the field can always be retrieved, but for
+ // unknown extensions which have not been imported in Python code, there
+ // is no message class and we cannot retrieve the value.
+ // TODO(amauryfa): consider building the class on the fly!
+ if (fields[i]->message_type() != NULL &&
+ cdescriptor_pool::GetMessageClass(
+ GetDescriptorPool(), fields[i]->message_type()) == NULL) {
+ PyErr_Clear();
+ continue;
+ }
+ PyObject* extensions = reinterpret_cast<PyObject*>(self->extensions);
+ if (extensions == NULL) {
+ return NULL;
+ }
+ // 'extension' reference later stolen by PyTuple_SET_ITEM.
+ PyObject* extension = PyObject_GetItem(extensions, extension_field);
+ if (extension == NULL) {
+ return NULL;
+ }
+ PyTuple_SET_ITEM(t.get(), 0, extension_field.release());
+ // Steals reference to 'extension'
+ PyTuple_SET_ITEM(t.get(), 1, extension);
+ } else {
+ const string& field_name = fields[i]->name();
+ ScopedPyObjectPtr py_field_name(PyString_FromStringAndSize(
+ field_name.c_str(), field_name.length()));
+ if (py_field_name == NULL) {
+ PyErr_SetString(PyExc_ValueError, "bad string");
+ return NULL;
+ }
+ ScopedPyObjectPtr field_descriptor(PyFieldDescriptor_New(fields[i]));
+ if (field_descriptor == NULL) {
+ return NULL;
+ }
+
+ PyObject* field_value = GetAttr(self, py_field_name);
+ if (field_value == NULL) {
+ PyErr_SetObject(PyExc_ValueError, py_field_name);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(t.get(), 0, field_descriptor.release());
+ PyTuple_SET_ITEM(t.get(), 1, field_value);
+ }
+ PyList_SET_ITEM(all_fields.get(), actual_size, t.release());
+ ++actual_size;
+ }
+ Py_SIZE(all_fields.get()) = actual_size;
+ return all_fields.release();
+}
+
+PyObject* FindInitializationErrors(CMessage* self) {
+ Message* message = self->message;
+ vector<string> errors;
+ message->FindInitializationErrors(&errors);
+
+ PyObject* error_list = PyList_New(errors.size());
+ if (error_list == NULL) {
+ return NULL;
+ }
+ for (Py_ssize_t i = 0; i < errors.size(); ++i) {
+ const string& error = errors[i];
+ PyObject* error_string = PyString_FromStringAndSize(
+ error.c_str(), error.length());
+ if (error_string == NULL) {
+ Py_DECREF(error_list);
+ return NULL;
+ }
+ PyList_SET_ITEM(error_list, i, error_string);
+ }
+ return error_list;
+}
+
+static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) {
+ if (!PyObject_TypeCheck(other, &CMessage_Type)) {
+ if (opid == Py_EQ) {
+ Py_RETURN_FALSE;
+ } else if (opid == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+ }
+ if (opid == Py_EQ || opid == Py_NE) {
+ ScopedPyObjectPtr self_fields(ListFields(self));
+ if (!self_fields) {
+ return NULL;
+ }
+ ScopedPyObjectPtr other_fields(ListFields(
+ reinterpret_cast<CMessage*>(other)));
+ if (!other_fields) {
+ return NULL;
+ }
+ return PyObject_RichCompare(self_fields, other_fields, opid);
+ } else {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+}
+
+PyObject* InternalGetScalar(
+ CMessage* self,
+ const FieldDescriptor* field_descriptor) {
+ Message* message = self->message;
+ const Reflection* reflection = message->GetReflection();
+
+ if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
+ return NULL;
+ }
+
+ PyObject* result = NULL;
+ switch (field_descriptor->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: {
+ int32 value = reflection->GetInt32(*message, field_descriptor);
+ result = PyInt_FromLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_INT64: {
+ int64 value = reflection->GetInt64(*message, field_descriptor);
+ result = PyLong_FromLongLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT32: {
+ uint32 value = reflection->GetUInt32(*message, field_descriptor);
+ result = PyInt_FromSize_t(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ uint64 value = reflection->GetUInt64(*message, field_descriptor);
+ result = PyLong_FromUnsignedLongLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ float value = reflection->GetFloat(*message, field_descriptor);
+ result = PyFloat_FromDouble(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ double value = reflection->GetDouble(*message, field_descriptor);
+ result = PyFloat_FromDouble(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_BOOL: {
+ bool value = reflection->GetBool(*message, field_descriptor);
+ result = PyBool_FromLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING: {
+ string value = reflection->GetString(*message, field_descriptor);
+ result = ToStringObject(field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ if (!message->GetReflection()->SupportsUnknownEnumValues() &&
+ !message->GetReflection()->HasField(*message, field_descriptor)) {
+ // Look for the value in the unknown fields.
+ UnknownFieldSet* unknown_field_set =
+ message->GetReflection()->MutableUnknownFields(message);
+ for (int i = 0; i < unknown_field_set->field_count(); ++i) {
+ if (unknown_field_set->field(i).number() ==
+ field_descriptor->number()) {
+ result = PyInt_FromLong(unknown_field_set->field(i).varint());
+ break;
+ }
+ }
+ }
+
+ if (result == NULL) {
+ const EnumValueDescriptor* enum_value =
+ message->GetReflection()->GetEnum(*message, field_descriptor);
+ result = PyInt_FromLong(enum_value->number());
+ }
+ break;
+ }
+ default:
+ PyErr_Format(
+ PyExc_SystemError, "Getting a value from a field of unknown type %d",
+ field_descriptor->cpp_type());
+ }
+
+ return result;
+}
+
+PyObject* InternalGetSubMessage(
+ CMessage* self, const FieldDescriptor* field_descriptor) {
+ const Reflection* reflection = self->message->GetReflection();
+ const Message& sub_message = reflection->GetMessage(
+ *self->message, field_descriptor, message_factory);
+
+ PyObject *message_class = cdescriptor_pool::GetMessageClass(
+ GetDescriptorPool(), field_descriptor->message_type());
+ if (message_class == NULL) {
+ return NULL;
+ }
+
+ CMessage* cmsg = cmessage::NewEmptyMessage(message_class,
+ sub_message.GetDescriptor());
+ if (cmsg == NULL) {
+ return NULL;
+ }
+
+ cmsg->owner = self->owner;
+ cmsg->parent = self;
+ cmsg->parent_field_descriptor = field_descriptor;
+ cmsg->read_only = !reflection->HasField(*self->message, field_descriptor);
+ cmsg->message = const_cast<Message*>(&sub_message);
+
+ return reinterpret_cast<PyObject*>(cmsg);
+}
+
+int InternalSetScalar(
+ CMessage* self,
+ const FieldDescriptor* field_descriptor,
+ PyObject* arg) {
+ Message* message = self->message;
+ const Reflection* reflection = message->GetReflection();
+
+ if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
+ return -1;
+ }
+
+ if (MaybeReleaseOverlappingOneofField(self, field_descriptor) < 0) {
+ return -1;
+ }
+
+ switch (field_descriptor->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: {
+ GOOGLE_CHECK_GET_INT32(arg, value, -1);
+ reflection->SetInt32(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_INT64: {
+ GOOGLE_CHECK_GET_INT64(arg, value, -1);
+ reflection->SetInt64(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT32: {
+ GOOGLE_CHECK_GET_UINT32(arg, value, -1);
+ reflection->SetUInt32(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ GOOGLE_CHECK_GET_UINT64(arg, value, -1);
+ reflection->SetUInt64(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ GOOGLE_CHECK_GET_FLOAT(arg, value, -1);
+ reflection->SetFloat(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ GOOGLE_CHECK_GET_DOUBLE(arg, value, -1);
+ reflection->SetDouble(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_BOOL: {
+ GOOGLE_CHECK_GET_BOOL(arg, value, -1);
+ reflection->SetBool(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING: {
+ if (!CheckAndSetString(
+ arg, message, field_descriptor, reflection, false, -1)) {
+ return -1;
+ }
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ GOOGLE_CHECK_GET_INT32(arg, value, -1);
+ if (reflection->SupportsUnknownEnumValues()) {
+ reflection->SetEnumValue(message, field_descriptor, value);
+ } else {
+ const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+ const EnumValueDescriptor* enum_value =
+ enum_descriptor->FindValueByNumber(value);
+ if (enum_value != NULL) {
+ reflection->SetEnum(message, field_descriptor, enum_value);
+ } else {
+ PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value);
+ return -1;
+ }
+ }
+ break;
+ }
+ default:
+ PyErr_Format(
+ PyExc_SystemError, "Setting value to a field of unknown type %d",
+ field_descriptor->cpp_type());
+ return -1;
+ }
+
+ return 0;
+}
+
+PyObject* FromString(PyTypeObject* cls, PyObject* serialized) {
+ PyObject* py_cmsg = PyObject_CallObject(
+ reinterpret_cast<PyObject*>(cls), NULL);
+ if (py_cmsg == NULL) {
+ return NULL;
+ }
+ CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
+
+ ScopedPyObjectPtr py_length(MergeFromString(cmsg, serialized));
+ if (py_length == NULL) {
+ Py_DECREF(py_cmsg);
+ return NULL;
+ }
+
+ return py_cmsg;
+}
+
+// Add the number of a field descriptor to the containing message class.
+// Equivalent to:
+// _cls.<field>_FIELD_NUMBER = <number>
+static bool AddFieldNumberToClass(
+ PyObject* cls, const FieldDescriptor* field_descriptor) {
+ string constant_name = field_descriptor->name() + "_FIELD_NUMBER";
+ UpperString(&constant_name);
+ ScopedPyObjectPtr attr_name(PyString_FromStringAndSize(
+ constant_name.c_str(), constant_name.size()));
+ if (attr_name == NULL) {
+ return false;
+ }
+ ScopedPyObjectPtr number(PyInt_FromLong(field_descriptor->number()));
+ if (number == NULL) {
+ return false;
+ }
+ if (PyObject_SetAttr(cls, attr_name, number) == -1) {
+ return false;
+ }
+ return true;
+}
+
+
+// Finalize the creation of the Message class.
+// Called from its metaclass: GeneratedProtocolMessageType.__init__().
+static PyObject* AddDescriptors(PyObject* cls, PyObject* descriptor) {
+ const Descriptor* message_descriptor =
+ cdescriptor_pool::RegisterMessageClass(
+ GetDescriptorPool(), cls, descriptor);
+ if (message_descriptor == NULL) {
+ return NULL;
+ }
+
+ // 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(cls, k_extensions_by_name, by_name) < 0) {
+ return NULL;
+ }
+ ScopedPyObjectPtr by_number(PyDict_New());
+ if (PyObject_SetAttr(cls, k_extensions_by_number, by_number) < 0) {
+ return NULL;
+ }
+ }
+
+ // For each field set: cls.<field>_FIELD_NUMBER = <number>
+ for (int i = 0; i < message_descriptor->field_count(); ++i) {
+ if (!AddFieldNumberToClass(cls, message_descriptor->field(i))) {
+ return NULL;
+ }
+ }
+
+ // For each enum set cls.<enum name> = EnumTypeWrapper(<enum descriptor>).
+ //
+ // The enum descriptor we get from
+ // <messagedescriptor>.enum_types_by_name[name]
+ // which was built previously.
+ for (int i = 0; i < message_descriptor->enum_type_count(); ++i) {
+ const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i);
+ ScopedPyObjectPtr enum_type(PyEnumDescriptor_New(enum_descriptor));
+ if (enum_type == NULL) {
+ return NULL;
+ }
+ // Add wrapped enum type to message class.
+ ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs(
+ EnumTypeWrapper_class, enum_type.get(), NULL));
+ if (wrapped == NULL) {
+ return NULL;
+ }
+ if (PyObject_SetAttrString(
+ cls, enum_descriptor->name().c_str(), wrapped) == -1) {
+ return NULL;
+ }
+
+ // For each enum value add cls.<name> = <number>
+ for (int j = 0; j < enum_descriptor->value_count(); ++j) {
+ const EnumValueDescriptor* enum_value_descriptor =
+ enum_descriptor->value(j);
+ ScopedPyObjectPtr value_number(PyInt_FromLong(
+ enum_value_descriptor->number()));
+ if (value_number == NULL) {
+ return NULL;
+ }
+ if (PyObject_SetAttrString(
+ cls, enum_value_descriptor->name().c_str(), value_number) == -1) {
+ return NULL;
+ }
+ }
+ }
+
+ // For each extension set cls.<extension name> = <extension descriptor>.
+ //
+ // Extension descriptors come from
+ // <message descriptor>.extensions_by_name[name]
+ // which was defined previously.
+ for (int i = 0; i < message_descriptor->extension_count(); ++i) {
+ const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i);
+ ScopedPyObjectPtr extension_field(PyFieldDescriptor_New(field));
+ if (extension_field == NULL) {
+ return NULL;
+ }
+
+ // Add the extension field to the message class.
+ if (PyObject_SetAttrString(
+ cls, field->name().c_str(), extension_field) == -1) {
+ return NULL;
+ }
+
+ // For each extension set cls.<extension name>_FIELD_NUMBER = <number>.
+ if (!AddFieldNumberToClass(cls, field)) {
+ return NULL;
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+PyObject* DeepCopy(CMessage* self, PyObject* arg) {
+ PyObject* clone = PyObject_CallObject(
+ reinterpret_cast<PyObject*>(Py_TYPE(self)), NULL);
+ if (clone == NULL) {
+ return NULL;
+ }
+ if (!PyObject_TypeCheck(clone, &CMessage_Type)) {
+ Py_DECREF(clone);
+ return NULL;
+ }
+ if (MergeFrom(reinterpret_cast<CMessage*>(clone),
+ reinterpret_cast<PyObject*>(self)) == NULL) {
+ Py_DECREF(clone);
+ return NULL;
+ }
+ return clone;
+}
+
+PyObject* ToUnicode(CMessage* self) {
+ // Lazy import to prevent circular dependencies
+ ScopedPyObjectPtr text_format(
+ PyImport_ImportModule("google.protobuf.text_format"));
+ if (text_format == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr method_name(PyString_FromString("MessageToString"));
+ if (method_name == NULL) {
+ return NULL;
+ }
+ Py_INCREF(Py_True);
+ ScopedPyObjectPtr encoded(PyObject_CallMethodObjArgs(text_format, method_name,
+ self, Py_True, NULL));
+ Py_DECREF(Py_True);
+ if (encoded == NULL) {
+ return NULL;
+ }
+#if PY_MAJOR_VERSION < 3
+ PyObject* decoded = PyString_AsDecodedObject(encoded, "utf-8", NULL);
+#else
+ PyObject* decoded = PyUnicode_FromEncodedObject(encoded, "utf-8", NULL);
+#endif
+ if (decoded == NULL) {
+ return NULL;
+ }
+ return decoded;
+}
+
+PyObject* Reduce(CMessage* self) {
+ ScopedPyObjectPtr constructor(reinterpret_cast<PyObject*>(Py_TYPE(self)));
+ constructor.inc();
+ ScopedPyObjectPtr args(PyTuple_New(0));
+ if (args == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr state(PyDict_New());
+ if (state == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr serialized(SerializePartialToString(self));
+ if (serialized == NULL) {
+ return NULL;
+ }
+ if (PyDict_SetItemString(state, "serialized", serialized) < 0) {
+ return NULL;
+ }
+ return Py_BuildValue("OOO", constructor.get(), args.get(), state.get());
+}
+
+PyObject* SetState(CMessage* self, PyObject* state) {
+ if (!PyDict_Check(state)) {
+ PyErr_SetString(PyExc_TypeError, "state not a dict");
+ return NULL;
+ }
+ PyObject* serialized = PyDict_GetItemString(state, "serialized");
+ if (serialized == NULL) {
+ return NULL;
+ }
+ if (ParseFromString(self, serialized) == NULL) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+// CMessage static methods:
+PyObject* _GetMessageDescriptor(PyObject* unused, PyObject* arg) {
+ return cdescriptor_pool::FindMessageByName(GetDescriptorPool(), arg);
+}
+
+PyObject* _GetFieldDescriptor(PyObject* unused, PyObject* arg) {
+ return cdescriptor_pool::FindFieldByName(GetDescriptorPool(), arg);
+}
+
+PyObject* _GetExtensionDescriptor(PyObject* unused, PyObject* arg) {
+ return cdescriptor_pool::FindExtensionByName(GetDescriptorPool(), arg);
+}
+
+PyObject* _GetEnumDescriptor(PyObject* unused, PyObject* arg) {
+ return cdescriptor_pool::FindEnumTypeByName(GetDescriptorPool(), arg);
+}
+
+PyObject* _GetOneofDescriptor(PyObject* unused, PyObject* arg) {
+ return cdescriptor_pool::FindOneofByName(GetDescriptorPool(), arg);
+}
+
+PyObject* _CheckCalledFromGeneratedFile(PyObject* unused,
+ PyObject* unused_arg) {
+ if (!_CalledFromGeneratedFile(1)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Descriptors should not be created directly, "
+ "but only retrieved from their parent.");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyMemberDef Members[] = {
+ {"Extensions", T_OBJECT_EX, offsetof(CMessage, extensions), 0,
+ "Extension dict"},
+ {NULL}
+};
+
+static PyMethodDef Methods[] = {
+ { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+ "Makes a deep copy of the class." },
+ { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+ "Outputs picklable representation of the message." },
+ { "__setstate__", (PyCFunction)SetState, METH_O,
+ "Inputs picklable representation of the message." },
+ { "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
+ "Outputs a unicode representation of the message." },
+ { "AddDescriptors", (PyCFunction)AddDescriptors, METH_O | METH_CLASS,
+ "Adds field descriptors to the class" },
+ { "ByteSize", (PyCFunction)ByteSize, METH_NOARGS,
+ "Returns the size of the message in bytes." },
+ { "Clear", (PyCFunction)Clear, METH_NOARGS,
+ "Clears the message." },
+ { "ClearExtension", (PyCFunction)ClearExtension, METH_O,
+ "Clears a message field." },
+ { "ClearField", (PyCFunction)ClearField, METH_O,
+ "Clears a message field." },
+ { "CopyFrom", (PyCFunction)CopyFrom, METH_O,
+ "Copies a protocol message into the current message." },
+ { "FindInitializationErrors", (PyCFunction)FindInitializationErrors,
+ METH_NOARGS,
+ "Finds unset required fields." },
+ { "FromString", (PyCFunction)FromString, METH_O | METH_CLASS,
+ "Creates new method instance from given serialized data." },
+ { "HasExtension", (PyCFunction)HasExtension, METH_O,
+ "Checks if a message field is set." },
+ { "HasField", (PyCFunction)HasField, METH_O,
+ "Checks if a message field is set." },
+ { "IsInitialized", (PyCFunction)IsInitialized, METH_VARARGS,
+ "Checks if all required fields of a protocol message are set." },
+ { "ListFields", (PyCFunction)ListFields, METH_NOARGS,
+ "Lists all set fields of a message." },
+ { "MergeFrom", (PyCFunction)MergeFrom, METH_O,
+ "Merges a protocol message into the current message." },
+ { "MergeFromString", (PyCFunction)MergeFromString, METH_O,
+ "Merges a serialized message into the current message." },
+ { "ParseFromString", (PyCFunction)ParseFromString, METH_O,
+ "Parses a serialized message into the current message." },
+ { "RegisterExtension", (PyCFunction)RegisterExtension, METH_O | METH_CLASS,
+ "Registers an extension with the current message." },
+ { "SerializePartialToString", (PyCFunction)SerializePartialToString,
+ METH_NOARGS,
+ "Serializes the message to a string, even if it isn't initialized." },
+ { "SerializeToString", (PyCFunction)SerializeToString, METH_NOARGS,
+ "Serializes the message to a string, only for initialized messages." },
+ { "SetInParent", (PyCFunction)SetInParent, METH_NOARGS,
+ "Sets the has bit of the given field in its parent message." },
+ { "WhichOneof", (PyCFunction)WhichOneof, METH_O,
+ "Returns the name of the field set inside a oneof, "
+ "or None if no field is set." },
+
+ // Static Methods.
+ { "_BuildFile", (PyCFunction)Python_BuildFile, METH_O | METH_STATIC,
+ "Registers a new protocol buffer file in the global C++ descriptor pool." },
+ { "_GetMessageDescriptor", (PyCFunction)_GetMessageDescriptor,
+ METH_O | METH_STATIC, "Finds a message descriptor in the message pool." },
+ { "_GetFieldDescriptor", (PyCFunction)_GetFieldDescriptor,
+ METH_O | METH_STATIC, "Finds a field descriptor in the message pool." },
+ { "_GetExtensionDescriptor", (PyCFunction)_GetExtensionDescriptor,
+ METH_O | METH_STATIC,
+ "Finds a extension descriptor in the message pool." },
+ { "_GetEnumDescriptor", (PyCFunction)_GetEnumDescriptor,
+ METH_O | METH_STATIC,
+ "Finds an enum descriptor in the message pool." },
+ { "_GetOneofDescriptor", (PyCFunction)_GetOneofDescriptor,
+ METH_O | METH_STATIC,
+ "Finds an oneof descriptor in the message pool." },
+ { "_CheckCalledFromGeneratedFile", (PyCFunction)_CheckCalledFromGeneratedFile,
+ METH_NOARGS | METH_STATIC,
+ "Raises TypeError if the caller is not in a _pb2.py file."},
+ { NULL, NULL}
+};
+
+static bool SetCompositeField(
+ CMessage* self, PyObject* name, PyObject* value) {
+ if (self->composite_fields == NULL) {
+ self->composite_fields = PyDict_New();
+ if (self->composite_fields == NULL) {
+ return false;
+ }
+ }
+ return PyDict_SetItem(self->composite_fields, name, value) == 0;
+}
+
+PyObject* GetAttr(CMessage* self, PyObject* name) {
+ PyObject* value = self->composite_fields ?
+ PyDict_GetItem(self->composite_fields, name) : NULL;
+ if (value != NULL) {
+ Py_INCREF(value);
+ return value;
+ }
+
+ const FieldDescriptor* field_descriptor = GetFieldDescriptor(self, name);
+ if (field_descriptor == NULL) {
+ return CMessage_Type.tp_base->tp_getattro(
+ reinterpret_cast<PyObject*>(self), name);
+ }
+
+ if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+ PyObject* py_container = NULL;
+ if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ PyObject *message_class = cdescriptor_pool::GetMessageClass(
+ GetDescriptorPool(), field_descriptor->message_type());
+ if (message_class == NULL) {
+ return NULL;
+ }
+ py_container = repeated_composite_container::NewContainer(
+ self, field_descriptor, message_class);
+ } else {
+ py_container = repeated_scalar_container::NewContainer(
+ self, field_descriptor);
+ }
+ if (py_container == NULL) {
+ return NULL;
+ }
+ if (!SetCompositeField(self, name, py_container)) {
+ Py_DECREF(py_container);
+ return NULL;
+ }
+ return py_container;
+ }
+
+ if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ PyObject* sub_message = InternalGetSubMessage(self, field_descriptor);
+ if (!SetCompositeField(self, name, sub_message)) {
+ Py_DECREF(sub_message);
+ return NULL;
+ }
+ return sub_message;
+ }
+
+ return InternalGetScalar(self, field_descriptor);
+}
+
+int SetAttr(CMessage* self, PyObject* name, PyObject* value) {
+ if (self->composite_fields && PyDict_Contains(self->composite_fields, name)) {
+ PyErr_SetString(PyExc_TypeError, "Can't set composite field");
+ return -1;
+ }
+
+ const FieldDescriptor* field_descriptor = GetFieldDescriptor(self, name);
+ if (field_descriptor != NULL) {
+ AssureWritable(self);
+ if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+ PyErr_Format(PyExc_AttributeError, "Assignment not allowed to repeated "
+ "field \"%s\" in protocol message object.",
+ field_descriptor->name().c_str());
+ return -1;
+ } else {
+ if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ PyErr_Format(PyExc_AttributeError, "Assignment not allowed to "
+ "field \"%s\" in protocol message object.",
+ field_descriptor->name().c_str());
+ return -1;
+ } else {
+ return InternalSetScalar(self, field_descriptor, value);
+ }
+ }
+ }
+
+ PyErr_Format(PyExc_AttributeError, "Assignment not allowed");
+ return -1;
+}
+
+} // namespace cmessage
+
+PyTypeObject CMessage_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ // Keep the fully qualified _message symbol in a line for opensource.
+ "google.protobuf.pyext._message."
+ "CMessage", // tp_name
+ sizeof(CMessage), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)cmessage::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
+ (reprfunc)cmessage::ToStr, // tp_str
+ (getattrofunc)cmessage::GetAttr, // tp_getattro
+ (setattrofunc)cmessage::SetAttr, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
+ "A ProtocolMessage", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ (richcmpfunc)cmessage::RichCompare, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ cmessage::Methods, // tp_methods
+ cmessage::Members, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)cmessage::Init, // tp_init
+ 0, // tp_alloc
+ cmessage::New, // tp_new
+};
+
+// --- Exposing the C proto living inside Python proto to C code:
+
+const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg);
+Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg);
+
+static const Message* GetCProtoInsidePyProtoImpl(PyObject* msg) {
+ if (!PyObject_TypeCheck(msg, &CMessage_Type)) {
+ return NULL;
+ }
+ CMessage* cmsg = reinterpret_cast<CMessage*>(msg);
+ return cmsg->message;
+}
+
+static Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
+ if (!PyObject_TypeCheck(msg, &CMessage_Type)) {
+ return NULL;
+ }
+ CMessage* cmsg = reinterpret_cast<CMessage*>(msg);
+ if ((cmsg->composite_fields && PyDict_Size(cmsg->composite_fields) != 0) ||
+ (cmsg->extensions != NULL &&
+ PyDict_Size(cmsg->extensions->values) != 0)) {
+ // There is currently no way of accurately syncing arbitrary changes to
+ // the underlying C++ message back to the CMessage (e.g. removed repeated
+ // composite containers). We only allow direct mutation of the underlying
+ // C++ message if there is no child data in the CMessage.
+ return NULL;
+ }
+ cmessage::AssureWritable(cmsg);
+ return cmsg->message;
+}
+
+static const char module_docstring[] =
+"python-proto2 is a module that can be used to enhance proto2 Python API\n"
+"performance.\n"
+"\n"
+"It provides access to the protocol buffers C++ reflection API that\n"
+"implements the basic protocol buffer functions.";
+
+void InitGlobals() {
+ // TODO(gps): Check all return values in this function for NULL and propagate
+ // the error (MemoryError) on up to result in an import failure. These should
+ // also be freed and reset to NULL during finalization.
+ kPythonZero = PyInt_FromLong(0);
+ kint32min_py = PyInt_FromLong(kint32min);
+ kint32max_py = PyInt_FromLong(kint32max);
+ kuint32max_py = PyLong_FromLongLong(kuint32max);
+ kint64min_py = PyLong_FromLongLong(kint64min);
+ kint64max_py = PyLong_FromLongLong(kint64max);
+ kuint64max_py = PyLong_FromUnsignedLongLong(kuint64max);
+
+ kDESCRIPTOR = PyString_FromString("DESCRIPTOR");
+ k_cdescriptor = PyString_FromString("_cdescriptor");
+ kfull_name = PyString_FromString("full_name");
+ k_extensions_by_name = PyString_FromString("_extensions_by_name");
+ k_extensions_by_number = PyString_FromString("_extensions_by_number");
+
+ message_factory = new DynamicMessageFactory(GetDescriptorPool()->pool);
+ message_factory->SetDelegateToGeneratedFactory(true);
+}
+
+bool InitProto2MessageModule(PyObject *m) {
+ // Initialize types and globals in descriptor.cc
+ if (!InitDescriptor()) {
+ return false;
+ }
+
+ // Initialize types and globals in descriptor_pool.cc
+ if (!InitDescriptorPool()) {
+ return false;
+ }
+
+ // Initialize constants defined in this file.
+ InitGlobals();
+
+ CMessage_Type.tp_hash = PyObject_HashNotImplemented;
+ if (PyType_Ready(&CMessage_Type) < 0) {
+ return false;
+ }
+
+ // 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(CMessage_Type.tp_dict, kDESCRIPTOR, 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(CMessage_Type.tp_dict,
+ k_extensions_by_name, immutable_dict) < 0) {
+ return false;
+ }
+ if (PyDict_SetItem(CMessage_Type.tp_dict,
+ k_extensions_by_number, immutable_dict) < 0) {
+ return false;
+ }
+
+ PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>(&CMessage_Type));
+
+ RepeatedScalarContainer_Type.tp_hash =
+ PyObject_HashNotImplemented;
+ if (PyType_Ready(&RepeatedScalarContainer_Type) < 0) {
+ return false;
+ }
+
+ PyModule_AddObject(m, "RepeatedScalarContainer",
+ reinterpret_cast<PyObject*>(
+ &RepeatedScalarContainer_Type));
+
+ RepeatedCompositeContainer_Type.tp_hash = PyObject_HashNotImplemented;
+ if (PyType_Ready(&RepeatedCompositeContainer_Type) < 0) {
+ return false;
+ }
+
+ PyModule_AddObject(
+ m, "RepeatedCompositeContainer",
+ reinterpret_cast<PyObject*>(
+ &RepeatedCompositeContainer_Type));
+
+ ExtensionDict_Type.tp_hash = PyObject_HashNotImplemented;
+ if (PyType_Ready(&ExtensionDict_Type) < 0) {
+ return false;
+ }
+
+ PyModule_AddObject(
+ m, "ExtensionDict",
+ reinterpret_cast<PyObject*>(&ExtensionDict_Type));
+
+ // This implementation provides full Descriptor types, we advertise it so that
+ // descriptor.py can use them in replacement of the Python classes.
+ PyModule_AddIntConstant(m, "_USE_C_DESCRIPTORS", 1);
+
+ PyModule_AddObject(m, "Descriptor", reinterpret_cast<PyObject*>(
+ &PyMessageDescriptor_Type));
+ PyModule_AddObject(m, "FieldDescriptor", reinterpret_cast<PyObject*>(
+ &PyFieldDescriptor_Type));
+ PyModule_AddObject(m, "EnumDescriptor", reinterpret_cast<PyObject*>(
+ &PyEnumDescriptor_Type));
+ PyModule_AddObject(m, "EnumValueDescriptor", reinterpret_cast<PyObject*>(
+ &PyEnumValueDescriptor_Type));
+ PyModule_AddObject(m, "FileDescriptor", reinterpret_cast<PyObject*>(
+ &PyFileDescriptor_Type));
+ PyModule_AddObject(m, "OneofDescriptor", reinterpret_cast<PyObject*>(
+ &PyOneofDescriptor_Type));
+
+ PyObject* enum_type_wrapper = PyImport_ImportModule(
+ "google.protobuf.internal.enum_type_wrapper");
+ if (enum_type_wrapper == NULL) {
+ return false;
+ }
+ EnumTypeWrapper_class =
+ PyObject_GetAttrString(enum_type_wrapper, "EnumTypeWrapper");
+ Py_DECREF(enum_type_wrapper);
+
+ PyObject* message_module = PyImport_ImportModule(
+ "google.protobuf.message");
+ if (message_module == NULL) {
+ return false;
+ }
+ EncodeError_class = PyObject_GetAttrString(message_module, "EncodeError");
+ DecodeError_class = PyObject_GetAttrString(message_module, "DecodeError");
+ Py_DECREF(message_module);
+
+ PyObject* pickle_module = PyImport_ImportModule("pickle");
+ if (pickle_module == NULL) {
+ return false;
+ }
+ PickleError_class = PyObject_GetAttrString(pickle_module, "PickleError");
+ Py_DECREF(pickle_module);
+
+ // Override {Get,Mutable}CProtoInsidePyProto.
+ GetCProtoInsidePyProtoPtr = GetCProtoInsidePyProtoImpl;
+ MutableCProtoInsidePyProtoPtr = MutableCProtoInsidePyProtoImpl;
+
+ return true;
+}
+
+} // namespace python
+} // namespace protobuf
+
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef _module = {
+ PyModuleDef_HEAD_INIT,
+ "_message",
+ google::protobuf::python::module_docstring,
+ -1,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#define INITFUNC PyInit__message
+#define INITFUNC_ERRORVAL NULL
+#else // Python 2
+#define INITFUNC init_message
+#define INITFUNC_ERRORVAL
+#endif
+
+extern "C" {
+ PyMODINIT_FUNC INITFUNC(void) {
+ PyObject* m;
+#if PY_MAJOR_VERSION >= 3
+ m = PyModule_Create(&_module);
+#else
+ m = Py_InitModule3("_message", NULL, google::protobuf::python::module_docstring);
+#endif
+ if (m == NULL) {
+ return INITFUNC_ERRORVAL;
+ }
+
+ if (!google::protobuf::python::InitProto2MessageModule(m)) {
+ Py_DECREF(m);
+ return INITFUNC_ERRORVAL;
+ }
+
+#if PY_MAJOR_VERSION >= 3
+ return m;
+#endif
+ }
+}
+} // namespace google
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
new file mode 100644
index 00000000..2f2da795
--- /dev/null
+++ b/python/google/protobuf/pyext/message.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.
+
+// Author: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__
+
+#include <Python.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class Reflection;
+class FieldDescriptor;
+class Descriptor;
+class DynamicMessageFactory;
+
+using internal::shared_ptr;
+
+namespace python {
+
+struct ExtensionDict;
+
+typedef struct CMessage {
+ PyObject_HEAD;
+
+ // This is the top-level C++ Message object that owns the whole
+ // proto tree. Every Python CMessage 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<Message> owner;
+
+ // Weak reference to a parent CMessage object. This is NULL for any top-level
+ // message and is set for any child message (i.e. a child submessage or a
+ // part of a repeated composite field).
+ //
+ // Used to make sure all ancestors are also mutable when first modifying
+ // a child submessage (in other words, turning a default message instance
+ // into a mutable one).
+ //
+ // If a submessage is released (becomes a new top-level message), this field
+ // MUST be set to NULL. The parent may get deallocated and further attempts
+ // to use this pointer will result in a crash.
+ struct CMessage* parent;
+
+ // Pointer to the parent's descriptor that describes this submessage.
+ // Used together with the parent's message when making a default message
+ // instance mutable.
+ // The pointer is owned by the global DescriptorPool.
+ const FieldDescriptor* parent_field_descriptor;
+
+ // Pointer to the C++ Message object for this CMessage. The
+ // CMessage does not own this pointer.
+ Message* message;
+
+ // Indicates this submessage is pointing to a default instance of a message.
+ // Submessages are always first created as read only messages and are then
+ // made writable, at which point this field is set to false.
+ bool read_only;
+
+ // A reference to a Python dictionary containing CMessage,
+ // RepeatedCompositeContainer, and RepeatedScalarContainer
+ // objects. Used as a cache to make sure we don't have to make a
+ // Python wrapper for the C++ Message objects on every access, or
+ // deal with the synchronization nightmare that could create.
+ PyObject* composite_fields;
+
+ // A reference to the dictionary containing the message's extensions.
+ // Similar to composite_fields, acting as a cache, but also contains the
+ // required extension dict logic.
+ ExtensionDict* extensions;
+} CMessage;
+
+extern PyTypeObject CMessage_Type;
+
+namespace cmessage {
+
+// 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 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.
+//
+// Corresponds to reflection api method ReleaseMessage.
+int ReleaseSubMessage(Message* message,
+ const FieldDescriptor* field_descriptor,
+ CMessage* child_cmessage);
+
+// Retrieves the C++ descriptor of a Python Extension descriptor.
+// On error, return NULL with an exception set.
+const 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, const FieldDescriptor* field_descriptor);
+
+// Deletes a range of C++ submessages in a repeated field (following a
+// removal in a RepeatedCompositeContainer).
+//
+// Releases messages to the provided cmessage_list if it is not NULL rather
+// than just removing them from the underlying proto. This cmessage_list must
+// have a CMessage for each underlying submessage. The CMessages referred to
+// by slice will be removed from cmessage_list by this function.
+//
+// Corresponds to reflection api method RemoveLast.
+int InternalDeleteRepeatedField(Message* message,
+ const FieldDescriptor* field_descriptor,
+ PyObject* slice, PyObject* cmessage_list);
+
+// Sets the specified scalar value to the message.
+int InternalSetScalar(CMessage* self,
+ const FieldDescriptor* field_descriptor,
+ PyObject* value);
+
+// Retrieves the specified scalar value from the message.
+//
+// Returns a new python reference.
+PyObject* InternalGetScalar(CMessage* self,
+ const FieldDescriptor* field_descriptor);
+
+// Clears the message, removing all contained data. Extension dictionary and
+// submessages are released first if there are remaining external references.
+//
+// Corresponds to message api method Clear.
+PyObject* Clear(CMessage* self);
+
+// Clears the data described by the given descriptor. Used to clear extensions
+// (which don't have names). Extension release is handled by ExtensionDict
+// class, not this function.
+// TODO(anuraag): Try to make this discrepancy in release semantics with
+// ClearField less confusing.
+//
+// Corresponds to reflection api method ClearField.
+PyObject* ClearFieldByDescriptor(
+ CMessage* self, const FieldDescriptor* descriptor);
+
+// Clears the data for the given field name. The message is released if there
+// are any external references.
+//
+// Corresponds to reflection api method ClearField.
+PyObject* ClearField(CMessage* self, PyObject* arg);
+
+// Checks if the message has the field described by the descriptor. Used for
+// extensions (which have no name).
+//
+// Corresponds to reflection api method HasField
+PyObject* HasFieldByDescriptor(
+ CMessage* self, const FieldDescriptor* field_descriptor);
+
+// Checks if the message has the named field.
+//
+// Corresponds to reflection api method HasField.
+PyObject* HasField(CMessage* self, PyObject* arg);
+
+// Initializes values of fields on a newly constructed message.
+int InitAttributes(CMessage* self, PyObject* kwargs);
+
+PyObject* MergeFrom(CMessage* self, PyObject* arg);
+
+// Retrieves an attribute named 'name' from CMessage 'self'. Returns
+// the attribute value on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* GetAttr(CMessage* self, PyObject* name);
+
+// Set the value of the attribute named 'name', for CMessage 'self',
+// to the value 'value'. Returns -1 on failure.
+int SetAttr(CMessage* self, PyObject* name, PyObject* value);
+
+PyObject* FindInitializationErrors(CMessage* self);
+
+// Set the owner field of self and any children of self, recursively.
+// Used when self is being released and thus has a new owner (the
+// released Message.)
+int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner);
+
+int AssureWritable(CMessage* self);
+
+DynamicMessageFactory* GetMessageFactory();
+
+} // namespace cmessage
+
+
+/* Is 64bit */
+#define IS_64BIT (SIZEOF_LONG == 8)
+
+#define FIELD_IS_REPEATED(field_descriptor) \
+ ((field_descriptor)->label() == FieldDescriptor::LABEL_REPEATED)
+
+#define GOOGLE_CHECK_GET_INT32(arg, value, err) \
+ int32 value; \
+ if (!CheckAndGetInteger(arg, &value, kint32min_py, kint32max_py)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_INT64(arg, value, err) \
+ int64 value; \
+ if (!CheckAndGetInteger(arg, &value, kint64min_py, kint64max_py)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_UINT32(arg, value, err) \
+ uint32 value; \
+ if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint32max_py)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_UINT64(arg, value, err) \
+ uint64 value; \
+ if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint64max_py)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_FLOAT(arg, value, err) \
+ float value; \
+ if (!CheckAndGetFloat(arg, &value)) { \
+ return err; \
+ } \
+
+#define GOOGLE_CHECK_GET_DOUBLE(arg, value, err) \
+ double value; \
+ if (!CheckAndGetDouble(arg, &value)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_BOOL(arg, value, err) \
+ bool value; \
+ if (!CheckAndGetBool(arg, &value)) { \
+ return err; \
+ }
+
+
+extern PyObject* kPythonZero;
+extern PyObject* kint32min_py;
+extern PyObject* kint32max_py;
+extern PyObject* kuint32max_py;
+extern PyObject* kint64min_py;
+extern PyObject* kint64max_py;
+extern PyObject* kuint64max_py;
+
+#define C(str) const_cast<char*>(str)
+
+void FormatTypeError(PyObject* arg, char* expected_types);
+template<class T>
+bool CheckAndGetInteger(
+ PyObject* arg, T* value, PyObject* min, PyObject* max);
+bool CheckAndGetDouble(PyObject* arg, double* value);
+bool CheckAndGetFloat(PyObject* arg, float* value);
+bool CheckAndGetBool(PyObject* arg, bool* value);
+bool CheckAndSetString(
+ PyObject* arg, Message* message,
+ const FieldDescriptor* descriptor,
+ const Reflection* reflection,
+ bool append,
+ int index);
+PyObject* ToStringObject(const 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 FieldDescriptor* field_descriptor,
+ const Message* message);
+
+extern PyObject* PickleError_class;
+
+} // namespace python
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__
diff --git a/python/google/protobuf/pyext/proto2_api_test.proto b/python/google/protobuf/pyext/proto2_api_test.proto
new file mode 100644
index 00000000..18aecfb7
--- /dev/null
+++ b/python/google/protobuf/pyext/proto2_api_test.proto
@@ -0,0 +1,40 @@
+// 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/internal/cpp/proto1_api_test.proto";
+
+package google.protobuf.python.internal;
+
+message TestNestedProto1APIMessage {
+ optional int32 a = 1;
+ optional TestMessage.NestedMessage b = 2;
+}
diff --git a/python/google/protobuf/pyext/python-proto2.cc b/python/google/protobuf/pyext/python-proto2.cc
deleted file mode 100644
index f2799e62..00000000
--- a/python/google/protobuf/pyext/python-proto2.cc
+++ /dev/null
@@ -1,1658 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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: petar@google.com (Petar Petrov)
-
-#include <Python.h>
-#include <map>
-#include <string>
-#include <vector>
-
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/pyext/python_descriptor.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/dynamic_message.h>
-#include <google/protobuf/message.h>
-#include <google/protobuf/unknown_field_set.h>
-#include <google/protobuf/pyext/python_protobuf.h>
-
-/* 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)
-
-#define GOOGLE_CHECK_GET_INT32(arg, value) \
- int32 value; \
- if (!CheckAndGetInteger(arg, &value, kint32min_py, kint32max_py)) { \
- return NULL; \
- }
-
-#define GOOGLE_CHECK_GET_INT64(arg, value) \
- int64 value; \
- if (!CheckAndGetInteger(arg, &value, kint64min_py, kint64max_py)) { \
- return NULL; \
- }
-
-#define GOOGLE_CHECK_GET_UINT32(arg, value) \
- uint32 value; \
- if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint32max_py)) { \
- return NULL; \
- }
-
-#define GOOGLE_CHECK_GET_UINT64(arg, value) \
- uint64 value; \
- if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint64max_py)) { \
- return NULL; \
- }
-
-#define GOOGLE_CHECK_GET_FLOAT(arg, value) \
- float value; \
- if (!CheckAndGetFloat(arg, &value)) { \
- return NULL; \
- } \
-
-#define GOOGLE_CHECK_GET_DOUBLE(arg, value) \
- double value; \
- if (!CheckAndGetDouble(arg, &value)) { \
- return NULL; \
- }
-
-#define GOOGLE_CHECK_GET_BOOL(arg, value) \
- bool value; \
- if (!CheckAndGetBool(arg, &value)) { \
- return NULL; \
- }
-
-#define C(str) const_cast<char*>(str)
-
-// --- Globals:
-
-// Constants used for integer type range checking.
-static PyObject* kPythonZero;
-static PyObject* kint32min_py;
-static PyObject* kint32max_py;
-static PyObject* kuint32max_py;
-static PyObject* kint64min_py;
-static PyObject* kint64max_py;
-static PyObject* kuint64max_py;
-
-namespace google {
-namespace protobuf {
-namespace python {
-
-// --- Support Routines:
-
-static void AddConstants(PyObject* module) {
- struct NameValue {
- char* name;
- int32 value;
- } constants[] = {
- // Labels:
- {"LABEL_OPTIONAL", google::protobuf::FieldDescriptor::LABEL_OPTIONAL},
- {"LABEL_REQUIRED", google::protobuf::FieldDescriptor::LABEL_REQUIRED},
- {"LABEL_REPEATED", google::protobuf::FieldDescriptor::LABEL_REPEATED},
- // CPP types:
- {"CPPTYPE_MESSAGE", google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE},
- // Field Types:
- {"TYPE_MESSAGE", google::protobuf::FieldDescriptor::TYPE_MESSAGE},
- // End.
- {NULL, 0}
- };
-
- for (NameValue* constant = constants;
- constant->name != NULL; constant++) {
- PyModule_AddIntConstant(module, constant->name, constant->value);
- }
-}
-
-// --- CMessage Custom Type:
-
-// ------ Type Forward Declaration:
-
-struct CMessage;
-struct CMessage_Type;
-
-static void CMessageDealloc(CMessage* self);
-static int CMessageInit(CMessage* self, PyObject *args, PyObject *kwds);
-static PyObject* CMessageStr(CMessage* self);
-
-static PyObject* CMessage_AddMessage(CMessage* self, PyObject* args);
-static PyObject* CMessage_AddRepeatedScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_AssignRepeatedScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_ByteSize(CMessage* self, PyObject* args);
-static PyObject* CMessage_Clear(CMessage* self, PyObject* args);
-static PyObject* CMessage_ClearField(CMessage* self, PyObject* args);
-static PyObject* CMessage_ClearFieldByDescriptor(
- CMessage* self, PyObject* args);
-static PyObject* CMessage_CopyFrom(CMessage* self, PyObject* args);
-static PyObject* CMessage_DebugString(CMessage* self, PyObject* args);
-static PyObject* CMessage_DeleteRepeatedField(CMessage* self, PyObject* args);
-static PyObject* CMessage_Equals(CMessage* self, PyObject* args);
-static PyObject* CMessage_FieldLength(CMessage* self, PyObject* args);
-static PyObject* CMessage_FindInitializationErrors(CMessage* self);
-static PyObject* CMessage_GetRepeatedMessage(CMessage* self, PyObject* args);
-static PyObject* CMessage_GetRepeatedScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_GetScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_HasField(CMessage* self, PyObject* args);
-static PyObject* CMessage_HasFieldByDescriptor(CMessage* self, PyObject* args);
-static PyObject* CMessage_IsInitialized(CMessage* self, PyObject* args);
-static PyObject* CMessage_ListFields(CMessage* self, PyObject* args);
-static PyObject* CMessage_MergeFrom(CMessage* self, PyObject* args);
-static PyObject* CMessage_MergeFromString(CMessage* self, PyObject* args);
-static PyObject* CMessage_MutableMessage(CMessage* self, PyObject* args);
-static PyObject* CMessage_NewSubMessage(CMessage* self, PyObject* args);
-static PyObject* CMessage_SetScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_SerializePartialToString(
- CMessage* self, PyObject* args);
-static PyObject* CMessage_SerializeToString(CMessage* self, PyObject* args);
-static PyObject* CMessage_SetInParent(CMessage* self, PyObject* args);
-static PyObject* CMessage_SwapRepeatedFieldElements(
- CMessage* self, PyObject* args);
-
-// ------ Object Definition:
-
-typedef struct CMessage {
- PyObject_HEAD
-
- struct CMessage* parent; // NULL if wasn't created from another message.
- CFieldDescriptor* parent_field;
- const char* full_name;
- google::protobuf::Message* message;
- bool free_message;
- bool read_only;
-} CMessage;
-
-// ------ Method Table:
-
-#define CMETHOD(name, args, doc) \
- { C(#name), (PyCFunction)CMessage_##name, args, C(doc) }
-static PyMethodDef CMessageMethods[] = {
- CMETHOD(AddMessage, METH_O,
- "Adds a new message to a repeated composite field."),
- CMETHOD(AddRepeatedScalar, METH_VARARGS,
- "Adds a scalar to a repeated scalar field."),
- CMETHOD(AssignRepeatedScalar, METH_VARARGS,
- "Clears and sets the values of a repeated scalar field."),
- CMETHOD(ByteSize, METH_NOARGS,
- "Returns the size of the message in bytes."),
- CMETHOD(Clear, METH_NOARGS,
- "Clears a protocol message."),
- CMETHOD(ClearField, METH_O,
- "Clears a protocol message field by name."),
- CMETHOD(ClearFieldByDescriptor, METH_O,
- "Clears a protocol message field by descriptor."),
- CMETHOD(CopyFrom, METH_O,
- "Copies a protocol message into the current message."),
- CMETHOD(DebugString, METH_NOARGS,
- "Returns the debug string of a protocol message."),
- CMETHOD(DeleteRepeatedField, METH_VARARGS,
- "Deletes a slice of values from a repeated field."),
- CMETHOD(Equals, METH_O,
- "Checks if two protocol messages are equal (by identity)."),
- CMETHOD(FieldLength, METH_O,
- "Returns the number of elements in a repeated field."),
- CMETHOD(FindInitializationErrors, METH_NOARGS,
- "Returns the initialization errors of a message."),
- CMETHOD(GetRepeatedMessage, METH_VARARGS,
- "Returns a message from a repeated composite field."),
- CMETHOD(GetRepeatedScalar, METH_VARARGS,
- "Returns a scalar value from a repeated scalar field."),
- CMETHOD(GetScalar, METH_O,
- "Returns the scalar value of a field."),
- CMETHOD(HasField, METH_O,
- "Checks if a message field is set."),
- CMETHOD(HasFieldByDescriptor, METH_O,
- "Checks if a message field is set by given its descriptor"),
- CMETHOD(IsInitialized, METH_NOARGS,
- "Checks if all required fields of a protocol message are set."),
- CMETHOD(ListFields, METH_NOARGS,
- "Lists all set fields of a message."),
- CMETHOD(MergeFrom, METH_O,
- "Merges a protocol message into the current message."),
- CMETHOD(MergeFromString, METH_O,
- "Merges a serialized message into the current message."),
- CMETHOD(MutableMessage, METH_O,
- "Returns a new instance of a nested protocol message."),
- CMETHOD(NewSubMessage, METH_O,
- "Creates and returns a python message given the descriptor of a "
- "composite field of the current message."),
- CMETHOD(SetScalar, METH_VARARGS,
- "Sets the value of a singular scalar field."),
- CMETHOD(SerializePartialToString, METH_VARARGS,
- "Serializes the message to a string, even if it isn't initialized."),
- CMETHOD(SerializeToString, METH_NOARGS,
- "Serializes the message to a string, only for initialized messages."),
- CMETHOD(SetInParent, METH_NOARGS,
- "Sets the has bit of the given field in its parent message."),
- CMETHOD(SwapRepeatedFieldElements, METH_VARARGS,
- "Swaps the elements in two positions in a repeated field."),
- { NULL, NULL }
-};
-#undef CMETHOD
-
-static PyMemberDef CMessageMembers[] = {
- { C("full_name"), T_STRING, offsetof(CMessage, full_name), 0, "Full name" },
- { NULL }
-};
-
-// ------ Type Definition:
-
-// The definition for the type object that captures the type of CMessage
-// in Python.
-PyTypeObject CMessage_Type = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0,
- C("google3.net.google.protobuf.python.internal."
- "_net_proto2___python."
- "CMessage"), // tp_name
- sizeof(CMessage), // tp_basicsize
- 0, // tp_itemsize
- (destructor)CMessageDealloc, // 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
- (reprfunc)CMessageStr, // tp_str
- 0, // tp_getattro
- 0, // tp_setattro
- 0, // tp_as_buffer
- Py_TPFLAGS_DEFAULT, // tp_flags
- C("A ProtocolMessage"), // tp_doc
- 0, // tp_traverse
- 0, // tp_clear
- 0, // tp_richcompare
- 0, // tp_weaklistoffset
- 0, // tp_iter
- 0, // tp_iternext
- CMessageMethods, // tp_methods
- CMessageMembers, // tp_members
- 0, // tp_getset
- 0, // tp_base
- 0, // tp_dict
- 0, // tp_descr_get
- 0, // tp_descr_set
- 0, // tp_dictoffset
- (initproc)CMessageInit, // tp_init
- PyType_GenericAlloc, // tp_alloc
- PyType_GenericNew, // tp_new
- PyObject_Del, // tp_free
-};
-
-// ------ Helper Functions:
-
-static void FormatTypeError(PyObject* arg, char* expected_types) {
- PyObject* s = PyObject_Str(PyObject_Type(arg));
- PyObject* repr = PyObject_Repr(PyObject_Type(arg));
- PyErr_Format(PyExc_TypeError,
- "%.100s has type %.100s, but expected one of: %s",
- PyString_AS_STRING(repr),
- PyString_AS_STRING(s),
- expected_types);
- Py_DECREF(s);
- Py_DECREF(repr);
-}
-
-template <class T>
-static bool CheckAndGetInteger(
- PyObject* arg, T* value, PyObject* min, PyObject* max) {
- bool is_long = PyLong_Check(arg);
- if (!PyInt_Check(arg) && !is_long) {
- FormatTypeError(arg, "int, long");
- return false;
- }
-
- if (PyObject_Compare(min, arg) > 0 || PyObject_Compare(max, arg) < 0) {
- PyObject* s = PyObject_Str(arg);
- PyErr_Format(PyExc_ValueError,
- "Value out of range: %s",
- PyString_AS_STRING(s));
- Py_DECREF(s);
- return false;
- }
- if (is_long) {
- if (min == kPythonZero) {
- *value = static_cast<T>(PyLong_AsUnsignedLongLong(arg));
- } else {
- *value = static_cast<T>(PyLong_AsLongLong(arg));
- }
- } else {
- *value = static_cast<T>(PyInt_AsLong(arg));
- }
- return true;
-}
-
-static bool CheckAndGetDouble(PyObject* arg, double* value) {
- if (!PyInt_Check(arg) && !PyLong_Check(arg) &&
- !PyFloat_Check(arg)) {
- FormatTypeError(arg, "int, long, float");
- return false;
- }
- *value = PyFloat_AsDouble(arg);
- return true;
-}
-
-static bool CheckAndGetFloat(PyObject* arg, float* value) {
- double double_value;
- if (!CheckAndGetDouble(arg, &double_value)) {
- return false;
- }
- *value = static_cast<float>(double_value);
- return true;
-}
-
-static bool CheckAndGetBool(PyObject* arg, bool* value) {
- if (!PyInt_Check(arg) && !PyBool_Check(arg) && !PyLong_Check(arg)) {
- FormatTypeError(arg, "int, long, bool");
- return false;
- }
- *value = static_cast<bool>(PyInt_AsLong(arg));
- return true;
-}
-
-google::protobuf::DynamicMessageFactory* global_message_factory = NULL;
-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) {
- return NULL;
- }
- return global_message_factory->GetPrototype(descriptor);
-}
-
-static bool CheckAndSetString(
- PyObject* arg, google::protobuf::Message* message,
- const google::protobuf::FieldDescriptor* descriptor,
- const google::protobuf::Reflection* reflection,
- bool append,
- int index) {
- GOOGLE_DCHECK(descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING ||
- descriptor->type() == google::protobuf::FieldDescriptor::TYPE_BYTES);
- if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
- if (!PyString_Check(arg) && !PyUnicode_Check(arg)) {
- FormatTypeError(arg, "str, unicode");
- return false;
- }
-
- if (PyString_Check(arg)) {
- PyObject* unicode = PyUnicode_FromEncodedObject(arg, "ascii", 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 "
- "unicode objects before being added.",
- PyString_AS_STRING(repr));
- Py_DECREF(repr);
- return false;
- } else {
- Py_DECREF(unicode);
- }
- }
- } else if (!PyString_Check(arg)) {
- FormatTypeError(arg, "str");
- return false;
- }
-
- PyObject* encoded_string = NULL;
- if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
- if (PyString_Check(arg)) {
- encoded_string = PyString_AsEncodedObject(arg, "utf-8", NULL);
- } else {
- encoded_string = PyUnicode_AsEncodedObject(arg, "utf-8", NULL);
- }
- } else {
- // In this case field type is "bytes".
- encoded_string = arg;
- Py_INCREF(encoded_string);
- }
-
- if (encoded_string == NULL) {
- return false;
- }
-
- char* value;
- Py_ssize_t value_len;
- if (PyString_AsStringAndSize(encoded_string, &value, &value_len) < 0) {
- Py_DECREF(encoded_string);
- return false;
- }
-
- string value_string(value, value_len);
- if (append) {
- reflection->AddString(message, descriptor, value_string);
- } else if (index < 0) {
- reflection->SetString(message, descriptor, value_string);
- } else {
- reflection->SetRepeatedString(message, descriptor, index, value_string);
- }
- Py_DECREF(encoded_string);
- return true;
-}
-
-static PyObject* ToStringObject(
- const google::protobuf::FieldDescriptor* descriptor, string value) {
- if (descriptor->type() != google::protobuf::FieldDescriptor::TYPE_STRING) {
- return PyString_FromStringAndSize(value.c_str(), value.length());
- }
-
- PyObject* result = PyUnicode_DecodeUTF8(value.c_str(), value.length(), NULL);
- // If the string can't be decoded in UTF-8, just return a string object that
- // contains the raw bytes. This can't happen if the value was assigned using
- // the members of the Python message object, but can happen if the values were
- // parsed from the wire (binary).
- if (result == NULL) {
- PyErr_Clear();
- result = PyString_FromStringAndSize(value.c_str(), value.length());
- }
- return result;
-}
-
-static void AssureWritable(CMessage* self) {
- if (self == NULL ||
- self->parent == NULL ||
- self->parent_field == NULL) {
- return;
- }
-
- if (!self->read_only) {
- return;
- }
-
- AssureWritable(self->parent);
-
- google::protobuf::Message* message = self->parent->message;
- const google::protobuf::Reflection* reflection = message->GetReflection();
- self->message = reflection->MutableMessage(
- message, self->parent_field->descriptor, global_message_factory);
- self->read_only = false;
- self->parent = NULL;
- self->parent_field = NULL;
-}
-
-static PyObject* InternalGetScalar(
- google::protobuf::Message* message,
- const google::protobuf::FieldDescriptor* field_descriptor) {
- 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!");
- return NULL;
- }
-
- PyObject* result = NULL;
- switch (field_descriptor->cpp_type()) {
- case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
- int32 value = reflection->GetInt32(*message, field_descriptor);
- result = PyInt_FromLong(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
- int64 value = reflection->GetInt64(*message, field_descriptor);
-#if IS_64BIT
- result = PyInt_FromLong(value);
-#else
- result = PyLong_FromLongLong(value);
-#endif
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
- uint32 value = reflection->GetUInt32(*message, field_descriptor);
-#if IS_64BIT
- result = PyInt_FromLong(value);
-#else
- result = PyLong_FromLongLong(value);
-#endif
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
- uint64 value = reflection->GetUInt64(*message, field_descriptor);
-#if IS_64BIT
- if (value <= static_cast<uint64>(kint64max)) {
- result = PyInt_FromLong(static_cast<uint64>(value));
- }
-#else
- if (value <= static_cast<uint32>(kint32max)) {
- result = PyInt_FromLong(static_cast<uint32>(value));
- }
-#endif
- else { // NOLINT
- result = PyLong_FromUnsignedLongLong(value);
- }
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
- float value = reflection->GetFloat(*message, field_descriptor);
- result = PyFloat_FromDouble(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
- double value = reflection->GetDouble(*message, field_descriptor);
- result = PyFloat_FromDouble(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
- bool value = reflection->GetBool(*message, field_descriptor);
- result = PyBool_FromLong(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
- string value = reflection->GetString(*message, field_descriptor);
- result = ToStringObject(field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
- if (!message->GetReflection()->HasField(*message, field_descriptor)) {
- // Look for the value in the unknown fields.
- google::protobuf::UnknownFieldSet* unknown_field_set =
- message->GetReflection()->MutableUnknownFields(message);
- for (int i = 0; i < unknown_field_set->field_count(); ++i) {
- if (unknown_field_set->field(i).number() ==
- field_descriptor->number()) {
- result = PyInt_FromLong(unknown_field_set->field(i).varint());
- break;
- }
- }
- }
-
- if (result == NULL) {
- const google::protobuf::EnumValueDescriptor* enum_value =
- message->GetReflection()->GetEnum(*message, field_descriptor);
- result = PyInt_FromLong(enum_value->number());
- }
- break;
- }
- default:
- PyErr_Format(
- PyExc_SystemError, "Getting a value from a field of unknown type %d",
- field_descriptor->cpp_type());
- }
-
- return result;
-}
-
-static PyObject* InternalSetScalar(
- google::protobuf::Message* message, const google::protobuf::FieldDescriptor* field_descriptor,
- PyObject* arg) {
- 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!");
- return NULL;
- }
-
- switch (field_descriptor->cpp_type()) {
- case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
- GOOGLE_CHECK_GET_INT32(arg, value);
- reflection->SetInt32(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
- GOOGLE_CHECK_GET_INT64(arg, value);
- reflection->SetInt64(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
- GOOGLE_CHECK_GET_UINT32(arg, value);
- reflection->SetUInt32(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
- GOOGLE_CHECK_GET_UINT64(arg, value);
- reflection->SetUInt64(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
- GOOGLE_CHECK_GET_FLOAT(arg, value);
- reflection->SetFloat(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
- GOOGLE_CHECK_GET_DOUBLE(arg, value);
- reflection->SetDouble(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
- GOOGLE_CHECK_GET_BOOL(arg, value);
- reflection->SetBool(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
- if (!CheckAndSetString(
- arg, message, field_descriptor, reflection, false, -1)) {
- return NULL;
- }
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
- GOOGLE_CHECK_GET_INT32(arg, value);
- const google::protobuf::EnumDescriptor* enum_descriptor =
- field_descriptor->enum_type();
- const google::protobuf::EnumValueDescriptor* enum_value =
- enum_descriptor->FindValueByNumber(value);
- if (enum_value != NULL) {
- reflection->SetEnum(message, field_descriptor, enum_value);
- } else {
- bool added = false;
- // Add the value to the unknown fields.
- google::protobuf::UnknownFieldSet* unknown_field_set =
- message->GetReflection()->MutableUnknownFields(message);
- for (int i = 0; i < unknown_field_set->field_count(); ++i) {
- if (unknown_field_set->field(i).number() ==
- field_descriptor->number()) {
- unknown_field_set->mutable_field(i)->set_varint(value);
- added = true;
- break;
- }
- }
-
- if (!added) {
- unknown_field_set->AddVarint(field_descriptor->number(), value);
- }
- reflection->ClearField(message, field_descriptor);
- }
- break;
- }
- default:
- PyErr_Format(
- PyExc_SystemError, "Setting value to a field of unknown type %d",
- field_descriptor->cpp_type());
- }
-
- Py_RETURN_NONE;
-}
-
-static PyObject* InternalAddRepeatedScalar(
- google::protobuf::Message* message, const google::protobuf::FieldDescriptor* field_descriptor,
- PyObject* arg) {
-
- if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
- PyErr_SetString(
- PyExc_KeyError, "Field does not belong to message!");
- return NULL;
- }
-
- const google::protobuf::Reflection* reflection = message->GetReflection();
- switch (field_descriptor->cpp_type()) {
- case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
- GOOGLE_CHECK_GET_INT32(arg, value);
- reflection->AddInt32(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
- GOOGLE_CHECK_GET_INT64(arg, value);
- reflection->AddInt64(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
- GOOGLE_CHECK_GET_UINT32(arg, value);
- reflection->AddUInt32(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
- GOOGLE_CHECK_GET_UINT64(arg, value);
- reflection->AddUInt64(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
- GOOGLE_CHECK_GET_FLOAT(arg, value);
- reflection->AddFloat(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
- GOOGLE_CHECK_GET_DOUBLE(arg, value);
- reflection->AddDouble(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
- GOOGLE_CHECK_GET_BOOL(arg, value);
- reflection->AddBool(message, field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
- if (!CheckAndSetString(
- arg, message, field_descriptor, reflection, true, -1)) {
- return NULL;
- }
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
- GOOGLE_CHECK_GET_INT32(arg, value);
- const google::protobuf::EnumDescriptor* enum_descriptor =
- field_descriptor->enum_type();
- const google::protobuf::EnumValueDescriptor* enum_value =
- enum_descriptor->FindValueByNumber(value);
- if (enum_value != NULL) {
- reflection->AddEnum(message, field_descriptor, enum_value);
- } else {
- PyObject* s = PyObject_Str(arg);
- PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
- PyString_AS_STRING(s));
- Py_DECREF(s);
- return NULL;
- }
- break;
- }
- default:
- PyErr_Format(
- PyExc_SystemError, "Adding value to a field of unknown type %d",
- field_descriptor->cpp_type());
- }
-
- Py_RETURN_NONE;
-}
-
-static PyObject* InternalGetRepeatedScalar(
- CMessage* cmessage, const google::protobuf::FieldDescriptor* field_descriptor,
- int index) {
- google::protobuf::Message* message = cmessage->message;
- const google::protobuf::Reflection* reflection = message->GetReflection();
-
- int field_size = reflection->FieldSize(*message, field_descriptor);
- if (index < 0) {
- index = field_size + index;
- }
- if (index < 0 || index >= field_size) {
- PyErr_Format(PyExc_IndexError,
- "list assignment index (%d) out of range", index);
- return NULL;
- }
-
- PyObject* result = NULL;
- switch (field_descriptor->cpp_type()) {
- case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
- int32 value = reflection->GetRepeatedInt32(
- *message, field_descriptor, index);
- result = PyInt_FromLong(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
- int64 value = reflection->GetRepeatedInt64(
- *message, field_descriptor, index);
- result = PyLong_FromLongLong(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
- uint32 value = reflection->GetRepeatedUInt32(
- *message, field_descriptor, index);
- result = PyLong_FromLongLong(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
- uint64 value = reflection->GetRepeatedUInt64(
- *message, field_descriptor, index);
- result = PyLong_FromUnsignedLongLong(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
- float value = reflection->GetRepeatedFloat(
- *message, field_descriptor, index);
- result = PyFloat_FromDouble(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
- double value = reflection->GetRepeatedDouble(
- *message, field_descriptor, index);
- result = PyFloat_FromDouble(value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
- bool value = reflection->GetRepeatedBool(
- *message, field_descriptor, index);
- result = PyBool_FromLong(value ? 1 : 0);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
- const google::protobuf::EnumValueDescriptor* enum_value =
- message->GetReflection()->GetRepeatedEnum(
- *message, field_descriptor, index);
- result = PyInt_FromLong(enum_value->number());
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
- string value = reflection->GetRepeatedString(
- *message, field_descriptor, index);
- result = ToStringObject(field_descriptor, value);
- break;
- }
- case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
- CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
- if (py_cmsg == NULL) {
- return NULL;
- }
- const google::protobuf::Message& msg = reflection->GetRepeatedMessage(
- *message, field_descriptor, index);
- py_cmsg->parent = cmessage;
- py_cmsg->full_name = field_descriptor->full_name().c_str();
- py_cmsg->message = const_cast<google::protobuf::Message*>(&msg);
- py_cmsg->free_message = false;
- py_cmsg->read_only = false;
- result = reinterpret_cast<PyObject*>(py_cmsg);
- break;
- }
- default:
- PyErr_Format(
- PyExc_SystemError,
- "Getting value from a repeated field of unknown type %d",
- field_descriptor->cpp_type());
- }
-
- return result;
-}
-
-static PyObject* InternalGetRepeatedScalarSlice(
- CMessage* cmessage, const google::protobuf::FieldDescriptor* field_descriptor,
- PyObject* slice) {
- Py_ssize_t from;
- Py_ssize_t to;
- Py_ssize_t step;
- Py_ssize_t length;
- bool return_list = false;
- google::protobuf::Message* message = cmessage->message;
-
- if (PyInt_Check(slice)) {
- from = to = PyInt_AsLong(slice);
- } else if (PyLong_Check(slice)) {
- from = to = PyLong_AsLong(slice);
- } else if (PySlice_Check(slice)) {
- const google::protobuf::Reflection* reflection = message->GetReflection();
- length = reflection->FieldSize(*message, field_descriptor);
- PySlice_GetIndices(
- reinterpret_cast<PySliceObject*>(slice), length, &from, &to, &step);
- return_list = true;
- } else {
- PyErr_SetString(PyExc_TypeError, "list indices must be integers");
- return NULL;
- }
-
- if (!return_list) {
- return InternalGetRepeatedScalar(cmessage, field_descriptor, from);
- }
-
- PyObject* list = PyList_New(0);
- if (list == NULL) {
- return NULL;
- }
-
- if (from <= to) {
- if (step < 0) return list;
- for (Py_ssize_t index = from; index < to; index += step) {
- if (index < 0 || index >= length) break;
- PyObject* s = InternalGetRepeatedScalar(
- cmessage, field_descriptor, index);
- PyList_Append(list, s);
- Py_DECREF(s);
- }
- } else {
- if (step > 0) return list;
- for (Py_ssize_t index = from; index > to; index += step) {
- if (index < 0 || index >= length) break;
- PyObject* s = InternalGetRepeatedScalar(
- cmessage, field_descriptor, index);
- PyList_Append(list, s);
- Py_DECREF(s);
- }
- }
- return list;
-}
-
-// ------ C Constructor/Destructor:
-
-static int CMessageInit(CMessage* self, PyObject *args, PyObject *kwds) {
- self->message = NULL;
- return 0;
-}
-
-static void CMessageDealloc(CMessage* self) {
- if (self->free_message) {
- if (self->read_only) {
- PyErr_WriteUnraisable(reinterpret_cast<PyObject*>(self));
- }
- delete self->message;
- }
- self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
-}
-
-// ------ Methods:
-
-static PyObject* CMessage_Clear(CMessage* self, PyObject* args) {
- AssureWritable(self);
- self->message->Clear();
- Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_IsInitialized(CMessage* self, PyObject* args) {
- return PyBool_FromLong(self->message->IsInitialized() ? 1 : 0);
-}
-
-static PyObject* CMessage_HasField(CMessage* self, PyObject* arg) {
- char* field_name;
- if (PyString_AsStringAndSize(arg, &field_name, NULL) < 0) {
- return NULL;
- }
-
- google::protobuf::Message* message = self->message;
- const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
- const google::protobuf::FieldDescriptor* field_descriptor =
- descriptor->FindFieldByName(field_name);
- if (field_descriptor == NULL) {
- PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
- return NULL;
- }
-
- bool has_field =
- message->GetReflection()->HasField(*message, field_descriptor);
- return PyBool_FromLong(has_field ? 1 : 0);
-}
-
-static PyObject* CMessage_HasFieldByDescriptor(CMessage* self, PyObject* arg) {
- CFieldDescriptor* cfield_descriptor = NULL;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
- &CFieldDescriptor_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
- return NULL;
- }
- cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
- google::protobuf::Message* message = self->message;
- const google::protobuf::FieldDescriptor* field_descriptor =
- cfield_descriptor->descriptor;
-
- if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
- PyErr_SetString(PyExc_KeyError,
- "Field does not belong to message!");
- return NULL;
- }
-
- if (FIELD_IS_REPEATED(field_descriptor)) {
- PyErr_SetString(PyExc_KeyError,
- "Field is repeated. A singular method is required.");
- return NULL;
- }
-
- bool has_field =
- message->GetReflection()->HasField(*message, field_descriptor);
- return PyBool_FromLong(has_field ? 1 : 0);
-}
-
-static PyObject* CMessage_ClearFieldByDescriptor(
- CMessage* self, PyObject* arg) {
- CFieldDescriptor* cfield_descriptor = NULL;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
- &CFieldDescriptor_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
- return NULL;
- }
- cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
- google::protobuf::Message* message = self->message;
- const google::protobuf::FieldDescriptor* field_descriptor =
- cfield_descriptor->descriptor;
-
- if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
- PyErr_SetString(PyExc_KeyError,
- "Field does not belong to message!");
- return NULL;
- }
-
- message->GetReflection()->ClearField(message, field_descriptor);
- Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_ClearField(CMessage* self, PyObject* arg) {
- char* field_name;
- if (PyString_AsStringAndSize(arg, &field_name, NULL) < 0) {
- return NULL;
- }
-
- google::protobuf::Message* message = self->message;
- const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
- const google::protobuf::FieldDescriptor* field_descriptor =
- descriptor->FindFieldByName(field_name);
- if (field_descriptor == NULL) {
- PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
- return NULL;
- }
-
- message->GetReflection()->ClearField(message, field_descriptor);
- Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_GetScalar(CMessage* self, PyObject* arg) {
- CFieldDescriptor* cdescriptor = NULL;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
- &CFieldDescriptor_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
- return NULL;
- }
- cdescriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
- google::protobuf::Message* message = self->message;
- return InternalGetScalar(message, cdescriptor->descriptor);
-}
-
-static PyObject* CMessage_GetRepeatedScalar(CMessage* self, PyObject* args) {
- CFieldDescriptor* cfield_descriptor;
- PyObject* slice;
- if (!PyArg_ParseTuple(args, C("O!O:GetRepeatedScalar"),
- &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
- return NULL;
- }
-
- return InternalGetRepeatedScalarSlice(
- self, cfield_descriptor->descriptor, slice);
-}
-
-static PyObject* CMessage_AssignRepeatedScalar(CMessage* self, PyObject* args) {
- CFieldDescriptor* cfield_descriptor;
- PyObject* slice;
- if (!PyArg_ParseTuple(args, C("O!O:AssignRepeatedScalar"),
- &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
- return NULL;
- }
-
- AssureWritable(self);
- google::protobuf::Message* message = self->message;
- message->GetReflection()->ClearField(message, cfield_descriptor->descriptor);
-
- PyObject* iter = PyObject_GetIter(slice);
- PyObject* next;
- while ((next = PyIter_Next(iter)) != NULL) {
- if (InternalAddRepeatedScalar(
- message, cfield_descriptor->descriptor, next) == NULL) {
- Py_DECREF(iter);
- return NULL;
- }
- }
- Py_DECREF(iter);
- Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_DeleteRepeatedField(CMessage* self, PyObject* args) {
- CFieldDescriptor* cfield_descriptor;
- PyObject* slice;
- if (!PyArg_ParseTuple(args, C("O!O:DeleteRepeatedField"),
- &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
- return NULL;
- }
- AssureWritable(self);
-
- Py_ssize_t length, from, to, step, slice_length;
- google::protobuf::Message* message = self->message;
- const google::protobuf::FieldDescriptor* field_descriptor =
- cfield_descriptor->descriptor;
- const google::protobuf::Reflection* reflection = message->GetReflection();
- int min, max;
- length = reflection->FieldSize(*message, field_descriptor);
-
- if (PyInt_Check(slice) || PyLong_Check(slice)) {
- from = to = PyLong_AsLong(slice);
- if (from < 0) {
- from = to = length + from;
- }
- step = 1;
- min = max = from;
-
- // Range check.
- if (from < 0 || from >= length) {
- PyErr_Format(PyExc_IndexError, "list assignment index out of range");
- return NULL;
- }
- } else if (PySlice_Check(slice)) {
- from = to = step = slice_length = 0;
- PySlice_GetIndicesEx(
- reinterpret_cast<PySliceObject*>(slice),
- length, &from, &to, &step, &slice_length);
- if (from < to) {
- min = from;
- max = to - 1;
- } else {
- min = to + 1;
- max = from;
- }
- } else {
- PyErr_SetString(PyExc_TypeError, "list indices must be integers");
- return NULL;
- }
-
- Py_ssize_t i = from;
- std::vector<bool> to_delete(length, false);
- while (i >= min && i <= max) {
- to_delete[i] = true;
- i += step;
- }
-
- to = 0;
- for (i = 0; i < length; ++i) {
- if (!to_delete[i]) {
- if (i != to) {
- reflection->SwapElements(message, field_descriptor, i, to);
- }
- ++to;
- }
- }
-
- while (i > to) {
- reflection->RemoveLast(message, field_descriptor);
- --i;
- }
-
- Py_RETURN_NONE;
-}
-
-
-static PyObject* CMessage_SetScalar(CMessage* self, PyObject* args) {
- CFieldDescriptor* cfield_descriptor;
- PyObject* arg;
- if (!PyArg_ParseTuple(args, C("O!O:SetScalar"),
- &CFieldDescriptor_Type, &cfield_descriptor, &arg)) {
- return NULL;
- }
- AssureWritable(self);
-
- return InternalSetScalar(self->message, cfield_descriptor->descriptor, arg);
-}
-
-static PyObject* CMessage_AddRepeatedScalar(CMessage* self, PyObject* args) {
- CFieldDescriptor* cfield_descriptor;
- PyObject* value;
- if (!PyArg_ParseTuple(args, C("O!O:AddRepeatedScalar"),
- &CFieldDescriptor_Type, &cfield_descriptor, &value)) {
- return NULL;
- }
- AssureWritable(self);
-
- return InternalAddRepeatedScalar(
- self->message, cfield_descriptor->descriptor, value);
-}
-
-static PyObject* CMessage_FieldLength(CMessage* self, PyObject* arg) {
- CFieldDescriptor* cfield_descriptor;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
- &CFieldDescriptor_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
- return NULL;
- }
- cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
- google::protobuf::Message* message = self->message;
- int length = message->GetReflection()->FieldSize(
- *message, cfield_descriptor->descriptor);
- return PyInt_FromLong(length);
-}
-
-static PyObject* CMessage_DebugString(CMessage* self, PyObject* args) {
- return PyString_FromString(self->message->DebugString().c_str());
-}
-
-static PyObject* CMessage_SerializeToString(CMessage* self, PyObject* args) {
- int size = self->message->ByteSize();
- if (size <= 0) {
- return PyString_FromString("");
- }
- PyObject* result = PyString_FromStringAndSize(NULL, size);
- if (result == NULL) {
- return NULL;
- }
- char* buffer = PyString_AS_STRING(result);
- self->message->SerializeWithCachedSizesToArray(
- reinterpret_cast<uint8*>(buffer));
- return result;
-}
-
-static PyObject* CMessage_SerializePartialToString(
- CMessage* self, PyObject* args) {
- string contents;
- self->message->SerializePartialToString(&contents);
- return PyString_FromStringAndSize(contents.c_str(), contents.size());
-}
-
-static PyObject* CMessageStr(CMessage* self) {
- char str[1024];
- str[sizeof(str) - 1] = 0;
- snprintf(str, sizeof(str) - 1, "CMessage: <%p>", self->message);
- return PyString_FromString(str);
-}
-
-static PyObject* CMessage_MergeFrom(CMessage* self, PyObject* arg) {
- CMessage* other_message;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a message");
- return NULL;
- }
-
- other_message = reinterpret_cast<CMessage*>(arg);
- if (other_message->message->GetDescriptor() !=
- self->message->GetDescriptor()) {
- PyErr_Format(PyExc_TypeError,
- "Tried to merge from a message with a different type. "
- "to: %s, from: %s",
- self->message->GetDescriptor()->full_name().c_str(),
- other_message->message->GetDescriptor()->full_name().c_str());
- return NULL;
- }
- AssureWritable(self);
-
- self->message->MergeFrom(*other_message->message);
- Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_CopyFrom(CMessage* self, PyObject* arg) {
- CMessage* other_message;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a message");
- return NULL;
- }
-
- other_message = reinterpret_cast<CMessage*>(arg);
- if (other_message->message->GetDescriptor() !=
- self->message->GetDescriptor()) {
- PyErr_Format(PyExc_TypeError,
- "Tried to copy from a message with a different type. "
- "to: %s, from: %s",
- self->message->GetDescriptor()->full_name().c_str(),
- other_message->message->GetDescriptor()->full_name().c_str());
- return NULL;
- }
-
- AssureWritable(self);
-
- self->message->CopyFrom(*other_message->message);
- Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_MergeFromString(CMessage* self, PyObject* arg) {
- const void* data;
- Py_ssize_t data_length;
- if (PyObject_AsReadBuffer(arg, &data, &data_length) < 0) {
- return NULL;
- }
-
- AssureWritable(self);
- google::protobuf::io::CodedInputStream input(
- reinterpret_cast<const uint8*>(data), data_length);
- bool success = self->message->MergePartialFromCodedStream(&input);
- if (success) {
- return PyInt_FromLong(self->message->ByteSize());
- } else {
- return PyInt_FromLong(-1);
- }
-}
-
-static PyObject* CMessage_ByteSize(CMessage* self, PyObject* args) {
- return PyLong_FromLong(self->message->ByteSize());
-}
-
-static PyObject* CMessage_SetInParent(CMessage* self, PyObject* args) {
- AssureWritable(self);
- Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_SwapRepeatedFieldElements(
- CMessage* self, PyObject* args) {
- CFieldDescriptor* cfield_descriptor;
- int index1, index2;
- if (!PyArg_ParseTuple(args, C("O!ii:SwapRepeatedFieldElements"),
- &CFieldDescriptor_Type, &cfield_descriptor,
- &index1, &index2)) {
- return NULL;
- }
-
- google::protobuf::Message* message = self->message;
- const google::protobuf::Reflection* reflection = message->GetReflection();
-
- reflection->SwapElements(
- message, cfield_descriptor->descriptor, index1, index2);
- Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_AddMessage(CMessage* self, PyObject* arg) {
- CFieldDescriptor* cfield_descriptor;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
- &CFieldDescriptor_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
- return NULL;
- }
- cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
- AssureWritable(self);
-
- CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
- if (py_cmsg == NULL) {
- return NULL;
- }
-
- google::protobuf::Message* message = self->message;
- const google::protobuf::Reflection* reflection = message->GetReflection();
- google::protobuf::Message* sub_message =
- reflection->AddMessage(message, cfield_descriptor->descriptor);
-
- py_cmsg->parent = NULL;
- py_cmsg->full_name = sub_message->GetDescriptor()->full_name().c_str();
- py_cmsg->message = sub_message;
- py_cmsg->free_message = false;
- py_cmsg->read_only = false;
- return reinterpret_cast<PyObject*>(py_cmsg);
-}
-
-static PyObject* CMessage_GetRepeatedMessage(CMessage* self, PyObject* args) {
- CFieldDescriptor* cfield_descriptor;
- PyObject* slice;
- if (!PyArg_ParseTuple(args, C("O!O:GetRepeatedMessage"),
- &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
- return NULL;
- }
-
- return InternalGetRepeatedScalarSlice(
- self, cfield_descriptor->descriptor, slice);
-}
-
-static PyObject* CMessage_NewSubMessage(CMessage* self, PyObject* arg) {
- CFieldDescriptor* cfield_descriptor;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
- &CFieldDescriptor_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
- return NULL;
- }
- cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
- CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
- if (py_cmsg == NULL) {
- return NULL;
- }
-
- google::protobuf::Message* message = self->message;
- const google::protobuf::Reflection* reflection = message->GetReflection();
- const google::protobuf::Message& sub_message =
- reflection->GetMessage(*message, cfield_descriptor->descriptor,
- global_message_factory);
-
- py_cmsg->full_name = sub_message.GetDescriptor()->full_name().c_str();
- py_cmsg->parent = self;
- py_cmsg->parent_field = cfield_descriptor;
- py_cmsg->message = const_cast<google::protobuf::Message*>(&sub_message);
- py_cmsg->free_message = false;
- py_cmsg->read_only = true;
- return reinterpret_cast<PyObject*>(py_cmsg);
-}
-
-static PyObject* CMessage_MutableMessage(CMessage* self, PyObject* arg) {
- CFieldDescriptor* cfield_descriptor;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
- &CFieldDescriptor_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
- return NULL;
- }
- cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
- AssureWritable(self);
-
- CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
- if (py_cmsg == NULL) {
- return NULL;
- }
-
- google::protobuf::Message* message = self->message;
- const google::protobuf::Reflection* reflection = message->GetReflection();
- google::protobuf::Message* mutable_message =
- reflection->MutableMessage(message, cfield_descriptor->descriptor,
- global_message_factory);
-
- py_cmsg->full_name = mutable_message->GetDescriptor()->full_name().c_str();
- py_cmsg->message = mutable_message;
- py_cmsg->free_message = false;
- py_cmsg->read_only = false;
- return reinterpret_cast<PyObject*>(py_cmsg);
-}
-
-static PyObject* CMessage_Equals(CMessage* self, PyObject* arg) {
- CMessage* other_message;
- if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
- PyErr_SetString(PyExc_TypeError, "Must be a message");
- return NULL;
- }
- other_message = reinterpret_cast<CMessage*>(arg);
-
- if (other_message->message == self->message) {
- return PyBool_FromLong(1);
- }
-
- if (other_message->message->GetDescriptor() !=
- self->message->GetDescriptor()) {
- return PyBool_FromLong(0);
- }
-
- return PyBool_FromLong(1);
-}
-
-static PyObject* CMessage_ListFields(CMessage* self, PyObject* args) {
- google::protobuf::Message* message = self->message;
- const google::protobuf::Reflection* reflection = message->GetReflection();
- vector<const google::protobuf::FieldDescriptor*> fields;
- reflection->ListFields(*message, &fields);
-
- PyObject* list = PyList_New(fields.size());
- if (list == NULL) {
- return NULL;
- }
-
- for (unsigned int i = 0; i < fields.size(); ++i) {
- bool is_extension = fields[i]->is_extension();
- PyObject* t = PyTuple_New(2);
- if (t == NULL) {
- Py_DECREF(list);
- return NULL;
- }
-
- PyObject* is_extension_object = PyBool_FromLong(is_extension ? 1 : 0);
-
- PyObject* field_name;
- const string* s;
- if (is_extension) {
- s = &fields[i]->full_name();
- } else {
- s = &fields[i]->name();
- }
- field_name = PyString_FromStringAndSize(s->c_str(), s->length());
- if (field_name == NULL) {
- Py_DECREF(list);
- Py_DECREF(t);
- return NULL;
- }
-
- PyTuple_SET_ITEM(t, 0, is_extension_object);
- PyTuple_SET_ITEM(t, 1, field_name);
- PyList_SET_ITEM(list, i, t);
- }
-
- return list;
-}
-
-static PyObject* CMessage_FindInitializationErrors(CMessage* self) {
- google::protobuf::Message* message = self->message;
- vector<string> errors;
- message->FindInitializationErrors(&errors);
-
- PyObject* error_list = PyList_New(errors.size());
- if (error_list == NULL) {
- return NULL;
- }
- for (unsigned int i = 0; i < errors.size(); ++i) {
- const string& error = errors[i];
- PyObject* error_string = PyString_FromStringAndSize(
- error.c_str(), error.length());
- if (error_string == NULL) {
- Py_DECREF(error_list);
- return NULL;
- }
- PyList_SET_ITEM(error_list, i, error_string);
- }
- return error_list;
-}
-
-// ------ Python Constructor:
-
-PyObject* Python_NewCMessage(PyObject* ignored, PyObject* arg) {
- const char* message_type = PyString_AsString(arg);
- if (message_type == NULL) {
- return NULL;
- }
-
- const google::protobuf::Message* message = CreateMessage(message_type);
- if (message == NULL) {
- PyErr_Format(PyExc_TypeError, "Couldn't create message of type %s!",
- message_type);
- return NULL;
- }
-
- CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
- if (py_cmsg == NULL) {
- return NULL;
- }
- py_cmsg->message = message->New();
- py_cmsg->free_message = true;
- py_cmsg->full_name = message->GetDescriptor()->full_name().c_str();
- py_cmsg->read_only = false;
- py_cmsg->parent = NULL;
- py_cmsg->parent_field = NULL;
- return reinterpret_cast<PyObject*>(py_cmsg);
-}
-
-// --- Module Functions (exposed to Python):
-
-PyMethodDef methods[] = {
- { C("NewCMessage"), (PyCFunction)Python_NewCMessage,
- METH_O,
- C("Creates a new C++ protocol message, given its full name.") },
- { C("NewCDescriptorPool"), (PyCFunction)Python_NewCDescriptorPool,
- METH_NOARGS,
- C("Creates a new C++ descriptor pool.") },
- { C("BuildFile"), (PyCFunction)Python_BuildFile,
- METH_O,
- C("Registers a new protocol buffer file in the global C++ descriptor "
- "pool.") },
- {NULL}
-};
-
-// --- Exposing the C proto living inside Python proto to C code:
-
-extern const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg);
-extern Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg);
-
-static const google::protobuf::Message* GetCProtoInsidePyProtoImpl(PyObject* msg) {
- PyObject* c_msg_obj = PyObject_GetAttrString(msg, "_cmsg");
- if (c_msg_obj == NULL) {
- PyErr_Clear();
- return NULL;
- }
- Py_DECREF(c_msg_obj);
- if (!PyObject_TypeCheck(c_msg_obj, &CMessage_Type)) {
- return NULL;
- }
- CMessage* c_msg = reinterpret_cast<CMessage*>(c_msg_obj);
- return c_msg->message;
-}
-
-static google::protobuf::Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
- PyObject* c_msg_obj = PyObject_GetAttrString(msg, "_cmsg");
- if (c_msg_obj == NULL) {
- PyErr_Clear();
- return NULL;
- }
- Py_DECREF(c_msg_obj);
- if (!PyObject_TypeCheck(c_msg_obj, &CMessage_Type)) {
- return NULL;
- }
- CMessage* c_msg = reinterpret_cast<CMessage*>(c_msg_obj);
- AssureWritable(c_msg);
- return c_msg->message;
-}
-
-// --- Module Init Function:
-
-static const char module_docstring[] =
-"python-proto2 is a module that can be used to enhance proto2 Python API\n"
-"performance.\n"
-"\n"
-"It provides access to the protocol buffers C++ reflection API that\n"
-"implements the basic protocol buffer functions.";
-
-extern "C" {
- void init_net_proto2___python() {
- // Initialize constants.
- kPythonZero = PyInt_FromLong(0);
- kint32min_py = PyInt_FromLong(kint32min);
- kint32max_py = PyInt_FromLong(kint32max);
- kuint32max_py = PyLong_FromLongLong(kuint32max);
- kint64min_py = PyLong_FromLongLong(kint64min);
- kint64max_py = PyLong_FromLongLong(kint64max);
- kuint64max_py = PyLong_FromUnsignedLongLong(kuint64max);
-
- global_message_factory = new DynamicMessageFactory(GetDescriptorPool());
- global_message_factory->SetDelegateToGeneratedFactory(true);
-
- // Export our functions to Python.
- PyObject *m;
- m = Py_InitModule3(C("_net_proto2___python"), methods, C(module_docstring));
- if (m == NULL) {
- return;
- }
-
- AddConstants(m);
-
- CMessage_Type.tp_new = PyType_GenericNew;
- if (PyType_Ready(&CMessage_Type) < 0) {
- return;
- }
-
- if (!InitDescriptor()) {
- return;
- }
-
- // Override {Get,Mutable}CProtoInsidePyProto.
- GetCProtoInsidePyProtoPtr = GetCProtoInsidePyProtoImpl;
- MutableCProtoInsidePyProtoPtr = MutableCProtoInsidePyProtoImpl;
- }
-}
-
-} // namespace python
-} // namespace protobuf
-} // namespace google
diff --git a/python/google/protobuf/pyext/python.proto b/python/google/protobuf/pyext/python.proto
new file mode 100644
index 00000000..cce645d7
--- /dev/null
+++ b/python/google/protobuf/pyext/python.proto
@@ -0,0 +1,68 @@
+// 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: tibell@google.com (Johan Tibell)
+//
+// 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;
+
+// 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;
+
+message TestAllTypes {
+ message NestedMessage {
+ optional int32 bb = 1;
+ optional ForeignMessage cc = 2;
+ }
+
+ repeated NestedMessage repeated_nested_message = 1;
+ optional NestedMessage optional_nested_message = 2;
+ optional int32 optional_int32 = 3;
+}
+
+message ForeignMessage {
+ optional int32 c = 1;
+ repeated int32 d = 2;
+}
+
+message TestAllExtensions {
+ extensions 1 to max;
+}
+
+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/python_descriptor.cc b/python/google/protobuf/pyext/python_descriptor.cc
deleted file mode 100644
index fb87bad1..00000000
--- a/python/google/protobuf/pyext/python_descriptor.cc
+++ /dev/null
@@ -1,334 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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: petar@google.com (Petar Petrov)
-
-#include <Python.h>
-
-#include <google/protobuf/pyext/python_descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
-
-#define C(str) const_cast<char*>(str)
-
-namespace google {
-namespace protobuf {
-namespace python {
-
-static void CFieldDescriptorDealloc(CFieldDescriptor* self);
-
-static google::protobuf::DescriptorPool* g_descriptor_pool = NULL;
-
-static PyObject* CFieldDescriptor_GetFullName(
- CFieldDescriptor* self, void *closure) {
- Py_XINCREF(self->full_name);
- return self->full_name;
-}
-
-static PyObject* CFieldDescriptor_GetName(
- CFieldDescriptor *self, void *closure) {
- Py_XINCREF(self->name);
- return self->name;
-}
-
-static PyObject* CFieldDescriptor_GetCppType(
- CFieldDescriptor *self, void *closure) {
- Py_XINCREF(self->cpp_type);
- return self->cpp_type;
-}
-
-static PyObject* CFieldDescriptor_GetLabel(
- CFieldDescriptor *self, void *closure) {
- Py_XINCREF(self->label);
- return self->label;
-}
-
-static PyObject* CFieldDescriptor_GetID(
- CFieldDescriptor *self, void *closure) {
- Py_XINCREF(self->id);
- return self->id;
-}
-
-
-static PyGetSetDef CFieldDescriptorGetters[] = {
- { C("full_name"),
- (getter)CFieldDescriptor_GetFullName, NULL, "Full name", NULL},
- { C("name"),
- (getter)CFieldDescriptor_GetName, NULL, "last name", NULL},
- { C("cpp_type"),
- (getter)CFieldDescriptor_GetCppType, NULL, "C++ Type", NULL},
- { C("label"),
- (getter)CFieldDescriptor_GetLabel, NULL, "Label", NULL},
- { C("id"),
- (getter)CFieldDescriptor_GetID, NULL, "ID", NULL},
- {NULL}
-};
-
-PyTypeObject CFieldDescriptor_Type = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0,
- C("google3.net.google.protobuf.python.internal."
- "_net_proto2___python."
- "CFieldDescriptor"), // tp_name
- sizeof(CFieldDescriptor), // tp_basicsize
- 0, // tp_itemsize
- (destructor)CFieldDescriptorDealloc, // 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 Field 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
- CFieldDescriptorGetters, // 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
-};
-
-static void CFieldDescriptorDealloc(CFieldDescriptor* self) {
- Py_DECREF(self->full_name);
- Py_DECREF(self->name);
- Py_DECREF(self->cpp_type);
- Py_DECREF(self->label);
- Py_DECREF(self->id);
- self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
-}
-
-typedef struct {
- PyObject_HEAD
-
- const google::protobuf::DescriptorPool* pool;
-} CDescriptorPool;
-
-static void CDescriptorPoolDealloc(CDescriptorPool* self);
-
-static PyObject* CDescriptorPool_NewCDescriptor(
- const google::protobuf::FieldDescriptor* field_descriptor) {
- CFieldDescriptor* cfield_descriptor = PyObject_New(
- CFieldDescriptor, &CFieldDescriptor_Type);
- if (cfield_descriptor == NULL) {
- return NULL;
- }
- cfield_descriptor->descriptor = field_descriptor;
-
- cfield_descriptor->full_name = PyString_FromString(
- field_descriptor->full_name().c_str());
- cfield_descriptor->name = PyString_FromString(
- field_descriptor->name().c_str());
- cfield_descriptor->cpp_type = PyLong_FromLong(field_descriptor->cpp_type());
- cfield_descriptor->label = PyLong_FromLong(field_descriptor->label());
- cfield_descriptor->id = PyLong_FromVoidPtr(cfield_descriptor);
- return reinterpret_cast<PyObject*>(cfield_descriptor);
-}
-
-static PyObject* CDescriptorPool_FindFieldByName(
- CDescriptorPool* self, PyObject* arg) {
- const char* full_field_name = PyString_AsString(arg);
- if (full_field_name == NULL) {
- return NULL;
- }
-
- const google::protobuf::FieldDescriptor* field_descriptor = NULL;
-
- field_descriptor = self->pool->FindFieldByName(full_field_name);
- if (field_descriptor == NULL) {
- PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
- full_field_name);
- return NULL;
- }
-
- return CDescriptorPool_NewCDescriptor(field_descriptor);
-}
-
-static PyObject* CDescriptorPool_FindExtensionByName(
- CDescriptorPool* self, PyObject* arg) {
- const char* full_field_name = PyString_AsString(arg);
- if (full_field_name == NULL) {
- return NULL;
- }
-
- const google::protobuf::FieldDescriptor* field_descriptor =
- self->pool->FindExtensionByName(full_field_name);
- if (field_descriptor == NULL) {
- PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
- full_field_name);
- return NULL;
- }
-
- return CDescriptorPool_NewCDescriptor(field_descriptor);
-}
-
-static PyMethodDef CDescriptorPoolMethods[] = {
- { C("FindFieldByName"),
- (PyCFunction)CDescriptorPool_FindFieldByName,
- METH_O,
- C("Searches for a field descriptor by full name.") },
- { C("FindExtensionByName"),
- (PyCFunction)CDescriptorPool_FindExtensionByName,
- METH_O,
- C("Searches for extension descriptor by full name.") },
- {NULL}
-};
-
-PyTypeObject CDescriptorPool_Type = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0,
- C("google3.net.google.protobuf.python.internal."
- "_net_proto2___python."
- "CFieldDescriptor"), // tp_name
- sizeof(CDescriptorPool), // tp_basicsize
- 0, // tp_itemsize
- (destructor)CDescriptorPoolDealloc, // 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 Descriptor Pool"), // tp_doc
- 0, // tp_traverse
- 0, // tp_clear
- 0, // tp_richcompare
- 0, // tp_weaklistoffset
- 0, // tp_iter
- 0, // tp_iternext
- CDescriptorPoolMethods, // tp_methods
- 0, // tp_members
- 0, // 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
-};
-
-static void CDescriptorPoolDealloc(CDescriptorPool* self) {
- self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
-}
-
-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<PyObject*>(cdescriptor_pool);
-}
-
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* arg) {
- char* message_type;
- Py_ssize_t message_len;
-
- if (PyString_AsStringAndSize(arg, &message_type, &message_len) < 0) {
- return NULL;
- }
-
- google::protobuf::FileDescriptorProto file_proto;
- if (!file_proto.ParseFromArray(message_type, message_len)) {
- PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
- return NULL;
- }
-
- // If this file is already in the generated pool, don't add it again.
- if (google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
- file_proto.name()) != NULL) {
- Py_RETURN_NONE;
- }
-
- const google::protobuf::FileDescriptor* descriptor = GetDescriptorPool()->BuildFile(
- file_proto);
- if (descriptor == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Couldn't build proto file into descriptor pool!");
- return NULL;
- }
-
- Py_RETURN_NONE;
-}
-
-bool InitDescriptor() {
- CFieldDescriptor_Type.tp_new = PyType_GenericNew;
- if (PyType_Ready(&CFieldDescriptor_Type) < 0)
- return false;
-
- CDescriptorPool_Type.tp_new = PyType_GenericNew;
- if (PyType_Ready(&CDescriptorPool_Type) < 0)
- return false;
- return true;
-}
-
-} // namespace python
-} // namespace protobuf
-} // namespace google
diff --git a/python/google/protobuf/pyext/python_protobuf.h b/python/google/protobuf/pyext/python_protobuf.h
index c5b0b1cd..beb6e460 100644
--- a/python/google/protobuf/pyext/python_protobuf.h
+++ b/python/google/protobuf/pyext/python_protobuf.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
new file mode 100644
index 00000000..0fe98e73
--- /dev/null
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -0,0 +1,776 @@
+// 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: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#include <google/protobuf/pyext/repeated_composite_container.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#if PY_MAJOR_VERSION >= 3
+ #define PyInt_Check PyLong_Check
+ #define PyInt_AsLong PyLong_AsLong
+ #define PyInt_FromLong PyLong_FromLong
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace repeated_composite_container {
+
+// TODO(tibell): We might also want to check:
+// GOOGLE_CHECK_NOTNULL((self)->owner.get());
+#define GOOGLE_CHECK_ATTACHED(self) \
+ do { \
+ GOOGLE_CHECK_NOTNULL((self)->message); \
+ 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_descriptor == NULL); \
+ GOOGLE_CHECK((self)->parent == NULL); \
+ } while (0);
+
+// Returns a new reference.
+static PyObject* GetKey(PyObject* x) {
+ // Just the identity function.
+ Py_INCREF(x);
+ return x;
+}
+
+#define GET_KEY(keyfunc, value) \
+ ((keyfunc) == NULL ? \
+ GetKey((value)) : \
+ PyObject_CallFunctionObjArgs((keyfunc), (value), NULL))
+
+// Converts a comparison function that returns -1, 0, or 1 into a
+// less-than predicate.
+//
+// Returns -1 on error, 1 if x < y, 0 if x >= y.
+static int islt(PyObject *x, PyObject *y, PyObject *compare) {
+ if (compare == NULL)
+ return PyObject_RichCompareBool(x, y, Py_LT);
+
+ ScopedPyObjectPtr res(PyObject_CallFunctionObjArgs(compare, x, y, NULL));
+ if (res == NULL)
+ return -1;
+ if (!PyInt_Check(res)) {
+ PyErr_Format(PyExc_TypeError,
+ "comparison function must return int, not %.200s",
+ Py_TYPE(res)->tp_name);
+ return -1;
+ }
+ return PyInt_AsLong(res) < 0;
+}
+
+// Copied from uarrsort.c but swaps memcpy swaps with protobuf/python swaps
+// TODO(anuraag): Is there a better way to do this then reinventing the wheel?
+static int InternalQuickSort(RepeatedCompositeContainer* self,
+ Py_ssize_t start,
+ Py_ssize_t limit,
+ PyObject* cmp,
+ PyObject* keyfunc) {
+ if (limit - start <= 1)
+ return 0; // Nothing to sort.
+
+ GOOGLE_CHECK_ATTACHED(self);
+
+ Message* message = self->message;
+ const Reflection* reflection = message->GetReflection();
+ const FieldDescriptor* descriptor = self->parent_field_descriptor;
+ Py_ssize_t left;
+ Py_ssize_t right;
+
+ PyObject* children = self->child_messages;
+
+ do {
+ left = start;
+ right = limit;
+ ScopedPyObjectPtr mid(
+ GET_KEY(keyfunc, PyList_GET_ITEM(children, (start + limit) / 2)));
+ do {
+ ScopedPyObjectPtr key(GET_KEY(keyfunc, PyList_GET_ITEM(children, left)));
+ int is_lt = islt(key, mid, cmp);
+ if (is_lt == -1)
+ return -1;
+ /* array[left]<x */
+ while (is_lt) {
+ ++left;
+ ScopedPyObjectPtr key(GET_KEY(keyfunc,
+ PyList_GET_ITEM(children, left)));
+ is_lt = islt(key, mid, cmp);
+ if (is_lt == -1)
+ return -1;
+ }
+ key.reset(GET_KEY(keyfunc, PyList_GET_ITEM(children, right - 1)));
+ is_lt = islt(mid, key, cmp);
+ if (is_lt == -1)
+ return -1;
+ while (is_lt) {
+ --right;
+ ScopedPyObjectPtr key(GET_KEY(keyfunc,
+ PyList_GET_ITEM(children, right - 1)));
+ is_lt = islt(mid, key, cmp);
+ if (is_lt == -1)
+ return -1;
+ }
+ if (left < right) {
+ --right;
+ if (left < right) {
+ reflection->SwapElements(message, descriptor, left, right);
+ PyObject* tmp = PyList_GET_ITEM(children, left);
+ PyList_SET_ITEM(children, left, PyList_GET_ITEM(children, right));
+ PyList_SET_ITEM(children, right, tmp);
+ }
+ ++left;
+ }
+ } while (left < right);
+
+ if ((right - start) < (limit - left)) {
+ /* sort [start..right[ */
+ if (start < (right - 1)) {
+ InternalQuickSort(self, start, right, cmp, keyfunc);
+ }
+
+ /* sort [left..limit[ */
+ start = left;
+ } else {
+ /* sort [left..limit[ */
+ if (left < (limit - 1)) {
+ InternalQuickSort(self, left, limit, cmp, keyfunc);
+ }
+
+ /* sort [start..right[ */
+ limit = right;
+ }
+ } while (start < (limit - 1));
+
+ return 0;
+}
+
+#undef GET_KEY
+
+// ---------------------------------------------------------------------
+// len()
+
+static Py_ssize_t Length(RepeatedCompositeContainer* self) {
+ Message* message = self->message;
+ if (message != NULL) {
+ return message->GetReflection()->FieldSize(*message,
+ 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.
+ return PyList_GET_SIZE(self->child_messages);
+ }
+}
+
+// Returns 0 if successful; returns -1 and sets an exception if
+// unsuccessful.
+static int UpdateChildMessages(RepeatedCompositeContainer* self) {
+ if (self->message == NULL)
+ return 0;
+
+ // A MergeFrom on a parent message could have caused extra messages to be
+ // added in the underlying protobuf so add them to our list. They can never
+ // be removed in such a way so there's no need to worry about that.
+ Py_ssize_t message_length = Length(self);
+ Py_ssize_t child_length = PyList_GET_SIZE(self->child_messages);
+ Message* message = self->message;
+ const 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);
+ CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init,
+ sub_message.GetDescriptor());
+ ScopedPyObjectPtr py_cmsg(reinterpret_cast<PyObject*>(cmsg));
+ if (cmsg == NULL) {
+ return -1;
+ }
+ cmsg->owner = self->owner;
+ cmsg->message = const_cast<Message*>(&sub_message);
+ cmsg->parent = self->parent;
+ if (PyList_Append(self->child_messages, py_cmsg) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------
+// add()
+
+static PyObject* AddToAttached(RepeatedCompositeContainer* self,
+ PyObject* args,
+ PyObject* kwargs) {
+ GOOGLE_CHECK_ATTACHED(self);
+
+ if (UpdateChildMessages(self) < 0) {
+ return NULL;
+ }
+ if (cmessage::AssureWritable(self->parent) == -1)
+ return NULL;
+ Message* message = self->message;
+ Message* sub_message =
+ message->GetReflection()->AddMessage(message,
+ self->parent_field_descriptor);
+ CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init,
+ sub_message->GetDescriptor());
+ if (cmsg == NULL)
+ return NULL;
+
+ cmsg->owner = self->owner;
+ cmsg->message = sub_message;
+ cmsg->parent = self->parent;
+ if (cmessage::InitAttributes(cmsg, kwargs) < 0) {
+ Py_DECREF(cmsg);
+ return NULL;
+ }
+
+ PyObject* py_cmsg = reinterpret_cast<PyObject*>(cmsg);
+ if (PyList_Append(self->child_messages, py_cmsg) < 0) {
+ Py_DECREF(py_cmsg);
+ return NULL;
+ }
+ return py_cmsg;
+}
+
+static PyObject* AddToReleased(RepeatedCompositeContainer* self,
+ PyObject* args,
+ PyObject* kwargs) {
+ GOOGLE_CHECK_RELEASED(self);
+
+ // Create a new Message detached from the rest.
+ PyObject* py_cmsg = PyEval_CallObjectWithKeywords(
+ self->subclass_init, NULL, kwargs);
+ if (py_cmsg == NULL)
+ return NULL;
+
+ if (PyList_Append(self->child_messages, py_cmsg) < 0) {
+ Py_DECREF(py_cmsg);
+ return NULL;
+ }
+ return py_cmsg;
+}
+
+PyObject* Add(RepeatedCompositeContainer* self,
+ PyObject* args,
+ PyObject* kwargs) {
+ if (self->message == NULL)
+ return AddToReleased(self, args, kwargs);
+ else
+ return AddToAttached(self, args, kwargs);
+}
+
+// ---------------------------------------------------------------------
+// extend()
+
+PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value) {
+ cmessage::AssureWritable(self->parent);
+ if (UpdateChildMessages(self) < 0) {
+ return NULL;
+ }
+ ScopedPyObjectPtr iter(PyObject_GetIter(value));
+ if (iter == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+ return NULL;
+ }
+ ScopedPyObjectPtr next;
+ while ((next.reset(PyIter_Next(iter))) != NULL) {
+ if (!PyObject_TypeCheck(next, &CMessage_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Not a cmessage");
+ return NULL;
+ }
+ ScopedPyObjectPtr new_message(Add(self, NULL, NULL));
+ if (new_message == NULL) {
+ return NULL;
+ }
+ CMessage* new_cmessage = reinterpret_cast<CMessage*>(new_message.get());
+ if (cmessage::MergeFrom(new_cmessage, next) == NULL) {
+ return NULL;
+ }
+ }
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject* MergeFrom(RepeatedCompositeContainer* self, PyObject* other) {
+ if (UpdateChildMessages(self) < 0) {
+ return NULL;
+ }
+ return Extend(self, other);
+}
+
+PyObject* Subscript(RepeatedCompositeContainer* self, PyObject* slice) {
+ if (UpdateChildMessages(self) < 0) {
+ 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,
+ PyObject* slice,
+ PyObject* value) {
+ if (UpdateChildMessages(self) < 0) {
+ return -1;
+ }
+ if (value != NULL) {
+ PyErr_SetString(PyExc_TypeError, "does not support assignment");
+ return -1;
+ }
+
+ // Delete from the underlying Message, if any.
+ if (self->message != NULL) {
+ if (cmessage::InternalDeleteRepeatedField(self->message,
+ self->parent_field_descriptor,
+ slice,
+ self->child_messages) < 0) {
+ return -1;
+ }
+ } else {
+ 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<PySliceObject*>(slice),
+#endif
+ length, &from, &to, &step, &slicelength) == -1) {
+ return -1;
+ }
+ return PySequence_DelSlice(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;
+ }
+ return PySequence_DelItem(self->child_messages, from);
+ }
+ }
+
+ return 0;
+}
+
+static PyObject* Remove(RepeatedCompositeContainer* self, PyObject* value) {
+ if (UpdateChildMessages(self) < 0) {
+ return NULL;
+ }
+ Py_ssize_t index = PySequence_Index(self->child_messages, value);
+ if (index == -1) {
+ return NULL;
+ }
+ ScopedPyObjectPtr py_index(PyLong_FromLong(index));
+ if (AssignSubscript(self, py_index, NULL) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject* RichCompare(RepeatedCompositeContainer* self,
+ PyObject* other,
+ int opid) {
+ if (UpdateChildMessages(self) < 0) {
+ return NULL;
+ }
+ if (!PyObject_TypeCheck(other, &RepeatedCompositeContainer_Type)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Can only compare repeated composite fields "
+ "against other repeated composite fields.");
+ return NULL;
+ }
+ if (opid == Py_EQ || opid == Py_NE) {
+ // TODO(anuraag): Don't make new lists just for this...
+ ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
+ if (full_slice == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr list(Subscript(self, full_slice));
+ if (list == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr other_list(
+ Subscript(
+ reinterpret_cast<RepeatedCompositeContainer*>(other), full_slice));
+ if (other_list == NULL) {
+ return NULL;
+ }
+ return PyObject_RichCompare(list, other_list, opid);
+ } else {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+}
+
+// ---------------------------------------------------------------------
+// sort()
+
+static PyObject* SortAttached(RepeatedCompositeContainer* self,
+ PyObject* args,
+ PyObject* kwds) {
+ // Sort the underlying Message array.
+ PyObject *compare = NULL;
+ int reverse = 0;
+ PyObject *keyfunc = NULL;
+ static char *kwlist[] = {"cmp", "key", "reverse", 0};
+
+ if (args != NULL) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:sort",
+ kwlist, &compare, &keyfunc, &reverse))
+ return NULL;
+ }
+ if (compare == Py_None)
+ compare = NULL;
+ if (keyfunc == Py_None)
+ keyfunc = NULL;
+
+ const Py_ssize_t length = Length(self);
+ if (InternalQuickSort(self, 0, length, compare, keyfunc) < 0)
+ return NULL;
+
+ // Finally reverse the result if requested.
+ if (reverse) {
+ Message* message = self->message;
+ const Reflection* reflection = message->GetReflection();
+ const FieldDescriptor* descriptor = self->parent_field_descriptor;
+
+ // Reverse the Message array.
+ for (int i = 0; i < length / 2; ++i)
+ reflection->SwapElements(message, descriptor, i, length - i - 1);
+
+ // Reverse the Python list.
+ ScopedPyObjectPtr res(PyObject_CallMethod(self->child_messages,
+ "reverse", NULL));
+ if (res == NULL)
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject* SortReleased(RepeatedCompositeContainer* self,
+ PyObject* args,
+ PyObject* kwds) {
+ ScopedPyObjectPtr m(PyObject_GetAttrString(self->child_messages, "sort"));
+ if (m == NULL)
+ return NULL;
+ if (PyObject_Call(m, args, kwds) == NULL)
+ return NULL;
+ Py_RETURN_NONE;
+}
+
+static PyObject* Sort(RepeatedCompositeContainer* self,
+ PyObject* args,
+ PyObject* kwds) {
+ // Support the old sort_function argument for backwards
+ // compatibility.
+ if (kwds != NULL) {
+ PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function");
+ if (sort_func != NULL) {
+ // Must set before deleting as sort_func is a borrowed reference
+ // and kwds might be the only thing keeping it alive.
+ PyDict_SetItemString(kwds, "cmp", sort_func);
+ PyDict_DelItemString(kwds, "sort_function");
+ }
+ }
+
+ if (UpdateChildMessages(self) < 0) {
+ return NULL;
+ }
+ if (self->message == NULL) {
+ return SortReleased(self, args, kwds);
+ } else {
+ return SortAttached(self, args, kwds);
+ }
+}
+
+// ---------------------------------------------------------------------
+
+static PyObject* Item(RepeatedCompositeContainer* self, Py_ssize_t index) {
+ if (UpdateChildMessages(self) < 0) {
+ return NULL;
+ }
+ Py_ssize_t length = Length(self);
+ if (index < 0) {
+ index = length + index;
+ }
+ PyObject* item = PyList_GetItem(self->child_messages, index);
+ if (item == NULL) {
+ return NULL;
+ }
+ Py_INCREF(item);
+ return item;
+}
+
+static PyObject* Pop(RepeatedCompositeContainer* self,
+ PyObject* args) {
+ Py_ssize_t index = -1;
+ if (!PyArg_ParseTuple(args, "|n", &index)) {
+ return NULL;
+ }
+ PyObject* item = Item(self, index);
+ if (item == NULL) {
+ PyErr_Format(PyExc_IndexError,
+ "list index (%zd) out of range",
+ index);
+ return NULL;
+ }
+ ScopedPyObjectPtr py_index(PyLong_FromSsize_t(index));
+ if (AssignSubscript(self, py_index, NULL) < 0) {
+ return NULL;
+ }
+ return item;
+}
+
+// The caller takes ownership of the returned Message.
+Message* ReleaseLast(const FieldDescriptor* field,
+ const Descriptor* type,
+ Message* message) {
+ GOOGLE_CHECK_NOTNULL(field);
+ GOOGLE_CHECK_NOTNULL(type);
+ GOOGLE_CHECK_NOTNULL(message);
+
+ Message* released_message = message->GetReflection()->ReleaseLast(
+ message, field);
+ // TODO(tibell): Deal with proto1.
+
+ // ReleaseMessage will return NULL which differs from
+ // child_cmessage->message, if the field does not exist. In this case,
+ // the latter points to the default instance via a const_cast<>, so we
+ // have to reset it to a new mutable object since we are taking ownership.
+ if (released_message == NULL) {
+ const Message* prototype =
+ cmessage::GetMessageFactory()->GetPrototype(type);
+ GOOGLE_CHECK_NOTNULL(prototype);
+ return prototype->New();
+ } else {
+ return released_message;
+ }
+}
+
+// Release field of message and transfer the ownership to cmessage.
+void ReleaseLastTo(const FieldDescriptor* field,
+ Message* message,
+ CMessage* cmessage) {
+ GOOGLE_CHECK_NOTNULL(field);
+ GOOGLE_CHECK_NOTNULL(message);
+ GOOGLE_CHECK_NOTNULL(cmessage);
+
+ shared_ptr<Message> released_message(
+ ReleaseLast(field, cmessage->message->GetDescriptor(), message));
+ cmessage->parent = NULL;
+ cmessage->parent_field_descriptor = NULL;
+ cmessage->message = released_message.get();
+ cmessage->read_only = false;
+ cmessage::SetOwner(cmessage, released_message);
+}
+
+// Called to release a container using
+// ClearField('container_field_name') on the parent.
+int Release(RepeatedCompositeContainer* self) {
+ if (UpdateChildMessages(self) < 0) {
+ PyErr_WriteUnraisable(PyBytes_FromString("Failed to update released "
+ "messages"));
+ return -1;
+ }
+
+ Message* message = self->message;
+ 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
+ // starting with the last one.
+ const Py_ssize_t size = PyList_GET_SIZE(self->child_messages);
+ GOOGLE_DCHECK_EQ(size, message->GetReflection()->FieldSize(*message, field));
+ for (Py_ssize_t i = size - 1; i >= 0; --i) {
+ CMessage* child_cmessage = reinterpret_cast<CMessage*>(
+ PyList_GET_ITEM(self->child_messages, i));
+ ReleaseLastTo(field, message, child_cmessage);
+ }
+
+ // Detach from containing message.
+ self->parent = NULL;
+ self->parent_field_descriptor = NULL;
+ self->message = NULL;
+ self->owner.reset();
+
+ return 0;
+}
+
+int SetOwner(RepeatedCompositeContainer* self,
+ const shared_ptr<Message>& new_owner) {
+ GOOGLE_CHECK_ATTACHED(self);
+
+ self->owner = new_owner;
+ const Py_ssize_t n = PyList_GET_SIZE(self->child_messages);
+ for (Py_ssize_t i = 0; i < n; ++i) {
+ PyObject* msg = PyList_GET_ITEM(self->child_messages, i);
+ if (cmessage::SetOwner(reinterpret_cast<CMessage*>(msg), new_owner) == -1) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+// The private constructor of RepeatedCompositeContainer objects.
+PyObject *NewContainer(
+ CMessage* parent,
+ const FieldDescriptor* parent_field_descriptor,
+ PyObject *concrete_class) {
+ if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+ return NULL;
+ }
+
+ RepeatedCompositeContainer* self =
+ reinterpret_cast<RepeatedCompositeContainer*>(
+ 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 reinterpret_cast<PyObject*>(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<PyObject*>(self));
+}
+
+static PySequenceMethods SqMethods = {
+ (lenfunc)Length, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ (ssizeargfunc)Item /* sq_item */
+};
+
+static PyMappingMethods MpMethods = {
+ (lenfunc)Length, /* mp_length */
+ (binaryfunc)Subscript, /* mp_subscript */
+ (objobjargproc)AssignSubscript,/* mp_ass_subscript */
+};
+
+static PyMethodDef Methods[] = {
+ { "add", (PyCFunction) Add, METH_VARARGS | METH_KEYWORDS,
+ "Adds an object to the repeated container." },
+ { "extend", (PyCFunction) Extend, METH_O,
+ "Adds objects to the repeated container." },
+ { "pop", (PyCFunction)Pop, METH_VARARGS,
+ "Removes an object from the repeated container and returns it." },
+ { "remove", (PyCFunction) Remove, METH_O,
+ "Removes an object from the repeated container." },
+ { "sort", (PyCFunction) Sort, METH_VARARGS | METH_KEYWORDS,
+ "Sorts the repeated container." },
+ { "MergeFrom", (PyCFunction) MergeFrom, METH_O,
+ "Adds objects to the repeated container." },
+ { NULL, NULL }
+};
+
+} // namespace repeated_composite_container
+
+PyTypeObject RepeatedCompositeContainer_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ // Keep the fully qualified _message symbol in a line for opensource.
+ "google.protobuf.pyext._message."
+ "RepeatedCompositeContainer", // tp_name
+ sizeof(RepeatedCompositeContainer), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)repeated_composite_container::Dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ &repeated_composite_container::SqMethods, // tp_as_sequence
+ &repeated_composite_container::MpMethods, // 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
+ "A Repeated scalar container", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ (richcmpfunc)repeated_composite_container::RichCompare, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ repeated_composite_container::Methods, // tp_methods
+ 0, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ 0, // tp_init
+};
+
+} // namespace python
+} // namespace protobuf
+} // namespace google
diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h
new file mode 100644
index 00000000..ce7cee0f
--- /dev/null
+++ b/python/google/protobuf/pyext/repeated_composite_container.h
@@ -0,0 +1,177 @@
+// 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: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__
+
+#include <Python.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <vector>
+
+namespace google {
+namespace protobuf {
+
+class FieldDescriptor;
+class Message;
+
+using internal::shared_ptr;
+
+namespace python {
+
+struct CMessage;
+
+// A RepeatedCompositeContainer can be in one of two states: attached
+// or released.
+//
+// When in the attached state all modifications to the container are
+// done both on the 'message' and on the 'child_messages'
+// list. In this state all Messages referred to by the children in
+// 'child_messages' are owner by the 'owner'.
+//
+// When in the released state 'message', 'owner', 'parent', and
+// 'parent_field_descriptor' are NULL.
+typedef struct RepeatedCompositeContainer {
+ PyObject_HEAD;
+
+ // This is the top-level C++ Message object that owns the whole
+ // proto tree. Every Python RepeatedCompositeContainer 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<Message> owner;
+
+ // Weak reference to parent object. May be NULL. Used to make sure
+ // the parent is writable before modifying the
+ // RepeatedCompositeContainer.
+ CMessage* parent;
+
+ // A descriptor used to modify the underlying 'message'.
+ // The pointer is owned by the global DescriptorPool.
+ const FieldDescriptor* parent_field_descriptor;
+
+ // Pointer to the C++ Message that contains this container. The
+ // RepeatedCompositeContainer does not own this pointer.
+ //
+ // If NULL, this message has been released from its parent (by
+ // calling Clear() or ClearField() on the parent.
+ Message* message;
+
+ // A callable that is used to create new child messages.
+ PyObject* subclass_init;
+
+ // A list of child messages.
+ PyObject* child_messages;
+} RepeatedCompositeContainer;
+
+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 FieldDescriptor* parent_field_descriptor,
+ PyObject *concrete_class);
+
+// Returns the number of items in this repeated composite container.
+static Py_ssize_t Length(RepeatedCompositeContainer* self);
+
+// Appends a new CMessage to the container and returns it. The
+// CMessage is initialized using the content of kwargs.
+//
+// Returns a new reference if successful; returns NULL and sets an
+// exception if unsuccessful.
+PyObject* Add(RepeatedCompositeContainer* self,
+ PyObject* args,
+ PyObject* kwargs);
+
+// Appends all the CMessages in the input iterator to the container.
+//
+// Returns None if successful; returns NULL and sets an exception if
+// unsuccessful.
+PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value);
+
+// Appends a new message to the container for each message in the
+// input iterator, merging each data element in. Equivalent to extend.
+//
+// Returns None if successful; returns NULL and sets an exception if
+// unsuccessful.
+PyObject* MergeFrom(RepeatedCompositeContainer* self, PyObject* other);
+
+// Accesses messages in the container.
+//
+// Returns a new reference to the message for an integer parameter.
+// Returns a new reference to a list of messages for a slice.
+PyObject* Subscript(RepeatedCompositeContainer* self, PyObject* slice);
+
+// Deletes items from the container (cannot be used for assignment).
+//
+// Returns 0 on success, -1 on failure.
+int AssignSubscript(RepeatedCompositeContainer* self,
+ PyObject* slice,
+ PyObject* value);
+
+// Releases the messages in the container to the given message.
+//
+// Returns 0 on success, -1 on failure.
+int ReleaseToMessage(RepeatedCompositeContainer* self, Message* new_message);
+
+// Releases the messages in the container to a new message.
+//
+// Returns 0 on success, -1 on failure.
+int Release(RepeatedCompositeContainer* self);
+
+// Returns 0 on success, -1 on failure.
+int SetOwner(RepeatedCompositeContainer* self,
+ const shared_ptr<Message>& new_owner);
+
+// Removes the last element of the repeated message field 'field' on
+// the Message 'message', and transfers the ownership of the released
+// Message to 'cmessage'.
+//
+// Corresponds to reflection api method ReleaseMessage.
+void ReleaseLastTo(const FieldDescriptor* field,
+ Message* message,
+ CMessage* cmessage);
+
+} // namespace repeated_composite_container
+} // namespace python
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc
new file mode 100644
index 00000000..110a4c85
--- /dev/null
+++ b/python/google/protobuf/pyext/repeated_scalar_container.cc
@@ -0,0 +1,813 @@
+// 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: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#include <google/protobuf/pyext/repeated_scalar_container.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#if PY_MAJOR_VERSION >= 3
+ #define PyInt_FromLong PyLong_FromLong
+ #if PY_VERSION_HEX < 0x03030000
+ #error "Python 3.0 - 3.2 are not supported."
+ #else
+ #define PyString_AsString(ob) \
+ (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob))
+ #endif
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace repeated_scalar_container {
+
+static int InternalAssignRepeatedField(
+ RepeatedScalarContainer* self, PyObject* list) {
+ self->message->GetReflection()->ClearField(self->message,
+ 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) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static Py_ssize_t Len(RepeatedScalarContainer* self) {
+ Message* message = self->message;
+ return message->GetReflection()->FieldSize(*message,
+ self->parent_field_descriptor);
+}
+
+static int AssignItem(RepeatedScalarContainer* self,
+ Py_ssize_t index,
+ PyObject* arg) {
+ cmessage::AssureWritable(self->parent);
+ Message* message = self->message;
+ const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+
+ const Reflection* reflection = message->GetReflection();
+ int field_size = reflection->FieldSize(*message, field_descriptor);
+ if (index < 0) {
+ index = field_size + index;
+ }
+ if (index < 0 || index >= field_size) {
+ PyErr_Format(PyExc_IndexError,
+ "list assignment index (%d) out of range",
+ static_cast<int>(index));
+ return -1;
+ }
+
+ if (arg == NULL) {
+ ScopedPyObjectPtr py_index(PyLong_FromLong(index));
+ return cmessage::InternalDeleteRepeatedField(message, field_descriptor,
+ py_index, NULL);
+ }
+
+ if (PySequence_Check(arg) && !(PyBytes_Check(arg) || PyUnicode_Check(arg))) {
+ PyErr_SetString(PyExc_TypeError, "Value must be scalar");
+ return -1;
+ }
+
+ switch (field_descriptor->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: {
+ GOOGLE_CHECK_GET_INT32(arg, value, -1);
+ reflection->SetRepeatedInt32(message, field_descriptor, index, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_INT64: {
+ GOOGLE_CHECK_GET_INT64(arg, value, -1);
+ reflection->SetRepeatedInt64(message, field_descriptor, index, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT32: {
+ GOOGLE_CHECK_GET_UINT32(arg, value, -1);
+ reflection->SetRepeatedUInt32(message, field_descriptor, index, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ GOOGLE_CHECK_GET_UINT64(arg, value, -1);
+ reflection->SetRepeatedUInt64(message, field_descriptor, index, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ GOOGLE_CHECK_GET_FLOAT(arg, value, -1);
+ reflection->SetRepeatedFloat(message, field_descriptor, index, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ GOOGLE_CHECK_GET_DOUBLE(arg, value, -1);
+ reflection->SetRepeatedDouble(message, field_descriptor, index, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_BOOL: {
+ GOOGLE_CHECK_GET_BOOL(arg, value, -1);
+ reflection->SetRepeatedBool(message, field_descriptor, index, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING: {
+ if (!CheckAndSetString(
+ arg, message, field_descriptor, reflection, false, index)) {
+ return -1;
+ }
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ GOOGLE_CHECK_GET_INT32(arg, value, -1);
+ if (reflection->SupportsUnknownEnumValues()) {
+ reflection->SetRepeatedEnumValue(message, field_descriptor, index,
+ value);
+ } else {
+ const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+ const EnumValueDescriptor* enum_value =
+ enum_descriptor->FindValueByNumber(value);
+ if (enum_value != NULL) {
+ reflection->SetRepeatedEnum(message, field_descriptor, index,
+ enum_value);
+ } else {
+ ScopedPyObjectPtr s(PyObject_Str(arg));
+ if (s != NULL) {
+ PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
+ PyString_AsString(s));
+ }
+ return -1;
+ }
+ }
+ break;
+ }
+ default:
+ PyErr_Format(
+ PyExc_SystemError, "Adding value to a field of unknown type %d",
+ field_descriptor->cpp_type());
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject* Item(RepeatedScalarContainer* self, Py_ssize_t index) {
+ Message* message = self->message;
+ const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+ const Reflection* reflection = message->GetReflection();
+
+ int field_size = reflection->FieldSize(*message, field_descriptor);
+ if (index < 0) {
+ index = field_size + index;
+ }
+ if (index < 0 || index >= field_size) {
+ PyErr_Format(PyExc_IndexError,
+ "list index (%zd) out of range",
+ index);
+ return NULL;
+ }
+
+ PyObject* result = NULL;
+ switch (field_descriptor->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: {
+ int32 value = reflection->GetRepeatedInt32(
+ *message, field_descriptor, index);
+ result = PyInt_FromLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_INT64: {
+ int64 value = reflection->GetRepeatedInt64(
+ *message, field_descriptor, index);
+ result = PyLong_FromLongLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT32: {
+ uint32 value = reflection->GetRepeatedUInt32(
+ *message, field_descriptor, index);
+ result = PyLong_FromLongLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ uint64 value = reflection->GetRepeatedUInt64(
+ *message, field_descriptor, index);
+ result = PyLong_FromUnsignedLongLong(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ float value = reflection->GetRepeatedFloat(
+ *message, field_descriptor, index);
+ result = PyFloat_FromDouble(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ double value = reflection->GetRepeatedDouble(
+ *message, field_descriptor, index);
+ result = PyFloat_FromDouble(value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_BOOL: {
+ bool value = reflection->GetRepeatedBool(
+ *message, field_descriptor, index);
+ result = PyBool_FromLong(value ? 1 : 0);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ const EnumValueDescriptor* enum_value =
+ message->GetReflection()->GetRepeatedEnum(
+ *message, field_descriptor, index);
+ result = PyInt_FromLong(enum_value->number());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING: {
+ string value = reflection->GetRepeatedString(
+ *message, field_descriptor, index);
+ result = ToStringObject(field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ PyObject* py_cmsg = PyObject_CallObject(reinterpret_cast<PyObject*>(
+ &CMessage_Type), NULL);
+ if (py_cmsg == NULL) {
+ return NULL;
+ }
+ CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
+ const Message& msg = reflection->GetRepeatedMessage(
+ *message, field_descriptor, index);
+ cmsg->owner = self->owner;
+ cmsg->parent = self->parent;
+ cmsg->message = const_cast<Message*>(&msg);
+ cmsg->read_only = false;
+ result = reinterpret_cast<PyObject*>(py_cmsg);
+ break;
+ }
+ default:
+ PyErr_Format(
+ PyExc_SystemError,
+ "Getting value from a repeated field of unknown type %d",
+ field_descriptor->cpp_type());
+ }
+
+ return result;
+}
+
+static PyObject* Subscript(RepeatedScalarContainer* self, PyObject* slice) {
+ Py_ssize_t from;
+ Py_ssize_t to;
+ Py_ssize_t step;
+ Py_ssize_t length;
+ Py_ssize_t slicelength;
+ bool return_list = false;
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(slice)) {
+ from = to = PyInt_AsLong(slice);
+ } else // NOLINT
+#endif
+ if (PyLong_Check(slice)) {
+ from = to = PyLong_AsLong(slice);
+ } else if (PySlice_Check(slice)) {
+ length = Len(self);
+#if PY_MAJOR_VERSION >= 3
+ if (PySlice_GetIndicesEx(slice,
+#else
+ if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice),
+#endif
+ length, &from, &to, &step, &slicelength) == -1) {
+ return NULL;
+ }
+ return_list = true;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "list indices must be integers");
+ return NULL;
+ }
+
+ if (!return_list) {
+ return Item(self, from);
+ }
+
+ PyObject* list = PyList_New(0);
+ if (list == NULL) {
+ return NULL;
+ }
+ if (from <= to) {
+ if (step < 0) {
+ return list;
+ }
+ for (Py_ssize_t index = from; index < to; index += step) {
+ if (index < 0 || index >= length) {
+ break;
+ }
+ ScopedPyObjectPtr s(Item(self, index));
+ PyList_Append(list, s);
+ }
+ } else {
+ if (step > 0) {
+ return list;
+ }
+ for (Py_ssize_t index = from; index > to; index += step) {
+ if (index < 0 || index >= length) {
+ break;
+ }
+ ScopedPyObjectPtr s(Item(self, index));
+ PyList_Append(list, s);
+ }
+ }
+ return list;
+}
+
+PyObject* Append(RepeatedScalarContainer* self, PyObject* item) {
+ cmessage::AssureWritable(self->parent);
+ Message* message = self->message;
+ const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+
+ const Reflection* reflection = message->GetReflection();
+ switch (field_descriptor->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: {
+ GOOGLE_CHECK_GET_INT32(item, value, NULL);
+ reflection->AddInt32(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_INT64: {
+ GOOGLE_CHECK_GET_INT64(item, value, NULL);
+ reflection->AddInt64(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT32: {
+ GOOGLE_CHECK_GET_UINT32(item, value, NULL);
+ reflection->AddUInt32(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ GOOGLE_CHECK_GET_UINT64(item, value, NULL);
+ reflection->AddUInt64(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ GOOGLE_CHECK_GET_FLOAT(item, value, NULL);
+ reflection->AddFloat(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ GOOGLE_CHECK_GET_DOUBLE(item, value, NULL);
+ reflection->AddDouble(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_BOOL: {
+ GOOGLE_CHECK_GET_BOOL(item, value, NULL);
+ reflection->AddBool(message, field_descriptor, value);
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING: {
+ if (!CheckAndSetString(
+ item, message, field_descriptor, reflection, true, -1)) {
+ return NULL;
+ }
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ GOOGLE_CHECK_GET_INT32(item, value, NULL);
+ if (reflection->SupportsUnknownEnumValues()) {
+ reflection->AddEnumValue(message, field_descriptor, value);
+ } else {
+ const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+ const EnumValueDescriptor* enum_value =
+ enum_descriptor->FindValueByNumber(value);
+ if (enum_value != NULL) {
+ reflection->AddEnum(message, field_descriptor, enum_value);
+ } else {
+ ScopedPyObjectPtr s(PyObject_Str(item));
+ if (s != NULL) {
+ PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
+ PyString_AsString(s));
+ }
+ return NULL;
+ }
+ }
+ break;
+ }
+ default:
+ PyErr_Format(
+ PyExc_SystemError, "Adding value to a field of unknown type %d",
+ field_descriptor->cpp_type());
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static int AssSubscript(RepeatedScalarContainer* self,
+ PyObject* slice,
+ PyObject* value) {
+ Py_ssize_t from;
+ Py_ssize_t to;
+ Py_ssize_t step;
+ Py_ssize_t length;
+ Py_ssize_t slicelength;
+ bool create_list = false;
+
+ cmessage::AssureWritable(self->parent);
+ Message* message = self->message;
+ const FieldDescriptor* field_descriptor =
+ self->parent_field_descriptor;
+
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(slice)) {
+ from = to = PyInt_AsLong(slice);
+ } else
+#endif
+ if (PyLong_Check(slice)) {
+ from = to = PyLong_AsLong(slice);
+ } else if (PySlice_Check(slice)) {
+ const Reflection* reflection = message->GetReflection();
+ length = reflection->FieldSize(*message, field_descriptor);
+#if PY_MAJOR_VERSION >= 3
+ if (PySlice_GetIndicesEx(slice,
+#else
+ if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice),
+#endif
+ length, &from, &to, &step, &slicelength) == -1) {
+ return -1;
+ }
+ create_list = true;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "list indices must be integers");
+ return -1;
+ }
+
+ if (value == NULL) {
+ return cmessage::InternalDeleteRepeatedField(
+ message, field_descriptor, slice, NULL);
+ }
+
+ if (!create_list) {
+ return AssignItem(self, from, value);
+ }
+
+ ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
+ if (full_slice == NULL) {
+ return -1;
+ }
+ ScopedPyObjectPtr new_list(Subscript(self, full_slice));
+ if (new_list == NULL) {
+ return -1;
+ }
+ if (PySequence_SetSlice(new_list, from, to, value) < 0) {
+ return -1;
+ }
+
+ return InternalAssignRepeatedField(self, new_list);
+}
+
+PyObject* Extend(RepeatedScalarContainer* self, PyObject* value) {
+ cmessage::AssureWritable(self->parent);
+
+ // TODO(ptucker): Deprecate this behavior. b/18413862
+ if (value == Py_None) {
+ Py_RETURN_NONE;
+ }
+ if ((Py_TYPE(value)->tp_as_sequence == NULL) && PyObject_Not(value)) {
+ Py_RETURN_NONE;
+ }
+
+ ScopedPyObjectPtr iter(PyObject_GetIter(value));
+ if (iter == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+ return NULL;
+ }
+ ScopedPyObjectPtr next;
+ while ((next.reset(PyIter_Next(iter))) != NULL) {
+ if (Append(self, next) == NULL) {
+ return NULL;
+ }
+ }
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject* Insert(RepeatedScalarContainer* self, PyObject* args) {
+ Py_ssize_t index;
+ PyObject* value;
+ if (!PyArg_ParseTuple(args, "lO", &index, &value)) {
+ return NULL;
+ }
+ ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
+ ScopedPyObjectPtr new_list(Subscript(self, full_slice));
+ if (PyList_Insert(new_list, index, value) < 0) {
+ return NULL;
+ }
+ int ret = InternalAssignRepeatedField(self, new_list);
+ if (ret < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject* Remove(RepeatedScalarContainer* self, PyObject* value) {
+ Py_ssize_t match_index = -1;
+ for (Py_ssize_t i = 0; i < Len(self); ++i) {
+ ScopedPyObjectPtr elem(Item(self, i));
+ if (PyObject_RichCompareBool(elem, value, Py_EQ)) {
+ match_index = i;
+ break;
+ }
+ }
+ if (match_index == -1) {
+ PyErr_SetString(PyExc_ValueError, "remove(x): x not in container");
+ return NULL;
+ }
+ if (AssignItem(self, match_index, NULL) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject* RichCompare(RepeatedScalarContainer* self,
+ PyObject* other,
+ int opid) {
+ if (opid != Py_EQ && opid != Py_NE) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ // Copy the contents of this repeated scalar container, and other if it is
+ // also a repeated scalar container, into Python lists so we can delegate
+ // to the list's compare method.
+
+ ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
+ if (full_slice == NULL) {
+ return NULL;
+ }
+
+ ScopedPyObjectPtr other_list_deleter;
+ if (PyObject_TypeCheck(other, &RepeatedScalarContainer_Type)) {
+ other_list_deleter.reset(Subscript(
+ reinterpret_cast<RepeatedScalarContainer*>(other), full_slice));
+ other = other_list_deleter.get();
+ }
+
+ ScopedPyObjectPtr list(Subscript(self, full_slice));
+ if (list == NULL) {
+ return NULL;
+ }
+ return PyObject_RichCompare(list, other, opid);
+}
+
+PyObject* Reduce(RepeatedScalarContainer* unused_self) {
+ PyErr_Format(
+ PickleError_class,
+ "can't pickle repeated message fields, convert to list first");
+ return NULL;
+}
+
+static PyObject* Sort(RepeatedScalarContainer* self,
+ PyObject* args,
+ PyObject* kwds) {
+ // Support the old sort_function argument for backwards
+ // compatibility.
+ if (kwds != NULL) {
+ PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function");
+ if (sort_func != NULL) {
+ // Must set before deleting as sort_func is a borrowed reference
+ // and kwds might be the only thing keeping it alive.
+ if (PyDict_SetItemString(kwds, "cmp", sort_func) == -1)
+ return NULL;
+ if (PyDict_DelItemString(kwds, "sort_function") == -1)
+ return NULL;
+ }
+ }
+
+ ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
+ if (full_slice == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr list(Subscript(self, full_slice));
+ if (list == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr m(PyObject_GetAttrString(list, "sort"));
+ if (m == NULL) {
+ return NULL;
+ }
+ ScopedPyObjectPtr res(PyObject_Call(m, args, kwds));
+ if (res == NULL) {
+ return NULL;
+ }
+ int ret = InternalAssignRepeatedField(self, list);
+ if (ret < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject* Pop(RepeatedScalarContainer* self,
+ PyObject* args) {
+ Py_ssize_t index = -1;
+ if (!PyArg_ParseTuple(args, "|n", &index)) {
+ return NULL;
+ }
+ PyObject* item = Item(self, index);
+ if (item == NULL) {
+ PyErr_Format(PyExc_IndexError,
+ "list index (%zd) out of range",
+ index);
+ return NULL;
+ }
+ if (AssignItem(self, index, NULL) < 0) {
+ return NULL;
+ }
+ return item;
+}
+
+// The private constructor of RepeatedScalarContainer objects.
+PyObject *NewContainer(
+ CMessage* parent, const FieldDescriptor* parent_field_descriptor) {
+ if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+ return NULL;
+ }
+
+ RepeatedScalarContainer* self = reinterpret_cast<RepeatedScalarContainer*>(
+ PyType_GenericAlloc(&RepeatedScalarContainer_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;
+
+ return reinterpret_cast<PyObject*>(self);
+}
+
+// Initializes the underlying Message object of "to" so it becomes a new parent
+// repeated scalar, and copies all the values from "from" to it. A child scalar
+// container can be released by passing it as both from and to (e.g. making it
+// the recipient of the new parent message and copying the values from itself).
+static int InitializeAndCopyToParentContainer(
+ RepeatedScalarContainer* from,
+ RepeatedScalarContainer* to) {
+ ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
+ if (full_slice == NULL) {
+ return -1;
+ }
+ ScopedPyObjectPtr values(Subscript(from, full_slice));
+ if (values == NULL) {
+ return -1;
+ }
+ Message* new_message = cmessage::GetMessageFactory()->GetPrototype(
+ from->message->GetDescriptor())->New();
+ to->parent = NULL;
+ to->parent_field_descriptor = from->parent_field_descriptor;
+ to->message = new_message;
+ to->owner.reset(new_message);
+ if (InternalAssignRepeatedField(to, values) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+int Release(RepeatedScalarContainer* self) {
+ return InitializeAndCopyToParentContainer(self, self);
+}
+
+PyObject* DeepCopy(RepeatedScalarContainer* self, PyObject* arg) {
+ RepeatedScalarContainer* clone = reinterpret_cast<RepeatedScalarContainer*>(
+ PyType_GenericAlloc(&RepeatedScalarContainer_Type, 0));
+ if (clone == NULL) {
+ return NULL;
+ }
+
+ if (InitializeAndCopyToParentContainer(self, clone) < 0) {
+ Py_DECREF(clone);
+ return NULL;
+ }
+ return reinterpret_cast<PyObject*>(clone);
+}
+
+static void Dealloc(RepeatedScalarContainer* self) {
+ self->owner.reset();
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+void SetOwner(RepeatedScalarContainer* self,
+ const shared_ptr<Message>& new_owner) {
+ self->owner = new_owner;
+}
+
+static PySequenceMethods SqMethods = {
+ (lenfunc)Len, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ (ssizeargfunc)Item, /* sq_item */
+ 0, /* sq_slice */
+ (ssizeobjargproc)AssignItem /* sq_ass_item */
+};
+
+static PyMappingMethods MpMethods = {
+ (lenfunc)Len, /* mp_length */
+ (binaryfunc)Subscript, /* mp_subscript */
+ (objobjargproc)AssSubscript, /* mp_ass_subscript */
+};
+
+static PyMethodDef Methods[] = {
+ { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+ "Makes a deep copy of the class." },
+ { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+ "Outputs picklable representation of the repeated field." },
+ { "append", (PyCFunction)Append, METH_O,
+ "Appends an object to the repeated container." },
+ { "extend", (PyCFunction)Extend, METH_O,
+ "Appends objects to the repeated container." },
+ { "insert", (PyCFunction)Insert, METH_VARARGS,
+ "Appends objects to the repeated container." },
+ { "pop", (PyCFunction)Pop, METH_VARARGS,
+ "Removes an object from the repeated container and returns it." },
+ { "remove", (PyCFunction)Remove, METH_O,
+ "Removes an object from the repeated container." },
+ { "sort", (PyCFunction)Sort, METH_VARARGS | METH_KEYWORDS,
+ "Sorts the repeated container."},
+ { NULL, NULL }
+};
+
+} // namespace repeated_scalar_container
+
+PyTypeObject RepeatedScalarContainer_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ // Keep the fully qualified _message symbol in a line for opensource.
+ "google.protobuf.pyext._message."
+ "RepeatedScalarContainer", // tp_name
+ sizeof(RepeatedScalarContainer), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)repeated_scalar_container::Dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ &repeated_scalar_container::SqMethods, // tp_as_sequence
+ &repeated_scalar_container::MpMethods, // 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
+ "A Repeated scalar container", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ (richcmpfunc)repeated_scalar_container::RichCompare, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ repeated_scalar_container::Methods, // tp_methods
+ 0, // tp_members
+ 0, // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ 0, // tp_init
+};
+
+} // namespace python
+} // namespace protobuf
+} // namespace google
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h
new file mode 100644
index 00000000..5dfa21e0
--- /dev/null
+++ b/python/google/protobuf/pyext/repeated_scalar_container.h
@@ -0,0 +1,118 @@
+// 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: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__
+
+#include <Python.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+using internal::shared_ptr;
+
+namespace python {
+
+struct CMessage;
+
+typedef struct RepeatedScalarContainer {
+ PyObject_HEAD;
+
+ // This is the top-level C++ Message object that owns the whole
+ // proto tree. Every Python RepeatedScalarContainer 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<Message> owner;
+
+ // Pointer to the C++ Message that contains this container. The
+ // RepeatedScalarContainer does not own this pointer.
+ Message* message;
+
+ // Weak reference to a parent CMessage object (i.e. may be NULL.)
+ //
+ // Used to make sure all ancestors are also mutable when first
+ // modifying the container.
+ CMessage* parent;
+
+ // Pointer to the parent's descriptor that describes this
+ // field. Used together with the parent's message when making a
+ // default message instance mutable.
+ // The pointer is owned by the global DescriptorPool.
+ const 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 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
+// unsuccessful.
+PyObject* Append(RepeatedScalarContainer* self, PyObject* item);
+
+// Releases the messages in the container to a new message.
+//
+// Returns 0 on success, -1 on failure.
+int Release(RepeatedScalarContainer* self);
+
+// Appends all the elements in the input iterator to the container.
+//
+// Returns None if successful; returns NULL and sets an exception if
+// unsuccessful.
+PyObject* Extend(RepeatedScalarContainer* self, PyObject* value);
+
+// Set the owner field of self and any children of self.
+void SetOwner(RepeatedScalarContainer* self,
+ const shared_ptr<Message>& new_owner);
+
+} // namespace repeated_scalar_container
+} // namespace python
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__
diff --git a/python/google/protobuf/pyext/scoped_pyobject_ptr.h b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
new file mode 100644
index 00000000..18ddd5cd
--- /dev/null
+++ b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
@@ -0,0 +1,97 @@
+// 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: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__
+
+#include <google/protobuf/stubs/common.h>
+
+#include <Python.h>
+
+namespace google {
+class ScopedPyObjectPtr {
+ public:
+ // Constructor. Defaults to initializing with NULL.
+ // There is no way to create an uninitialized ScopedPyObjectPtr.
+ explicit ScopedPyObjectPtr(PyObject* p = NULL) : ptr_(p) { }
+
+ // Destructor. If there is a PyObject object, delete it.
+ ~ScopedPyObjectPtr() {
+ Py_XDECREF(ptr_);
+ }
+
+ // Reset. Deletes the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ PyObject* reset(PyObject* p = NULL) {
+ if (p != ptr_) {
+ Py_XDECREF(ptr_);
+ ptr_ = p;
+ }
+ return ptr_;
+ }
+
+ // Releases ownership of the object.
+ PyObject* release() {
+ PyObject* p = ptr_;
+ ptr_ = NULL;
+ return p;
+ }
+
+ operator PyObject*() { return ptr_; }
+
+ PyObject* operator->() const {
+ assert(ptr_ != NULL);
+ return ptr_;
+ }
+
+ PyObject* get() const { return ptr_; }
+
+ Py_ssize_t refcnt() const { return Py_REFCNT(ptr_); }
+
+ void inc() const { Py_INCREF(ptr_); }
+
+ // Comparison operators.
+ // These return whether a ScopedPyObjectPtr and a raw pointer
+ // refer to the same object, not just to two different but equal
+ // objects.
+ bool operator==(const PyObject* p) const { return ptr_ == p; }
+ bool operator!=(const PyObject* p) const { return ptr_ != p; }
+
+ private:
+ PyObject* ptr_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ScopedPyObjectPtr);
+};
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__
diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py
index 1373c882..55e653a0 100755
--- a/python/google/protobuf/reflection.py
+++ b/python/google/protobuf/reflection.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -50,17 +50,18 @@ __author__ = 'robinson@google.com (Will Robinson)'
from google.protobuf.internal import api_implementation
from google.protobuf import descriptor as descriptor_mod
+from google.protobuf import message
+
_FieldDescriptor = descriptor_mod.FieldDescriptor
if api_implementation.Type() == 'cpp':
- from google.protobuf.internal import cpp_message
- _NewMessage = cpp_message.NewMessage
- _InitMessage = cpp_message.InitMessage
+ from google.protobuf.pyext import cpp_message as message_impl
else:
- from google.protobuf.internal import python_message
- _NewMessage = python_message.NewMessage
- _InitMessage = python_message.InitMessage
+ from google.protobuf.internal import python_message as message_impl
+
+_NewMessage = message_impl.NewMessage
+_InitMessage = message_impl.InitMessage
class GeneratedProtocolMessageType(type):
@@ -84,6 +85,10 @@ class GeneratedProtocolMessageType(type):
myproto_instance = MyProtoClass()
myproto.foo_field = 23
...
+
+ The above example will not work for nested types. If you wish to include them,
+ use reflection.MakeClass() instead of manually instantiating the class in
+ order to create the appropriate class structure.
"""
# Must be consistent with the protocol-compiler code in
@@ -112,11 +117,10 @@ class GeneratedProtocolMessageType(type):
Newly-allocated class.
"""
descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
- _NewMessage(descriptor, dictionary)
+ bases = _NewMessage(bases, descriptor, dictionary)
superclass = super(GeneratedProtocolMessageType, cls)
new_class = superclass.__new__(cls, name, bases, dictionary)
- setattr(descriptor, '_concrete_class', new_class)
return new_class
def __init__(cls, name, bases, dictionary):
@@ -140,3 +144,56 @@ class GeneratedProtocolMessageType(type):
_InitMessage(descriptor, cls)
superclass = super(GeneratedProtocolMessageType, cls)
superclass.__init__(name, bases, dictionary)
+ setattr(descriptor, '_concrete_class', cls)
+
+
+def ParseMessage(descriptor, byte_str):
+ """Generate a new Message instance from this Descriptor and a byte string.
+
+ Args:
+ descriptor: Protobuf Descriptor object
+ byte_str: Serialized protocol buffer byte string
+
+ Returns:
+ Newly created protobuf Message object.
+ """
+ result_class = MakeClass(descriptor)
+ new_msg = result_class()
+ new_msg.ParseFromString(byte_str)
+ return new_msg
+
+
+def MakeClass(descriptor):
+ """Construct a class object for a protobuf described by descriptor.
+
+ Composite descriptors are handled by defining the new class as a member of the
+ parent class, recursing as deep as necessary.
+ This is the dynamic equivalent to:
+
+ class Parent(message.Message):
+ __metaclass__ = GeneratedProtocolMessageType
+ DESCRIPTOR = descriptor
+ class Child(message.Message):
+ __metaclass__ = GeneratedProtocolMessageType
+ DESCRIPTOR = descriptor.nested_types[0]
+
+ Sample usage:
+ file_descriptor = descriptor_pb2.FileDescriptorProto()
+ file_descriptor.ParseFromString(proto2_string)
+ msg_descriptor = descriptor.MakeDescriptor(file_descriptor.message_type[0])
+ msg_class = reflection.MakeClass(msg_descriptor)
+ msg = msg_class()
+
+ Args:
+ descriptor: A descriptor.Descriptor object describing the protobuf.
+ Returns:
+ The Message class object described by the descriptor.
+ """
+ attributes = {}
+ for name, nested_type in descriptor.nested_types_by_name.items():
+ attributes[name] = MakeClass(nested_type)
+
+ attributes[GeneratedProtocolMessageType._DESCRIPTOR_KEY] = descriptor
+
+ return GeneratedProtocolMessageType(str(descriptor.name), (message.Message,),
+ attributes)
diff --git a/python/google/protobuf/service.py b/python/google/protobuf/service.py
index 180b70e8..9e00de70 100755
--- a/python/google/protobuf/service.py
+++ b/python/google/protobuf/service.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
diff --git a/python/google/protobuf/service_reflection.py b/python/google/protobuf/service_reflection.py
index 851e83e7..1c3636af 100755
--- a/python/google/protobuf/service_reflection.py
+++ b/python/google/protobuf/service_reflection.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
diff --git a/python/google/protobuf/symbol_database.py b/python/google/protobuf/symbol_database.py
new file mode 100644
index 00000000..4c70b393
--- /dev/null
+++ b/python/google/protobuf/symbol_database.py
@@ -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.
+
+"""A database of Python protocol buffer generated symbols.
+
+SymbolDatabase makes it easy to create new instances of a registered type, given
+only the type's protocol buffer symbol name. Once all symbols are registered,
+they can be accessed using either the MessageFactory interface which
+SymbolDatabase exposes, or the DescriptorPool interface of the underlying
+pool.
+
+Example usage:
+
+ db = symbol_database.SymbolDatabase()
+
+ # Register symbols of interest, from one or multiple files.
+ db.RegisterFileDescriptor(my_proto_pb2.DESCRIPTOR)
+ db.RegisterMessage(my_proto_pb2.MyMessage)
+ db.RegisterEnumDescriptor(my_proto_pb2.MyEnum.DESCRIPTOR)
+
+ # The database can be used as a MessageFactory, to generate types based on
+ # their name:
+ types = db.GetMessages(['my_proto.proto'])
+ my_message_instance = types['MyMessage']()
+
+ # The database's underlying descriptor pool can be queried, so it's not
+ # necessary to know a type's filename to be able to generate it:
+ filename = db.pool.FindFileContainingSymbol('MyMessage')
+ my_message_instance = db.GetMessages([filename])['MyMessage']()
+
+ # This functionality is also provided directly via a convenience method:
+ my_message_instance = db.GetSymbol('MyMessage')()
+"""
+
+
+from google.protobuf import descriptor_pool
+
+
+class SymbolDatabase(object):
+ """A database of Python generated symbols.
+
+ SymbolDatabase also models message_factory.MessageFactory.
+
+ The symbol database can be used to keep a global registry of all protocol
+ buffer types used within a program.
+ """
+
+ def __init__(self):
+ """Constructor."""
+
+ self._symbols = {}
+ self._symbols_by_file = {}
+ self.pool = descriptor_pool.DescriptorPool()
+
+ def RegisterMessage(self, message):
+ """Registers the given message type in the local database.
+
+ Args:
+ message: a message.Message, to be registered.
+
+ Returns:
+ The provided message.
+ """
+
+ desc = message.DESCRIPTOR
+ self._symbols[desc.full_name] = message
+ if desc.file.name not in self._symbols_by_file:
+ self._symbols_by_file[desc.file.name] = {}
+ self._symbols_by_file[desc.file.name][desc.full_name] = message
+ self.pool.AddDescriptor(desc)
+ return message
+
+ def RegisterEnumDescriptor(self, enum_descriptor):
+ """Registers the given enum descriptor in the local database.
+
+ Args:
+ enum_descriptor: a descriptor.EnumDescriptor.
+
+ Returns:
+ The provided descriptor.
+ """
+ self.pool.AddEnumDescriptor(enum_descriptor)
+ return enum_descriptor
+
+ def RegisterFileDescriptor(self, file_descriptor):
+ """Registers the given file descriptor in the local database.
+
+ Args:
+ file_descriptor: a descriptor.FileDescriptor.
+
+ Returns:
+ The provided descriptor.
+ """
+ self.pool.AddFileDescriptor(file_descriptor)
+
+ def GetSymbol(self, symbol):
+ """Tries to find a symbol in the local database.
+
+ Currently, this method only returns message.Message instances, however, if
+ may be extended in future to support other symbol types.
+
+ Args:
+ symbol: A str, a protocol buffer symbol.
+
+ Returns:
+ A Python class corresponding to the symbol.
+
+ Raises:
+ KeyError: if the symbol could not be found.
+ """
+
+ return self._symbols[symbol]
+
+ def GetPrototype(self, descriptor):
+ """Builds a proto2 message class based on the passed in descriptor.
+
+ Passing a descriptor with a fully qualified name matching a previous
+ invocation will cause the same class to be returned.
+
+ Args:
+ descriptor: The descriptor to build from.
+
+ Returns:
+ A class describing the passed in descriptor.
+ """
+
+ return self.GetSymbol(descriptor.full_name)
+
+ def GetMessages(self, files):
+ """Gets all the messages from a specified file.
+
+ This will find and resolve dependencies, failing if they are not registered
+ in the symbol database.
+
+
+ Args:
+ files: The file names to extract messages from.
+
+ Returns:
+ A dictionary mapping proto names to the message classes. This will include
+ any dependent messages as well as any messages defined in the same file as
+ a specified message.
+
+ Raises:
+ KeyError: if a file could not be found.
+ """
+
+ result = {}
+ for f in files:
+ result.update(self._symbols_by_file[f])
+ return result
+
+_DEFAULT = SymbolDatabase()
+
+
+def Default():
+ """Returns the default SymbolDatabase."""
+ return _DEFAULT
diff --git a/python/google/protobuf/text_encoding.py b/python/google/protobuf/text_encoding.py
new file mode 100644
index 00000000..2d86a67c
--- /dev/null
+++ b/python/google/protobuf/text_encoding.py
@@ -0,0 +1,110 @@
+# 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.
+
+#PY25 compatible for GAE.
+#
+"""Encoding related utilities."""
+
+import re
+import sys ##PY25
+
+# Lookup table for utf8
+_cescape_utf8_to_str = [chr(i) for i in xrange(0, 256)]
+_cescape_utf8_to_str[9] = r'\t' # optional escape
+_cescape_utf8_to_str[10] = r'\n' # optional escape
+_cescape_utf8_to_str[13] = r'\r' # optional escape
+_cescape_utf8_to_str[39] = r"\'" # optional escape
+
+_cescape_utf8_to_str[34] = r'\"' # necessary escape
+_cescape_utf8_to_str[92] = r'\\' # necessary escape
+
+# Lookup table for non-utf8, with necessary escapes at (o >= 127 or o < 32)
+_cescape_byte_to_str = ([r'\%03o' % i for i in xrange(0, 32)] +
+ [chr(i) for i in xrange(32, 127)] +
+ [r'\%03o' % i for i in xrange(127, 256)])
+_cescape_byte_to_str[9] = r'\t' # optional escape
+_cescape_byte_to_str[10] = r'\n' # optional escape
+_cescape_byte_to_str[13] = r'\r' # optional escape
+_cescape_byte_to_str[39] = r"\'" # optional escape
+
+_cescape_byte_to_str[34] = r'\"' # necessary escape
+_cescape_byte_to_str[92] = r'\\' # necessary escape
+
+
+def CEscape(text, as_utf8):
+ """Escape a bytes string for use in an ascii protocol buffer.
+
+ text.encode('string_escape') does not seem to satisfy our needs as it
+ encodes unprintable characters using two-digit hex escapes whereas our
+ C++ unescaping function allows hex escapes to be any length. So,
+ "\0011".encode('string_escape') ends up being "\\x011", which will be
+ decoded in C++ as a single-character string with char code 0x11.
+
+ Args:
+ text: A byte string to be escaped
+ as_utf8: Specifies if result should be returned in UTF-8 encoding
+ Returns:
+ Escaped string
+ """
+ # PY3 hack: make Ord work for str and bytes:
+ # //platforms/networking/data uses unicode here, hence basestring.
+ Ord = ord if isinstance(text, basestring) else lambda x: x
+ if as_utf8:
+ return ''.join(_cescape_utf8_to_str[Ord(c)] for c in text)
+ return ''.join(_cescape_byte_to_str[Ord(c)] for c in text)
+
+
+_CUNESCAPE_HEX = re.compile(r'(\\+)x([0-9a-fA-F])(?![0-9a-fA-F])')
+_cescape_highbit_to_str = ([chr(i) for i in range(0, 127)] +
+ [r'\%03o' % i for i in range(127, 256)])
+
+
+def CUnescape(text):
+ """Unescape a text string with C-style escape sequences to UTF-8 bytes."""
+
+ def ReplaceHex(m):
+ # Only replace the match if the number of leading back slashes is odd. i.e.
+ # the slash itself is not escaped.
+ if len(m.group(1)) & 1:
+ return m.group(1) + 'x0' + m.group(2)
+ return m.group(0)
+
+ # This is required because the 'string_escape' encoding doesn't
+ # allow single-digit hex escapes (like '\xf').
+ result = _CUNESCAPE_HEX.sub(ReplaceHex, text)
+
+ if sys.version_info[0] < 3: ##PY25
+##!PY25 if str is bytes: # PY2
+ return result.decode('string_escape')
+ result = ''.join(_cescape_highbit_to_str[ord(c)] for c in result)
+ return (result.encode('ascii') # Make it bytes to allow decode.
+ .decode('unicode_escape')
+ # Make it bytes again to return the proper type.
+ .encode('raw_unicode_escape'))
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index c3a1cf60..a47ce3e3 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -1,6 +1,6 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
@@ -28,6 +28,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#PY25 compatible for GAE.
+#
+# Copyright 2007 Google Inc. All Rights Reserved.
+
"""Contains routines for printing protocol messages in text format."""
__author__ = 'kenton@google.com (Kenton Varda)'
@@ -35,27 +39,61 @@ __author__ = 'kenton@google.com (Kenton Varda)'
import cStringIO
import re
-from collections import deque
from google.protobuf.internal import type_checkers
from google.protobuf import descriptor
+from google.protobuf import text_encoding
+
+__all__ = ['MessageToString', 'PrintMessage', 'PrintField',
+ 'PrintFieldValue', 'Merge']
-__all__ = [ 'MessageToString', 'PrintMessage', 'PrintField',
- 'PrintFieldValue', 'Merge' ]
+_INTEGER_CHECKERS = (type_checkers.Uint32ValueChecker(),
+ type_checkers.Int32ValueChecker(),
+ type_checkers.Uint64ValueChecker(),
+ type_checkers.Int64ValueChecker())
+_FLOAT_INFINITY = re.compile('-?inf(?:inity)?f?', re.IGNORECASE)
+_FLOAT_NAN = re.compile('nanf?', re.IGNORECASE)
+_FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
+ descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
-# Infinity and NaN are not explicitly supported by Python pre-2.6, and
-# float('inf') does not work on Windows (pre-2.6).
-_INFINITY = 1e10000 # overflows, thus will actually be infinity.
-_NAN = _INFINITY * 0
+class Error(Exception):
+ """Top-level module error for text_format."""
-class ParseError(Exception):
+
+class ParseError(Error):
"""Thrown in case of ASCII parsing error."""
-def MessageToString(message, as_utf8=False, as_one_line=False):
+def MessageToString(message, as_utf8=False, as_one_line=False,
+ pointy_brackets=False, use_index_order=False,
+ float_format=None):
+ """Convert protobuf message to text format.
+
+ Floating point values can be formatted compactly with 15 digits of
+ precision (which is the most that IEEE 754 "double" can guarantee)
+ using float_format='.15g'.
+
+ Args:
+ message: The protocol buffers message.
+ as_utf8: Produce text output in UTF8 format.
+ as_one_line: Don't introduce newlines between fields.
+ pointy_brackets: If True, use angle brackets instead of curly braces for
+ nesting.
+ use_index_order: If True, print fields of a proto message using the order
+ defined in source code instead of the field number. By default, use the
+ field number order.
+ float_format: If set, use this to specify floating point number formatting
+ (per the "Format Specification Mini-Language"); otherwise, str() is used.
+
+ Returns:
+ A string of the text formatted protocol buffer message.
+ """
out = cStringIO.StringIO()
- PrintMessage(message, out, as_utf8=as_utf8, as_one_line=as_one_line)
+ PrintMessage(message, out, as_utf8=as_utf8, as_one_line=as_one_line,
+ pointy_brackets=pointy_brackets,
+ use_index_order=use_index_order,
+ float_format=float_format)
result = out.getvalue()
out.close()
if as_one_line:
@@ -63,20 +101,32 @@ def MessageToString(message, as_utf8=False, as_one_line=False):
return result
-def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False):
- for field, value in message.ListFields():
+def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False,
+ pointy_brackets=False, use_index_order=False,
+ float_format=None):
+ fields = message.ListFields()
+ if use_index_order:
+ fields.sort(key=lambda x: x[0].index)
+ for field, value in fields:
if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
for element in value:
- PrintField(field, element, out, indent, as_utf8, as_one_line)
+ 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)
+ 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):
+def PrintField(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 name/value pair. For repeated fields, the value
should be a single element."""
- out.write(' ' * indent);
+ out.write(' ' * indent)
if field.is_extension:
out.write('[')
if (field.containing_type.GetOptions().message_set_wire_format and
@@ -98,71 +148,182 @@ def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False):
# don't include it.
out.write(': ')
- PrintFieldValue(field, value, out, indent, as_utf8, as_one_line)
+ 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(' ')
else:
out.write('\n')
-def PrintFieldValue(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."""
+ if pointy_brackets:
+ openb = '<'
+ closeb = '>'
+ else:
+ openb = '{'
+ closeb = '}'
+
if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
if as_one_line:
- out.write(' { ')
- PrintMessage(value, out, indent, as_utf8, as_one_line)
- out.write('}')
+ 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(' {\n')
- PrintMessage(value, out, indent + 2, as_utf8, as_one_line)
- out.write(' ' * indent + '}')
+ 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:
- out.write(field.enum_type.values_by_number[value].name)
+ enum_value = field.enum_type.values_by_number.get(value, None)
+ if enum_value is not None:
+ out.write(enum_value.name)
+ else:
+ out.write(str(value))
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
out.write('\"')
- if type(value) is unicode:
- out.write(_CEscape(value.encode('utf-8'), as_utf8))
+ if isinstance(value, unicode):
+ out_value = value.encode('utf-8')
else:
- out.write(_CEscape(value, as_utf8))
+ out_value = value
+ if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+ # We need to escape non-UTF8 chars in TYPE_BYTES field.
+ out_as_utf8 = False
+ else:
+ out_as_utf8 = as_utf8
+ out.write(text_encoding.CEscape(out_value, out_as_utf8))
out.write('\"')
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
if value:
- out.write("true")
+ out.write('true')
else:
- out.write("false")
+ out.write('false')
+ elif field.cpp_type in _FLOAT_TYPES and float_format is not None:
+ out.write('{1:{0}}'.format(float_format, value))
else:
out.write(str(value))
+def Parse(text, message):
+ """Parses an ASCII representation of a protocol message into a message.
+
+ Args:
+ text: Message ASCII representation.
+ message: A protocol buffer message to merge into.
+
+ Returns:
+ The same message passed as argument.
+
+ Raises:
+ ParseError: On ASCII parsing problems.
+ """
+ if not isinstance(text, str): text = text.decode('utf-8')
+ return ParseLines(text.split('\n'), message)
+
+
def Merge(text, message):
- """Merges an ASCII representation of a protocol message into a message.
+ """Parses an ASCII representation of a protocol message into a message.
+
+ Like Parse(), but allows repeated values for a non-repeated field, and uses
+ the last one.
Args:
text: Message ASCII representation.
message: A protocol buffer message to merge into.
+ Returns:
+ The same message passed as argument.
+
Raises:
ParseError: On ASCII parsing problems.
"""
- tokenizer = _Tokenizer(text)
+ return MergeLines(text.split('\n'), message)
+
+
+def ParseLines(lines, message):
+ """Parses an ASCII representation of a protocol message into a message.
+
+ Args:
+ lines: An iterable of lines of a message's ASCII representation.
+ message: A protocol buffer message to merge into.
+
+ Returns:
+ The same message passed as argument.
+
+ Raises:
+ ParseError: On ASCII parsing problems.
+ """
+ _ParseOrMerge(lines, message, False)
+ return message
+
+
+def MergeLines(lines, message):
+ """Parses an ASCII representation of a protocol message into a message.
+
+ Args:
+ lines: An iterable of lines of a message's ASCII representation.
+ message: A protocol buffer message to merge into.
+
+ Returns:
+ The same message passed as argument.
+
+ Raises:
+ ParseError: On ASCII parsing problems.
+ """
+ _ParseOrMerge(lines, message, True)
+ return message
+
+
+def _ParseOrMerge(lines, message, allow_multiple_scalars):
+ """Converts an ASCII representation of a protocol message into a message.
+
+ Args:
+ lines: Lines of a message's ASCII representation.
+ message: A protocol buffer message to merge into.
+ allow_multiple_scalars: Determines if repeated values for a non-repeated
+ field are permitted, e.g., the string "foo: 1 foo: 2" for a
+ required/optional field named "foo".
+
+ Raises:
+ ParseError: On ASCII parsing problems.
+ """
+ tokenizer = _Tokenizer(lines)
while not tokenizer.AtEnd():
- _MergeField(tokenizer, message)
+ _MergeField(tokenizer, message, allow_multiple_scalars)
-def _MergeField(tokenizer, message):
+def _MergeField(tokenizer, message, allow_multiple_scalars):
"""Merges a single protocol message field into a message.
Args:
tokenizer: A tokenizer to parse the field name and values.
message: A protocol message to record the data.
+ allow_multiple_scalars: Determines if repeated values for a non-repeated
+ field are permitted, e.g., the string "foo: 1 foo: 2" for a
+ required/optional field named "foo".
Raises:
ParseError: In case of ASCII parsing problems.
"""
message_descriptor = message.DESCRIPTOR
+ if (hasattr(message_descriptor, 'syntax') and
+ message_descriptor.syntax == 'proto3'):
+ # Proto3 doesn't represent presence so we can't test if multiple
+ # scalars have occurred. We have to allow them.
+ allow_multiple_scalars = True
if tokenizer.TryConsume('['):
name = [tokenizer.ConsumeIdentifier()]
while tokenizer.TryConsume('.'):
@@ -173,7 +334,9 @@ def _MergeField(tokenizer, message):
raise tokenizer.ParseErrorPreviousToken(
'Message type "%s" does not have extensions.' %
message_descriptor.full_name)
+ # pylint: disable=protected-access
field = message.Extensions._FindExtensionByName(name)
+ # pylint: enable=protected-access
if not field:
raise tokenizer.ParseErrorPreviousToken(
'Extension "%s" not registered.' % name)
@@ -227,18 +390,26 @@ def _MergeField(tokenizer, message):
while not tokenizer.TryConsume(end_token):
if tokenizer.AtEnd():
raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))
- _MergeField(tokenizer, sub_message)
+ _MergeField(tokenizer, sub_message, allow_multiple_scalars)
else:
- _MergeScalarField(tokenizer, message, field)
+ _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
+
+ # For historical reasons, fields may optionally be separated by commas or
+ # semicolons.
+ if not tokenizer.TryConsume(','):
+ tokenizer.TryConsume(';')
-def _MergeScalarField(tokenizer, message, field):
+def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars):
"""Merges a single protocol message scalar field into a message.
Args:
tokenizer: A tokenizer to parse the field value.
message: A protocol message to record the data.
field: The descriptor of the field to be merged.
+ allow_multiple_scalars: Determines if repeated values for a non-repeated
+ field are permitted, e.g., the string "foo: 1 foo: 2" for a
+ required/optional field named "foo".
Raises:
ParseError: In case of ASCII parsing problems.
@@ -271,24 +442,7 @@ def _MergeScalarField(tokenizer, message, field):
elif field.type == descriptor.FieldDescriptor.TYPE_BYTES:
value = tokenizer.ConsumeByteString()
elif field.type == descriptor.FieldDescriptor.TYPE_ENUM:
- # Enum can be specified by a number (the enum value), or by
- # a string literal (the enum name).
- enum_descriptor = field.enum_type
- if tokenizer.LookingAtInteger():
- number = tokenizer.ConsumeInt32()
- enum_value = enum_descriptor.values_by_number.get(number, None)
- if enum_value is None:
- raise tokenizer.ParseErrorPreviousToken(
- 'Enum type "%s" has no value with number %d.' % (
- enum_descriptor.full_name, number))
- else:
- identifier = tokenizer.ConsumeIdentifier()
- enum_value = enum_descriptor.values_by_name.get(identifier, None)
- if enum_value is None:
- raise tokenizer.ParseErrorPreviousToken(
- 'Enum type "%s" has no value named %s.' % (
- enum_descriptor.full_name, identifier))
- value = enum_value.number
+ value = tokenizer.ConsumeEnum(field)
else:
raise RuntimeError('Unknown field type %d' % field.type)
@@ -299,9 +453,19 @@ def _MergeScalarField(tokenizer, message, field):
getattr(message, field.name).append(value)
else:
if field.is_extension:
- message.Extensions[field] = value
+ if not allow_multiple_scalars and message.HasExtension(field):
+ raise tokenizer.ParseErrorPreviousToken(
+ 'Message type "%s" should not have multiple "%s" extensions.' %
+ (message.DESCRIPTOR.full_name, field.full_name))
+ else:
+ message.Extensions[field] = value
else:
- setattr(message, field.name, value)
+ if not allow_multiple_scalars and message.HasField(field.name):
+ raise tokenizer.ParseErrorPreviousToken(
+ 'Message type "%s" should not have multiple "%s" fields.' %
+ (message.DESCRIPTOR.full_name, field.name))
+ else:
+ setattr(message, field.name, value)
class _Tokenizer(object):
@@ -319,26 +483,19 @@ class _Tokenizer(object):
'[0-9+-][0-9a-zA-Z_.+-]*|' # a number
'\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|' # a double-quoted string
'\'([^\'\n\\\\]|\\\\.)*(\'|\\\\?$)') # a single-quoted string
- _IDENTIFIER = re.compile('\w+')
- _INTEGER_CHECKERS = [type_checkers.Uint32ValueChecker(),
- type_checkers.Int32ValueChecker(),
- type_checkers.Uint64ValueChecker(),
- type_checkers.Int64ValueChecker()]
- _FLOAT_INFINITY = re.compile('-?inf(inity)?f?', re.IGNORECASE)
- _FLOAT_NAN = re.compile("nanf?", re.IGNORECASE)
-
- def __init__(self, text_message):
- self._text_message = text_message
+ _IDENTIFIER = re.compile(r'\w+')
+ def __init__(self, lines):
self._position = 0
self._line = -1
self._column = 0
self._token_start = None
self.token = ''
- self._lines = deque(text_message.split('\n'))
+ self._lines = iter(lines)
self._current_line = ''
self._previous_line = 0
self._previous_column = 0
+ self._more_lines = True
self._SkipWhitespace()
self.NextToken()
@@ -348,16 +505,19 @@ class _Tokenizer(object):
Returns:
True iff the end was reached.
"""
- return self.token == ''
+ return not self.token
def _PopLine(self):
while len(self._current_line) <= self._column:
- if not self._lines:
+ try:
+ self._current_line = self._lines.next()
+ except StopIteration:
self._current_line = ''
+ self._more_lines = False
return
- self._line += 1
- self._column = 0
- self._current_line = self._lines.popleft()
+ else:
+ self._line += 1
+ self._column = 0
def _SkipWhitespace(self):
while True:
@@ -394,17 +554,6 @@ class _Tokenizer(object):
if not self.TryConsume(token):
raise self._ParseError('Expected "%s".' % token)
- def LookingAtInteger(self):
- """Checks if the current token is an integer.
-
- Returns:
- True iff the current token is an integer.
- """
- if not self.token:
- return False
- c = self.token[0]
- return (c >= '0' and c <= '9') or c == '-' or c == '+'
-
def ConsumeIdentifier(self):
"""Consumes protocol message field identifier.
@@ -430,9 +579,9 @@ class _Tokenizer(object):
ParseError: If a signed 32bit integer couldn't be consumed.
"""
try:
- result = self._ParseInteger(self.token, is_signed=True, is_long=False)
+ result = ParseInteger(self.token, is_signed=True, is_long=False)
except ValueError, e:
- raise self._IntegerParseError(e)
+ raise self._ParseError(str(e))
self.NextToken()
return result
@@ -446,9 +595,9 @@ class _Tokenizer(object):
ParseError: If an unsigned 32bit integer couldn't be consumed.
"""
try:
- result = self._ParseInteger(self.token, is_signed=False, is_long=False)
+ result = ParseInteger(self.token, is_signed=False, is_long=False)
except ValueError, e:
- raise self._IntegerParseError(e)
+ raise self._ParseError(str(e))
self.NextToken()
return result
@@ -462,9 +611,9 @@ class _Tokenizer(object):
ParseError: If a signed 64bit integer couldn't be consumed.
"""
try:
- result = self._ParseInteger(self.token, is_signed=True, is_long=True)
+ result = ParseInteger(self.token, is_signed=True, is_long=True)
except ValueError, e:
- raise self._IntegerParseError(e)
+ raise self._ParseError(str(e))
self.NextToken()
return result
@@ -478,9 +627,9 @@ class _Tokenizer(object):
ParseError: If an unsigned 64bit integer couldn't be consumed.
"""
try:
- result = self._ParseInteger(self.token, is_signed=False, is_long=True)
+ result = ParseInteger(self.token, is_signed=False, is_long=True)
except ValueError, e:
- raise self._IntegerParseError(e)
+ raise self._ParseError(str(e))
self.NextToken()
return result
@@ -493,21 +642,10 @@ class _Tokenizer(object):
Raises:
ParseError: If a floating point number couldn't be consumed.
"""
- text = self.token
- if self._FLOAT_INFINITY.match(text):
- self.NextToken()
- if text.startswith('-'):
- return -_INFINITY
- return _INFINITY
-
- if self._FLOAT_NAN.match(text):
- self.NextToken()
- return _NAN
-
try:
- result = float(text)
+ result = ParseFloat(self.token)
except ValueError, e:
- raise self._FloatParseError(e)
+ raise self._ParseError(str(e))
self.NextToken()
return result
@@ -520,14 +658,12 @@ class _Tokenizer(object):
Raises:
ParseError: If a boolean value couldn't be consumed.
"""
- if self.token in ('true', 't', '1'):
- self.NextToken()
- return True
- elif self.token in ('false', 'f', '0'):
- self.NextToken()
- return False
- else:
- raise self._ParseError('Expected "true" or "false".')
+ try:
+ result = ParseBool(self.token)
+ except ValueError, e:
+ raise self._ParseError(str(e))
+ self.NextToken()
+ return result
def ConsumeString(self):
"""Consumes a string value.
@@ -538,9 +674,9 @@ class _Tokenizer(object):
Raises:
ParseError: If a string value couldn't be consumed.
"""
- bytes = self.ConsumeByteString()
+ the_bytes = self.ConsumeByteString()
try:
- return unicode(bytes, 'utf-8')
+ return unicode(the_bytes, 'utf-8')
except UnicodeDecodeError, e:
raise self._StringParseError(e)
@@ -553,10 +689,11 @@ class _Tokenizer(object):
Raises:
ParseError: If a byte array value couldn't be consumed.
"""
- list = [self._ConsumeSingleByteString()]
- while len(self.token) > 0 and self.token[0] in ('\'', '"'):
- list.append(self._ConsumeSingleByteString())
- return "".join(list)
+ the_list = [self._ConsumeSingleByteString()]
+ while self.token and self.token[0] in ('\'', '"'):
+ the_list.append(self._ConsumeSingleByteString())
+ return ''.encode('latin1').join(the_list) ##PY25
+##!PY25 return b''.join(the_list)
def _ConsumeSingleByteString(self):
"""Consume one token of a string literal.
@@ -567,48 +704,24 @@ class _Tokenizer(object):
"""
text = self.token
if len(text) < 1 or text[0] not in ('\'', '"'):
- raise self._ParseError('Exptected string.')
+ raise self._ParseError('Expected string but found: "%r"' % text)
if len(text) < 2 or text[-1] != text[0]:
raise self._ParseError('String missing ending quote.')
try:
- result = _CUnescape(text[1:-1])
+ result = text_encoding.CUnescape(text[1:-1])
except ValueError, e:
raise self._ParseError(str(e))
self.NextToken()
return result
- def _ParseInteger(self, text, is_signed=False, is_long=False):
- """Parses an integer.
-
- Args:
- text: The text to parse.
- is_signed: True if a signed integer must be parsed.
- is_long: True if a long integer must be parsed.
-
- Returns:
- The integer value.
-
- Raises:
- ValueError: Thrown Iff the text is not a valid integer.
- """
- pos = 0
- if text.startswith('-'):
- pos += 1
-
- base = 10
- if text.startswith('0x', pos) or text.startswith('0X', pos):
- base = 16
- elif text.startswith('0', pos):
- base = 8
-
- # Do the actual parsing. Exception handling is propagated to caller.
- result = int(text, base)
-
- # Check if the integer is sane. Exceptions handled by callers.
- checker = self._INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
- checker.CheckValue(result)
+ def ConsumeEnum(self, field):
+ try:
+ result = ParseEnum(field, self.token)
+ except ValueError, e:
+ raise self._ParseError(str(e))
+ self.NextToken()
return result
def ParseErrorPreviousToken(self, message):
@@ -626,13 +739,7 @@ class _Tokenizer(object):
def _ParseError(self, message):
"""Creates and *returns* a ParseError for the current token."""
return ParseError('%d:%d : %s' % (
- self._line + 1, self._column - len(self.token) + 1, message))
-
- def _IntegerParseError(self, e):
- return self._ParseError('Couldn\'t parse integer: ' + str(e))
-
- def _FloatParseError(self, e):
- return self._ParseError('Couldn\'t parse number: ' + str(e))
+ self._line + 1, self._column + 1, message))
def _StringParseError(self, e):
return self._ParseError('Couldn\'t parse string: ' + str(e))
@@ -645,7 +752,7 @@ class _Tokenizer(object):
self._column += len(self.token)
self._SkipWhitespace()
- if not self._lines and len(self._current_line) <= self._column:
+ if not self._more_lines:
self.token = ''
return
@@ -657,35 +764,121 @@ class _Tokenizer(object):
self.token = self._current_line[self._column]
-# text.encode('string_escape') does not seem to satisfy our needs as it
-# encodes unprintable characters using two-digit hex escapes whereas our
-# C++ unescaping function allows hex escapes to be any length. So,
-# "\0011".encode('string_escape') ends up being "\\x011", which will be
-# decoded in C++ as a single-character string with char code 0x11.
-def _CEscape(text, as_utf8):
- def escape(c):
- o = ord(c)
- if o == 10: return r"\n" # optional escape
- if o == 13: return r"\r" # optional escape
- if o == 9: return r"\t" # optional escape
- if o == 39: return r"\'" # optional escape
+def ParseInteger(text, is_signed=False, is_long=False):
+ """Parses an integer.
- if o == 34: return r'\"' # necessary escape
- if o == 92: return r"\\" # necessary escape
+ Args:
+ text: The text to parse.
+ is_signed: True if a signed integer must be parsed.
+ is_long: True if a long integer must be parsed.
- # necessary escapes
- if not as_utf8 and (o >= 127 or o < 32): return "\\%03o" % o
- return c
- return "".join([escape(c) for c in text])
+ Returns:
+ The integer value.
+ Raises:
+ ValueError: Thrown Iff the text is not a valid integer.
+ """
+ # Do the actual parsing. Exception handling is propagated to caller.
+ try:
+ # We force 32-bit values to int and 64-bit values to long to make
+ # alternate implementations where the distinction is more significant
+ # (e.g. the C++ implementation) simpler.
+ if is_long:
+ result = long(text, 0)
+ else:
+ result = int(text, 0)
+ except ValueError:
+ raise ValueError('Couldn\'t parse integer: %s' % text)
-_CUNESCAPE_HEX = re.compile('\\\\x([0-9a-fA-F]{2}|[0-9a-fA-F])')
+ # Check if the integer is sane. Exceptions handled by callers.
+ checker = _INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
+ checker.CheckValue(result)
+ return result
+
+
+def ParseFloat(text):
+ """Parse a floating point number.
+
+ Args:
+ text: Text to parse.
+ Returns:
+ The number parsed.
-def _CUnescape(text):
- def ReplaceHex(m):
- return chr(int(m.group(0)[2:], 16))
- # This is required because the 'string_escape' encoding doesn't
- # allow single-digit hex escapes (like '\xf').
- result = _CUNESCAPE_HEX.sub(ReplaceHex, text)
- return result.decode('string_escape')
+ Raises:
+ ValueError: If a floating point number couldn't be parsed.
+ """
+ try:
+ # Assume Python compatible syntax.
+ return float(text)
+ except ValueError:
+ # Check alternative spellings.
+ if _FLOAT_INFINITY.match(text):
+ if text[0] == '-':
+ return float('-inf')
+ else:
+ return float('inf')
+ elif _FLOAT_NAN.match(text):
+ return float('nan')
+ else:
+ # assume '1.0f' format
+ try:
+ return float(text.rstrip('f'))
+ except ValueError:
+ raise ValueError('Couldn\'t parse float: %s' % text)
+
+
+def ParseBool(text):
+ """Parse a boolean value.
+
+ Args:
+ text: Text to parse.
+
+ Returns:
+ Boolean values parsed
+
+ Raises:
+ ValueError: If text is not a valid boolean.
+ """
+ if text in ('true', 't', '1'):
+ return True
+ elif text in ('false', 'f', '0'):
+ return False
+ else:
+ raise ValueError('Expected "true" or "false".')
+
+
+def ParseEnum(field, value):
+ """Parse an enum value.
+
+ The value can be specified by a number (the enum value), or by
+ a string literal (the enum name).
+
+ Args:
+ field: Enum field descriptor.
+ value: String value.
+
+ Returns:
+ Enum value number.
+
+ Raises:
+ ValueError: If the enum value could not be parsed.
+ """
+ enum_descriptor = field.enum_type
+ try:
+ number = int(value, 0)
+ except ValueError:
+ # Identifier.
+ enum_value = enum_descriptor.values_by_name.get(value, None)
+ if enum_value is None:
+ raise ValueError(
+ 'Enum type "%s" has no value named %s.' % (
+ enum_descriptor.full_name, value))
+ else:
+ # Numeric value.
+ enum_value = enum_descriptor.values_by_number.get(number, None)
+ if enum_value is None:
+ raise ValueError(
+ 'Enum type "%s" has no value with number %d.' % (
+ enum_descriptor.full_name, number))
+ return enum_value.number
diff --git a/python/mox.py b/python/mox.py
index ce80ba50..257468e5 100755
--- a/python/mox.py
+++ b/python/mox.py
@@ -31,7 +31,7 @@ If an unexpected method (or an expected method with unexpected
parameters) is called, then an exception will be raised.
Once you are done interacting with the mock, you need to verify that
-all the expected interactions occured. (Maybe your code exited
+all the expected interactions occurred. (Maybe your code exited
prematurely without calling some cleanup method!) The verify phase
ensures that every expected method was called; otherwise, an exception
will be raised.
diff --git a/python/setup.py b/python/setup.py
index 5df0df89..c18818e2 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -1,22 +1,39 @@
#! /usr/bin/python
#
# See README for usage instructions.
+import sys
+import os
+import subprocess
# We must use setuptools, not distutils, because we need to use the
# namespace_packages option for the "google" package.
-from ez_setup import use_setuptools
-use_setuptools()
-
-from setuptools import setup, Extension
+try:
+ from setuptools import setup, Extension
+except ImportError:
+ try:
+ from ez_setup import use_setuptools
+ use_setuptools()
+ from setuptools import setup, Extension
+ except ImportError:
+ sys.stderr.write(
+ "Could not import setuptools; make sure you have setuptools or "
+ "ez_setup installed.\n")
+ raise
+from distutils.command.clean import clean as _clean
+if sys.version_info[0] >= 3:
+ # Python 3
+ from distutils.command.build_py import build_py_2to3 as _build_py
+else:
+ # Python 2
+ from distutils.command.build_py import build_py as _build_py
from distutils.spawn import find_executable
-import sys
-import os
-import subprocess
maintainer_email = "protobuf@googlegroups.com"
# Find the Protocol Compiler.
-if os.path.exists("../src/protoc"):
+if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
+ protoc = os.environ['PROTOC']
+elif os.path.exists("../src/protoc"):
protoc = "../src/protoc"
elif os.path.exists("../src/protoc.exe"):
protoc = "../src/protoc.exe"
@@ -27,6 +44,18 @@ elif os.path.exists("../vsprojects/Release/protoc.exe"):
else:
protoc = find_executable("protoc")
+def GetVersion():
+ """Gets the version from google/protobuf/__init__.py
+
+ Do not import google.protobuf.__init__ directly, because an installed protobuf
+ library may be loaded instead.
+
+ """
+ with open(os.path.join('google', 'protobuf', '__init__.py')) as version_file:
+ exec(version_file.read())
+ return __version__
+
+
def generate_proto(source):
"""Invokes the Protocol Compiler to generate a _pb2.py from the given
.proto file. Does nothing if the output already exists and is newer than
@@ -34,14 +63,14 @@ def generate_proto(source):
output = source.replace(".proto", "_pb2.py").replace("../src/", "")
- if not os.path.exists(source):
- print "Can't find required file: " + source
- sys.exit(-1)
-
if (not os.path.exists(output) or
(os.path.exists(source) and
os.path.getmtime(source) > os.path.getmtime(output))):
- print "Generating %s..." % output
+ print ("Generating %s..." % output)
+
+ if not os.path.exists(source):
+ sys.stderr.write("Can't find required file: %s\n" % source)
+ sys.exit(-1)
if protoc == None:
sys.stderr.write(
@@ -53,75 +82,90 @@ def generate_proto(source):
if subprocess.call(protoc_command) != 0:
sys.exit(-1)
-def MakeTestSuite():
- # This is apparently needed on some systems to make sure that the tests
- # work even if a previous version is already installed.
- if 'google' in sys.modules:
- del sys.modules['google']
-
+def GenerateUnittestProtos():
generate_proto("../src/google/protobuf/unittest.proto")
generate_proto("../src/google/protobuf/unittest_custom_options.proto")
generate_proto("../src/google/protobuf/unittest_import.proto")
+ generate_proto("../src/google/protobuf/unittest_import_public.proto")
generate_proto("../src/google/protobuf/unittest_mset.proto")
generate_proto("../src/google/protobuf/unittest_no_generic_services.proto")
+ generate_proto("../src/google/protobuf/unittest_proto3_arena.proto")
+ generate_proto("google/protobuf/internal/descriptor_pool_test1.proto")
+ generate_proto("google/protobuf/internal/descriptor_pool_test2.proto")
+ generate_proto("google/protobuf/internal/test_bad_identifiers.proto")
+ generate_proto("google/protobuf/internal/missing_enum_values.proto")
generate_proto("google/protobuf/internal/more_extensions.proto")
+ generate_proto("google/protobuf/internal/more_extensions_dynamic.proto")
generate_proto("google/protobuf/internal/more_messages.proto")
-
- import unittest
- import google.protobuf.internal.generator_test as generator_test
- import google.protobuf.internal.descriptor_test as descriptor_test
- import google.protobuf.internal.reflection_test as reflection_test
- import google.protobuf.internal.service_reflection_test \
- as service_reflection_test
- import google.protobuf.internal.text_format_test as text_format_test
- import google.protobuf.internal.wire_format_test as wire_format_test
-
- loader = unittest.defaultTestLoader
- suite = unittest.TestSuite()
- for test in [ generator_test,
- descriptor_test,
- reflection_test,
- service_reflection_test,
- text_format_test,
- wire_format_test ]:
- suite.addTest(loader.loadTestsFromModule(test))
-
- return suite
-
-if __name__ == '__main__':
- # TODO(kenton): Integrate this into setuptools somehow?
- if len(sys.argv) >= 2 and sys.argv[1] == "clean":
- # Delete generated _pb2.py files and .pyc files in the code tree.
+ 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")
+
+class clean(_clean):
+ def run(self):
+ # Delete generated files in the code tree.
for (dirpath, dirnames, filenames) in os.walk("."):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
if filepath.endswith("_pb2.py") or filepath.endswith(".pyc") or \
- filepath.endswith(".so") or filepath.endswith(".o"):
+ filepath.endswith(".so") or filepath.endswith(".o") or \
+ filepath.endswith('google/protobuf/compiler/__init__.py'):
os.remove(filepath)
- else:
+ # _clean is an old-style class, so super() doesn't work.
+ _clean.run(self)
+
+class build_py(_build_py):
+ def run(self):
# Generate necessary .proto file if it doesn't exist.
- # TODO(kenton): Maybe we should hook this into a distutils command?
generate_proto("../src/google/protobuf/descriptor.proto")
generate_proto("../src/google/protobuf/compiler/plugin.proto")
+ GenerateUnittestProtos()
+
+ # Make sure google.protobuf/** are valid packages.
+ for path in ['', 'internal/', 'compiler/', 'pyext/']:
+ try:
+ open('google/protobuf/%s__init__.py' % path, 'a').close()
+ except EnvironmentError:
+ pass
+ # _build_py is an old-style class, so super() doesn't work.
+ _build_py.run(self)
+ # TODO(mrovner): Subclass to run 2to3 on some files only.
+ # Tracing what https://wiki.python.org/moin/PortingPythonToPy3k's "Approach 2"
+ # section on how to get 2to3 to run on source files during install under
+ # Python 3. This class seems like a good place to put logic that calls
+ # python3's distutils.util.run_2to3 on the subset of the files we have in our
+ # release that are subject to conversion.
+ # See code reference in previous code review.
+if __name__ == '__main__':
ext_module_list = []
-
- # C++ implementation extension
- if os.getenv("PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION", "python") == "cpp":
- print "Using EXPERIMENTAL C++ Implmenetation."
+ cpp_impl = '--cpp_implementation'
+ if cpp_impl in sys.argv:
+ sys.argv.remove(cpp_impl)
+ # C++ implementation extension
ext_module_list.append(Extension(
- "google.protobuf.internal._net_proto2___python",
- [ "google/protobuf/pyext/python_descriptor.cc",
- "google/protobuf/pyext/python_protobuf.cc",
- "google/protobuf/pyext/python-proto2.cc" ],
- include_dirs = [ "." ],
- libraries = [ "protobuf" ]))
+ "google.protobuf.pyext._message",
+ [ "google/protobuf/pyext/descriptor.cc",
+ "google/protobuf/pyext/descriptor_containers.cc",
+ "google/protobuf/pyext/descriptor_pool.cc",
+ "google/protobuf/pyext/message.cc",
+ "google/protobuf/pyext/extension_dict.cc",
+ "google/protobuf/pyext/repeated_scalar_container.cc",
+ "google/protobuf/pyext/repeated_composite_container.cc" ],
+ define_macros=[('GOOGLE_PROTOBUF_HAS_ONEOF', '1')],
+ include_dirs = [ ".", "..", "../src"],
+ libraries = [ "protobuf" ],
+ library_dirs = [ '../src/.libs' ],
+ ))
+ os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp'
setup(name = 'protobuf',
- version = '2.4.1',
+ version = GetVersion(),
packages = [ 'google' ],
namespace_packages = [ 'google' ],
- test_suite = 'setup.MakeTestSuite',
+ google_test_dir = "google/protobuf/internal",
# Must list modules explicitly so that we don't install tests.
py_modules = [
'google.protobuf.internal.api_implementation',
@@ -129,6 +173,7 @@ if __name__ == '__main__':
'google.protobuf.internal.cpp_message',
'google.protobuf.internal.decoder',
'google.protobuf.internal.encoder',
+ 'google.protobuf.internal.enum_type_wrapper',
'google.protobuf.internal.message_listener',
'google.protobuf.internal.python_message',
'google.protobuf.internal.type_checkers',
@@ -137,12 +182,26 @@ if __name__ == '__main__':
'google.protobuf.descriptor_pb2',
'google.protobuf.compiler.plugin_pb2',
'google.protobuf.message',
+ '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',
'google.protobuf.service_reflection',
- 'google.protobuf.text_format' ],
+ 'google.protobuf.symbol_database',
+ 'google.protobuf.text_encoding',
+ 'google.protobuf.text_format'],
+ cmdclass = { 'clean': clean, 'build_py': build_py },
+ install_requires = ['setuptools'],
+ # TODO: Restore dependency once a Python 3 compatible google-apputils
+ # is released.
+ setup_requires = (['google-apputils']
+ if sys.version_info[0] < 3 else
+ []),
ext_modules = ext_module_list,
- url = 'http://code.google.com/p/protobuf/',
+ url = 'https://developers.google.com/protocol-buffers/',
maintainer = maintainer_email,
maintainer_email = 'protobuf@googlegroups.com',
license = 'New BSD License',
diff --git a/ruby/.gitignore b/ruby/.gitignore
new file mode 100644
index 00000000..80c978f2
--- /dev/null
+++ b/ruby/.gitignore
@@ -0,0 +1,6 @@
+*.bundle
+tags
+.idea/
+lib/google/protobuf_java.jar
+protobuf-jruby.iml
+target/
diff --git a/ruby/Gemfile b/ruby/Gemfile
new file mode 100644
index 00000000..fa75df15
--- /dev/null
+++ b/ruby/Gemfile
@@ -0,0 +1,3 @@
+source 'https://rubygems.org'
+
+gemspec
diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock
new file mode 100644
index 00000000..89deb47d
--- /dev/null
+++ b/ruby/Gemfile.lock
@@ -0,0 +1,25 @@
+PATH
+ remote: .
+ specs:
+ google-protobuf (3.0.0.alpha.2)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ power_assert (0.2.2)
+ rake (10.4.2)
+ rake-compiler (0.9.5)
+ rake
+ rubygems-tasks (0.2.4)
+ test-unit (3.0.9)
+ power_assert
+
+PLATFORMS
+ java
+ ruby
+
+DEPENDENCIES
+ google-protobuf!
+ rake-compiler
+ rubygems-tasks
+ test-unit
diff --git a/ruby/README.md b/ruby/README.md
new file mode 100644
index 00000000..d2fa76ab
--- /dev/null
+++ b/ruby/README.md
@@ -0,0 +1,111 @@
+This directory contains the Ruby extension that implements Protocol Buffers
+functionality in Ruby.
+
+The Ruby extension makes use of generated Ruby code that defines message and
+enum types in a Ruby DSL. You may write definitions in this DSL directly, but
+we recommend using protoc's Ruby generation support with .proto files. The
+build process in this directory only installs the extension; you need to
+install protoc as well to have Ruby code generation functionality.
+
+Installation from Gem
+---------------------
+
+When we release a version of Protocol Buffers, we will upload a Gem to
+[RubyGems](https://www.rubygems.org/). To use this pre-packaged gem, simply
+install it as you would any other gem:
+
+ $ gem install [--prerelease] google-protobuf
+
+The `--pre` flag is necessary if we have not yet made a non-alpha/beta release
+of the Ruby extension; it allows `gem` to consider these "pre-release"
+alpha/beta versions.
+
+Once the gem is installed, you may or may not need `protoc`. If you write your
+message type descriptions directly in the Ruby DSL, you do not need it.
+However, if you wish to generate the Ruby DSL from a `.proto` file, you will
+also want to install Protocol Buffers itself, as described in this repository's
+main `README` file. The version of `protoc` included in the latest release
+supports the `--ruby_out` option to generate Ruby code.
+
+A simple example of using the Ruby extension follows. More extensive
+documentation may be found in the RubyDoc comments (`call-seq` tags) in the
+source, and we plan to release separate, more detailed, documentation at a
+later date.
+
+ require 'google/protobuf'
+
+ # generated from my_proto_types.proto with protoc:
+ # $ protoc --ruby_out=. my_proto_types.proto
+ require 'my_proto_types'
+
+ mymessage = MyTestMessage.new(:field1 => 42, :field2 => ["a", "b", "c"])
+ mymessage.field1 = 43
+ mymessage.field2.push("d")
+ mymessage.field3 = SubMessage.new(:foo => 100)
+
+ encoded_data = MyTestMessage.encode(mymessage)
+ decoded = MyTestMessage.decode(encoded_data)
+ assert decoded == mymessage
+
+ puts "JSON:"
+ puts MyTestMessage.encode_json(mymessage)
+
+Installation from Source (Building Gem)
+---------------------------------------
+
+To build this Ruby extension, you will need:
+
+* Rake
+* Bundler
+* Ruby development headers
+* a C compiler
+
+To Build the JRuby extension, you will need:
+
+* Maven
+* The latest version of the protobuf java library
+* Install JRuby via rbenv or RVM
+
+First switch to the desired platform with rbenv or RVM.
+
+Then install the required Ruby gems:
+
+ $ gem install bundler
+ $ bundle
+
+Then build the Gem:
+
+ $ rake gem
+ $ gem install pkg/protobuf-$VERSION.gem
+
+To run the specs:
+
+ $ rake test
+
+This gem includes the upb parsing and serialization library as a single-file
+amalgamation. It is up-to-date with upb git commit
+`535bc2fe2f2b467f59347ffc9449e11e47791257`.
+
+Version Number Scheme
+---------------------
+
+We are using a version number scheme that is a hybrid of Protocol Buffers'
+overall version number and some Ruby-specific rules. Gem does not allow
+re-uploads of a gem with the same version number, so we add a sequence number
+("upload version") to the version. We also format alphabetical tags (alpha,
+pre, ...) slightly differently, and we avoid hyphens. In more detail:
+
+* First, we determine the prefix: a Protocol Buffers version "3.0.0-alpha-2"
+ becomes "3.0.0.alpha.2". When we release 3.0.0, this prefix will be simply
+ "3.0.0".
+* We then append the upload version: "3.0.0.alpha.2.0" or "3.0.0.0". If we need
+ to upload a new version of the gem to fix an issue, the version becomes
+ "3.0.0.alpha.2.1" or "3.0.0.1".
+* If we are working on a prerelease version, we append a prerelease tag:
+ "3.0.0.alpha.3.0.pre". The prerelease tag comes at the end so that when
+ version numbers are sorted, any prerelease builds are ordered between the
+ prior version and current version.
+
+These rules are designed to work with the sorting rules for
+[Gem::Version](http://ruby-doc.org/stdlib-2.0/libdoc/rubygems/rdoc/Gem/Version.html):
+release numbers should sort in actual release order.
diff --git a/ruby/Rakefile b/ruby/Rakefile
new file mode 100644
index 00000000..7c1d8495
--- /dev/null
+++ b/ruby/Rakefile
@@ -0,0 +1,33 @@
+require "rubygems"
+require "rubygems/package_task"
+require "rake/extensiontask" unless RUBY_PLATFORM == "java"
+require "rake/testtask"
+
+spec = Gem::Specification.load("google-protobuf.gemspec")
+
+if RUBY_PLATFORM == "java"
+ task :clean do
+ system("mvn clean")
+ end
+
+ task :compile do
+ system("mvn package")
+ end
+else
+ Rake::ExtensionTask.new("protobuf_c", spec) do |ext|
+ ext.ext_dir = "ext/google/protobuf_c"
+ ext.lib_dir = "lib/google"
+ end
+end
+
+Gem::PackageTask.new(spec) do |pkg|
+end
+
+Rake::TestTask.new(:test => :build) do |t|
+ t.test_files = FileList["tests/*.rb"]
+end
+
+task :build => [:clean, :compile]
+task :default => [:build]
+
+# vim:sw=2:et
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
new file mode 100644
index 00000000..b39c27f4
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -0,0 +1,1676 @@
+// 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Common utilities.
+// -----------------------------------------------------------------------------
+
+const char* kDescriptorInstanceVar = "descriptor";
+
+static const char* get_str(VALUE str) {
+ Check_Type(str, T_STRING);
+ return RSTRING_PTR(str);
+}
+
+static VALUE rb_str_maybe_null(const char* s) {
+ if (s == NULL) {
+ s = "";
+ }
+ return rb_str_new2(s);
+}
+
+static upb_def* check_notfrozen(const upb_def* def) {
+ if (upb_def_isfrozen(def)) {
+ rb_raise(rb_eRuntimeError,
+ "Attempt to modify a frozen descriptor. Once descriptors are "
+ "added to the descriptor pool, they may not be modified.");
+ }
+ return (upb_def*)def;
+}
+
+static upb_msgdef* check_msg_notfrozen(const upb_msgdef* def) {
+ return upb_downcast_msgdef_mutable(check_notfrozen((const upb_def*)def));
+}
+
+static upb_fielddef* check_field_notfrozen(const upb_fielddef* def) {
+ return upb_downcast_fielddef_mutable(check_notfrozen((const upb_def*)def));
+}
+
+static upb_oneofdef* check_oneof_notfrozen(const upb_oneofdef* def) {
+ return (upb_oneofdef*)check_notfrozen((const upb_def*)def);
+}
+
+static upb_enumdef* check_enum_notfrozen(const upb_enumdef* def) {
+ return (upb_enumdef*)check_notfrozen((const upb_def*)def);
+}
+
+// -----------------------------------------------------------------------------
+// DescriptorPool.
+// -----------------------------------------------------------------------------
+
+#define DEFINE_CLASS(name, string_name) \
+ VALUE c ## name; \
+ const rb_data_type_t _ ## name ## _type = { \
+ string_name, \
+ { name ## _mark, name ## _free, NULL }, \
+ }; \
+ name* ruby_to_ ## name(VALUE val) { \
+ name* ret; \
+ TypedData_Get_Struct(val, name, &_ ## name ## _type, ret); \
+ return ret; \
+ } \
+
+#define DEFINE_SELF(type, var, rb_var) \
+ type* var = ruby_to_ ## type(rb_var);
+
+// Global singleton DescriptorPool. The user is free to create others, but this
+// is used by generated code.
+VALUE generated_pool;
+
+DEFINE_CLASS(DescriptorPool, "Google::Protobuf::DescriptorPool");
+
+void DescriptorPool_mark(void* _self) {
+}
+
+void DescriptorPool_free(void* _self) {
+ DescriptorPool* self = _self;
+ upb_symtab_unref(self->symtab, &self->symtab);
+ xfree(self);
+}
+
+/*
+ * call-seq:
+ * DescriptorPool.new => pool
+ *
+ * Creates a new, empty, descriptor pool.
+ */
+VALUE DescriptorPool_alloc(VALUE klass) {
+ DescriptorPool* self = ALLOC(DescriptorPool);
+ self->symtab = upb_symtab_new(&self->symtab);
+ return TypedData_Wrap_Struct(klass, &_DescriptorPool_type, self);
+}
+
+void DescriptorPool_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "DescriptorPool", rb_cObject);
+ rb_define_alloc_func(klass, DescriptorPool_alloc);
+ rb_define_method(klass, "add", DescriptorPool_add, 1);
+ rb_define_method(klass, "build", DescriptorPool_build, 0);
+ rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
+ rb_define_singleton_method(klass, "generated_pool",
+ DescriptorPool_generated_pool, 0);
+ cDescriptorPool = klass;
+ rb_gc_register_address(&cDescriptorPool);
+
+ generated_pool = rb_class_new_instance(0, NULL, klass);
+ rb_gc_register_address(&generated_pool);
+}
+
+static void add_descriptor_to_pool(DescriptorPool* self,
+ Descriptor* descriptor) {
+ CHECK_UPB(
+ upb_symtab_add(self->symtab, (upb_def**)&descriptor->msgdef, 1,
+ NULL, &status),
+ "Adding Descriptor to DescriptorPool failed");
+}
+
+static void add_enumdesc_to_pool(DescriptorPool* self,
+ EnumDescriptor* enumdesc) {
+ CHECK_UPB(
+ upb_symtab_add(self->symtab, (upb_def**)&enumdesc->enumdef, 1,
+ NULL, &status),
+ "Adding EnumDescriptor to DescriptorPool failed");
+}
+
+/*
+ * call-seq:
+ * DescriptorPool.add(descriptor)
+ *
+ * Adds the given Descriptor or EnumDescriptor to this pool. All references to
+ * other types in a Descriptor's fields must be resolvable within this pool or
+ * an exception will be raised.
+ */
+VALUE DescriptorPool_add(VALUE _self, VALUE def) {
+ DEFINE_SELF(DescriptorPool, self, _self);
+ VALUE def_klass = rb_obj_class(def);
+ if (def_klass == cDescriptor) {
+ add_descriptor_to_pool(self, ruby_to_Descriptor(def));
+ } else if (def_klass == cEnumDescriptor) {
+ add_enumdesc_to_pool(self, ruby_to_EnumDescriptor(def));
+ } else {
+ rb_raise(rb_eArgError,
+ "Second argument must be a Descriptor or EnumDescriptor.");
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * DescriptorPool.build(&block)
+ *
+ * Invokes the block with a Builder instance as self. All message and enum types
+ * added within the block are committed to the pool atomically, and may refer
+ * (co)recursively to each other. The user should call Builder#add_message and
+ * Builder#add_enum within the block as appropriate. This is the recommended,
+ * idiomatic way to define new message and enum types.
+ */
+VALUE DescriptorPool_build(VALUE _self) {
+ VALUE ctx = rb_class_new_instance(0, NULL, cBuilder);
+ VALUE block = rb_block_proc();
+ rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+ rb_funcall(ctx, rb_intern("finalize_to_pool"), 1, _self);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * DescriptorPool.lookup(name) => descriptor
+ *
+ * Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none
+ * exists with the given name.
+ */
+VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
+ DEFINE_SELF(DescriptorPool, self, _self);
+ const char* name_str = get_str(name);
+ const upb_def* def = upb_symtab_lookup(self->symtab, name_str);
+ if (!def) {
+ return Qnil;
+ }
+ return get_def_obj(def);
+}
+
+/*
+ * call-seq:
+ * DescriptorPool.generated_pool => descriptor_pool
+ *
+ * Class method that returns the global DescriptorPool. This is a singleton into
+ * which generated-code message and enum types are registered. The user may also
+ * register types in this pool for convenience so that they do not have to hold
+ * a reference to a private pool instance.
+ */
+VALUE DescriptorPool_generated_pool(VALUE _self) {
+ return generated_pool;
+}
+
+// -----------------------------------------------------------------------------
+// Descriptor.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(Descriptor, "Google::Protobuf::Descriptor");
+
+void Descriptor_mark(void* _self) {
+ Descriptor* self = _self;
+ rb_gc_mark(self->klass);
+ rb_gc_mark(self->typeclass_references);
+}
+
+void Descriptor_free(void* _self) {
+ Descriptor* self = _self;
+ upb_msgdef_unref(self->msgdef, &self->msgdef);
+ if (self->layout) {
+ free_layout(self->layout);
+ }
+ if (self->fill_handlers) {
+ upb_handlers_unref(self->fill_handlers, &self->fill_handlers);
+ }
+ if (self->fill_method) {
+ upb_pbdecodermethod_unref(self->fill_method, &self->fill_method);
+ }
+ if (self->pb_serialize_handlers) {
+ upb_handlers_unref(self->pb_serialize_handlers,
+ &self->pb_serialize_handlers);
+ }
+ if (self->json_serialize_handlers) {
+ upb_handlers_unref(self->pb_serialize_handlers,
+ &self->json_serialize_handlers);
+ }
+ xfree(self);
+}
+
+/*
+ * call-seq:
+ * Descriptor.new => descriptor
+ *
+ * Creates a new, empty, message type descriptor. At a minimum, its name must be
+ * set before it is added to a pool. It cannot be used to create messages until
+ * it is added to a pool, after which it becomes immutable (as part of a
+ * finalization process).
+ */
+VALUE Descriptor_alloc(VALUE klass) {
+ Descriptor* self = ALLOC(Descriptor);
+ VALUE ret = TypedData_Wrap_Struct(klass, &_Descriptor_type, self);
+ self->msgdef = upb_msgdef_new(&self->msgdef);
+ self->klass = Qnil;
+ self->layout = NULL;
+ self->fill_handlers = NULL;
+ self->fill_method = NULL;
+ self->pb_serialize_handlers = NULL;
+ self->json_serialize_handlers = NULL;
+ self->typeclass_references = rb_ary_new();
+ return ret;
+}
+
+void Descriptor_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "Descriptor", rb_cObject);
+ rb_define_alloc_func(klass, Descriptor_alloc);
+ rb_define_method(klass, "each", Descriptor_each, 0);
+ rb_define_method(klass, "lookup", Descriptor_lookup, 1);
+ rb_define_method(klass, "add_field", Descriptor_add_field, 1);
+ rb_define_method(klass, "add_oneof", Descriptor_add_oneof, 1);
+ rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0);
+ rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1);
+ rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
+ rb_define_method(klass, "name", Descriptor_name, 0);
+ rb_define_method(klass, "name=", Descriptor_name_set, 1);
+ rb_include_module(klass, rb_mEnumerable);
+ cDescriptor = klass;
+ rb_gc_register_address(&cDescriptor);
+}
+
+/*
+ * call-seq:
+ * Descriptor.name => name
+ *
+ * Returns the name of this message type as a fully-qualfied string (e.g.,
+ * My.Package.MessageType).
+ */
+VALUE Descriptor_name(VALUE _self) {
+ DEFINE_SELF(Descriptor, self, _self);
+ return rb_str_maybe_null(upb_msgdef_fullname(self->msgdef));
+}
+
+/*
+ * call-seq:
+ * Descriptor.name = name
+ *
+ * Assigns a name to this message type. The descriptor must not have been added
+ * to a pool yet.
+ */
+VALUE Descriptor_name_set(VALUE _self, VALUE str) {
+ DEFINE_SELF(Descriptor, self, _self);
+ upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef);
+ const char* name = get_str(str);
+ CHECK_UPB(
+ upb_msgdef_setfullname(mut_def, name, &status),
+ "Error setting Descriptor name");
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Descriptor.each(&block)
+ *
+ * Iterates over fields in this message type, yielding to the block on each one.
+ */
+VALUE Descriptor_each(VALUE _self) {
+ DEFINE_SELF(Descriptor, self, _self);
+
+ upb_msg_field_iter it;
+ for (upb_msg_field_begin(&it, self->msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+ VALUE obj = get_def_obj(field);
+ rb_yield(obj);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Descriptor.lookup(name) => FieldDescriptor
+ *
+ * Returns the field descriptor for the field with the given name, if present,
+ * or nil if none.
+ */
+VALUE Descriptor_lookup(VALUE _self, VALUE name) {
+ DEFINE_SELF(Descriptor, self, _self);
+ const char* s = get_str(name);
+ const upb_fielddef* field = upb_msgdef_ntofz(self->msgdef, s);
+ if (field == NULL) {
+ return Qnil;
+ }
+ return get_def_obj(field);
+}
+
+/*
+ * call-seq:
+ * Descriptor.add_field(field) => nil
+ *
+ * Adds the given FieldDescriptor to this message type. This descriptor must not
+ * have been added to a pool yet. Raises an exception if a field with the same
+ * name or number already exists. Sub-type references (e.g. for fields of type
+ * message) are not resolved at this point.
+ */
+VALUE Descriptor_add_field(VALUE _self, VALUE obj) {
+ DEFINE_SELF(Descriptor, self, _self);
+ upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef);
+ FieldDescriptor* def = ruby_to_FieldDescriptor(obj);
+ upb_fielddef* mut_field_def = check_field_notfrozen(def->fielddef);
+ CHECK_UPB(
+ upb_msgdef_addfield(mut_def, mut_field_def, NULL, &status),
+ "Adding field to Descriptor failed");
+ add_def_obj(def->fielddef, obj);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Descriptor.add_oneof(oneof) => nil
+ *
+ * Adds the given OneofDescriptor to this message type. This descriptor must not
+ * have been added to a pool yet. Raises an exception if a oneof with the same
+ * name already exists, or if any of the oneof's fields' names or numbers
+ * conflict with an existing field in this message type. All fields in the oneof
+ * are added to the message descriptor. Sub-type references (e.g. for fields of
+ * type message) are not resolved at this point.
+ */
+VALUE Descriptor_add_oneof(VALUE _self, VALUE obj) {
+ DEFINE_SELF(Descriptor, self, _self);
+ upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef);
+ OneofDescriptor* def = ruby_to_OneofDescriptor(obj);
+ upb_oneofdef* mut_oneof_def = check_oneof_notfrozen(def->oneofdef);
+ CHECK_UPB(
+ upb_msgdef_addoneof(mut_def, mut_oneof_def, NULL, &status),
+ "Adding oneof to Descriptor failed");
+ add_def_obj(def->oneofdef, obj);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Descriptor.each_oneof(&block) => nil
+ *
+ * Invokes the given block for each oneof in this message type, passing the
+ * corresponding OneofDescriptor.
+ */
+VALUE Descriptor_each_oneof(VALUE _self) {
+ DEFINE_SELF(Descriptor, self, _self);
+
+ upb_msg_oneof_iter it;
+ for (upb_msg_oneof_begin(&it, self->msgdef);
+ !upb_msg_oneof_done(&it);
+ upb_msg_oneof_next(&it)) {
+ const upb_oneofdef* oneof = upb_msg_iter_oneof(&it);
+ VALUE obj = get_def_obj(oneof);
+ rb_yield(obj);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Descriptor.lookup_oneof(name) => OneofDescriptor
+ *
+ * Returns the oneof descriptor for the oneof with the given name, if present,
+ * or nil if none.
+ */
+VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
+ DEFINE_SELF(Descriptor, self, _self);
+ const char* s = get_str(name);
+ const upb_oneofdef* oneof = upb_msgdef_ntooz(self->msgdef, s);
+ if (oneof == NULL) {
+ return Qnil;
+ }
+ return get_def_obj(oneof);
+}
+
+/*
+ * call-seq:
+ * Descriptor.msgclass => message_klass
+ *
+ * Returns the Ruby class created for this message type. Valid only once the
+ * message type has been added to a pool.
+ */
+VALUE Descriptor_msgclass(VALUE _self) {
+ DEFINE_SELF(Descriptor, self, _self);
+ if (!upb_def_isfrozen((const upb_def*)self->msgdef)) {
+ rb_raise(rb_eRuntimeError,
+ "Cannot fetch message class from a Descriptor not yet in a pool.");
+ }
+ if (self->klass == Qnil) {
+ self->klass = build_class_from_descriptor(self);
+ }
+ return self->klass;
+}
+
+// -----------------------------------------------------------------------------
+// FieldDescriptor.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(FieldDescriptor, "Google::Protobuf::FieldDescriptor");
+
+void FieldDescriptor_mark(void* _self) {
+}
+
+void FieldDescriptor_free(void* _self) {
+ FieldDescriptor* self = _self;
+ upb_fielddef_unref(self->fielddef, &self->fielddef);
+ xfree(self);
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.new => field
+ *
+ * Returns a new field descriptor. Its name, type, etc. must be set before it is
+ * added to a message type.
+ */
+VALUE FieldDescriptor_alloc(VALUE klass) {
+ FieldDescriptor* self = ALLOC(FieldDescriptor);
+ VALUE ret = TypedData_Wrap_Struct(klass, &_FieldDescriptor_type, self);
+ upb_fielddef* fielddef = upb_fielddef_new(&self->fielddef);
+ upb_fielddef_setpacked(fielddef, false);
+ self->fielddef = fielddef;
+ return ret;
+}
+
+void FieldDescriptor_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "FieldDescriptor", rb_cObject);
+ rb_define_alloc_func(klass, FieldDescriptor_alloc);
+ rb_define_method(klass, "name", FieldDescriptor_name, 0);
+ rb_define_method(klass, "name=", FieldDescriptor_name_set, 1);
+ rb_define_method(klass, "type", FieldDescriptor_type, 0);
+ rb_define_method(klass, "type=", FieldDescriptor_type_set, 1);
+ rb_define_method(klass, "label", FieldDescriptor_label, 0);
+ rb_define_method(klass, "label=", FieldDescriptor_label_set, 1);
+ rb_define_method(klass, "number", FieldDescriptor_number, 0);
+ rb_define_method(klass, "number=", FieldDescriptor_number_set, 1);
+ rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
+ rb_define_method(klass, "submsg_name=", FieldDescriptor_submsg_name_set, 1);
+ rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
+ rb_define_method(klass, "get", FieldDescriptor_get, 1);
+ rb_define_method(klass, "set", FieldDescriptor_set, 2);
+ cFieldDescriptor = klass;
+ rb_gc_register_address(&cFieldDescriptor);
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.name => name
+ *
+ * Returns the name of this field.
+ */
+VALUE FieldDescriptor_name(VALUE _self) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ return rb_str_maybe_null(upb_fielddef_name(self->fielddef));
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.name = name
+ *
+ * Sets the name of this field. Cannot be called once the containing message
+ * type, if any, is added to a pool.
+ */
+VALUE FieldDescriptor_name_set(VALUE _self, VALUE str) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+ const char* name = get_str(str);
+ CHECK_UPB(upb_fielddef_setname(mut_def, name, &status),
+ "Error setting FieldDescriptor name");
+ return Qnil;
+}
+
+upb_fieldtype_t ruby_to_fieldtype(VALUE type) {
+ if (TYPE(type) != T_SYMBOL) {
+ rb_raise(rb_eArgError, "Expected symbol for field type.");
+ }
+
+ upb_fieldtype_t upb_type = -1;
+
+#define CONVERT(upb, ruby) \
+ if (SYM2ID(type) == rb_intern( # ruby )) { \
+ upb_type = UPB_TYPE_ ## upb; \
+ }
+
+ CONVERT(FLOAT, float);
+ CONVERT(DOUBLE, double);
+ CONVERT(BOOL, bool);
+ CONVERT(STRING, string);
+ CONVERT(BYTES, bytes);
+ CONVERT(MESSAGE, message);
+ CONVERT(ENUM, enum);
+ CONVERT(INT32, int32);
+ CONVERT(INT64, int64);
+ CONVERT(UINT32, uint32);
+ CONVERT(UINT64, uint64);
+
+#undef CONVERT
+
+ if (upb_type == -1) {
+ rb_raise(rb_eArgError, "Unknown field type.");
+ }
+
+ return upb_type;
+}
+
+VALUE fieldtype_to_ruby(upb_fieldtype_t type) {
+ switch (type) {
+#define CONVERT(upb, ruby) \
+ case UPB_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby ));
+ CONVERT(FLOAT, float);
+ CONVERT(DOUBLE, double);
+ CONVERT(BOOL, bool);
+ CONVERT(STRING, string);
+ CONVERT(BYTES, bytes);
+ CONVERT(MESSAGE, message);
+ CONVERT(ENUM, enum);
+ CONVERT(INT32, int32);
+ CONVERT(INT64, int64);
+ CONVERT(UINT32, uint32);
+ CONVERT(UINT64, uint64);
+#undef CONVERT
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.type => type
+ *
+ * Returns this field's type, as a Ruby symbol, or nil if not yet set.
+ *
+ * Valid field types are:
+ * :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
+ * :bytes, :message.
+ */
+VALUE FieldDescriptor_type(VALUE _self) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ if (!upb_fielddef_typeisset(self->fielddef)) {
+ return Qnil;
+ }
+ return fieldtype_to_ruby(upb_fielddef_type(self->fielddef));
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.type = type
+ *
+ * Sets this field's type. Cannot be called if field is part of a message type
+ * already in a pool.
+ */
+VALUE FieldDescriptor_type_set(VALUE _self, VALUE type) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+ upb_fielddef_settype(mut_def, ruby_to_fieldtype(type));
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.label => label
+ *
+ * Returns this field's label (i.e., plurality), as a Ruby symbol.
+ *
+ * Valid field labels are:
+ * :optional, :repeated
+ */
+VALUE FieldDescriptor_label(VALUE _self) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ switch (upb_fielddef_label(self->fielddef)) {
+#define CONVERT(upb, ruby) \
+ case UPB_LABEL_ ## upb : return ID2SYM(rb_intern( # ruby ));
+
+ CONVERT(OPTIONAL, optional);
+ CONVERT(REQUIRED, required);
+ CONVERT(REPEATED, repeated);
+
+#undef CONVERT
+ }
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.label = label
+ *
+ * Sets the label on this field. Cannot be called if field is part of a message
+ * type already in a pool.
+ */
+VALUE FieldDescriptor_label_set(VALUE _self, VALUE label) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+ if (TYPE(label) != T_SYMBOL) {
+ rb_raise(rb_eArgError, "Expected symbol for field label.");
+ }
+
+ upb_label_t upb_label = -1;
+
+#define CONVERT(upb, ruby) \
+ if (SYM2ID(label) == rb_intern( # ruby )) { \
+ upb_label = UPB_LABEL_ ## upb; \
+ }
+
+ CONVERT(OPTIONAL, optional);
+ CONVERT(REQUIRED, required);
+ CONVERT(REPEATED, repeated);
+
+#undef CONVERT
+
+ if (upb_label == -1) {
+ rb_raise(rb_eArgError, "Unknown field label.");
+ }
+
+ upb_fielddef_setlabel(mut_def, upb_label);
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.number => number
+ *
+ * Returns the tag number for this field.
+ */
+VALUE FieldDescriptor_number(VALUE _self) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ return INT2NUM(upb_fielddef_number(self->fielddef));
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.number = number
+ *
+ * Sets the tag number for this field. Cannot be called if field is part of a
+ * message type already in a pool.
+ */
+VALUE FieldDescriptor_number_set(VALUE _self, VALUE number) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+ CHECK_UPB(upb_fielddef_setnumber(mut_def, NUM2INT(number), &status),
+ "Error setting field number");
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.submsg_name => submsg_name
+ *
+ * Returns the name of the message or enum type corresponding to this field, if
+ * it is a message or enum field (respectively), or nil otherwise. This type
+ * name will be resolved within the context of the pool to which the containing
+ * message type is added.
+ */
+VALUE FieldDescriptor_submsg_name(VALUE _self) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ if (!upb_fielddef_hassubdef(self->fielddef)) {
+ return Qnil;
+ }
+ return rb_str_maybe_null(upb_fielddef_subdefname(self->fielddef));
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.submsg_name = submsg_name
+ *
+ * Sets the name of the message or enum type corresponding to this field, if it
+ * is a message or enum field (respectively). This type name will be resolved
+ * within the context of the pool to which the containing message type is added.
+ * Cannot be called on field that are not of message or enum type, or on fields
+ * that are part of a message type already added to a pool.
+ */
+VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+ if (!upb_fielddef_hassubdef(self->fielddef)) {
+ rb_raise(rb_eTypeError, "FieldDescriptor does not have subdef.");
+ }
+ const char* str = get_str(value);
+ CHECK_UPB(upb_fielddef_setsubdefname(mut_def, str, &status),
+ "Error setting submessage name");
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.subtype => message_or_enum_descriptor
+ *
+ * Returns the message or enum descriptor corresponding to this field's type if
+ * it is a message or enum field, respectively, or nil otherwise. Cannot be
+ * called *until* the containing message type is added to a pool (and thus
+ * resolved).
+ */
+VALUE FieldDescriptor_subtype(VALUE _self) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ if (!upb_fielddef_hassubdef(self->fielddef)) {
+ return Qnil;
+ }
+ const upb_def* def = upb_fielddef_subdef(self->fielddef);
+ if (def == NULL) {
+ return Qnil;
+ }
+ return get_def_obj(def);
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.get(message) => value
+ *
+ * Returns the value set for this field on the given message. Raises an
+ * exception if message is of the wrong type.
+ */
+VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ MessageHeader* msg;
+ TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+ if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
+ rb_raise(rb_eTypeError, "get method called on wrong message type");
+ }
+ return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef);
+}
+
+/*
+ * call-seq:
+ * FieldDescriptor.set(message, value)
+ *
+ * Sets the value corresponding to this field to the given value on the given
+ * message. Raises an exception if message is of the wrong type. Performs the
+ * ordinary type-checks for field setting.
+ */
+VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
+ DEFINE_SELF(FieldDescriptor, self, _self);
+ MessageHeader* msg;
+ TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+ if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
+ rb_raise(rb_eTypeError, "set method called on wrong message type");
+ }
+ layout_set(msg->descriptor->layout, Message_data(msg), self->fielddef, value);
+ return Qnil;
+}
+
+// -----------------------------------------------------------------------------
+// OneofDescriptor.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(OneofDescriptor, "Google::Protobuf::OneofDescriptor");
+
+void OneofDescriptor_mark(void* _self) {
+}
+
+void OneofDescriptor_free(void* _self) {
+ OneofDescriptor* self = _self;
+ upb_oneofdef_unref(self->oneofdef, &self->oneofdef);
+ xfree(self);
+}
+
+/*
+ * call-seq:
+ * OneofDescriptor.new => oneof_descriptor
+ *
+ * Creates a new, empty, oneof descriptor. The oneof may only be modified prior
+ * to being added to a message descriptor which is subsequently added to a pool.
+ */
+VALUE OneofDescriptor_alloc(VALUE klass) {
+ OneofDescriptor* self = ALLOC(OneofDescriptor);
+ VALUE ret = TypedData_Wrap_Struct(klass, &_OneofDescriptor_type, self);
+ self->oneofdef = upb_oneofdef_new(&self->oneofdef);
+ return ret;
+}
+
+void OneofDescriptor_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "OneofDescriptor", rb_cObject);
+ rb_define_alloc_func(klass, OneofDescriptor_alloc);
+ rb_define_method(klass, "name", OneofDescriptor_name, 0);
+ rb_define_method(klass, "name=", OneofDescriptor_name_set, 1);
+ rb_define_method(klass, "add_field", OneofDescriptor_add_field, 1);
+ rb_define_method(klass, "each", OneofDescriptor_each, 0);
+ rb_include_module(klass, rb_mEnumerable);
+ cOneofDescriptor = klass;
+ rb_gc_register_address(&cOneofDescriptor);
+}
+
+/*
+ * call-seq:
+ * OneofDescriptor.name => name
+ *
+ * Returns the name of this oneof.
+ */
+VALUE OneofDescriptor_name(VALUE _self) {
+ DEFINE_SELF(OneofDescriptor, self, _self);
+ return rb_str_maybe_null(upb_oneofdef_name(self->oneofdef));
+}
+
+/*
+ * call-seq:
+ * OneofDescriptor.name = name
+ *
+ * Sets a new name for this oneof. The oneof must not have been added to a
+ * message descriptor yet.
+ */
+VALUE OneofDescriptor_name_set(VALUE _self, VALUE value) {
+ DEFINE_SELF(OneofDescriptor, self, _self);
+ upb_oneofdef* mut_def = check_oneof_notfrozen(self->oneofdef);
+ const char* str = get_str(value);
+ CHECK_UPB(upb_oneofdef_setname(mut_def, str, &status),
+ "Error setting oneof name");
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * OneofDescriptor.add_field(field) => nil
+ *
+ * Adds a field to this oneof. The field may have been added to this oneof in
+ * the past, or the message to which this oneof belongs (if any), but may not
+ * have already been added to any other oneof or message. Otherwise, an
+ * exception is raised.
+ *
+ * All fields added to the oneof via this method will be automatically added to
+ * the message to which this oneof belongs, if it belongs to one currently, or
+ * else will be added to any message to which the oneof is later added at the
+ * time that it is added.
+ */
+VALUE OneofDescriptor_add_field(VALUE _self, VALUE obj) {
+ DEFINE_SELF(OneofDescriptor, self, _self);
+ upb_oneofdef* mut_def = check_oneof_notfrozen(self->oneofdef);
+ FieldDescriptor* def = ruby_to_FieldDescriptor(obj);
+ upb_fielddef* mut_field_def = check_field_notfrozen(def->fielddef);
+ CHECK_UPB(
+ upb_oneofdef_addfield(mut_def, mut_field_def, NULL, &status),
+ "Adding field to OneofDescriptor failed");
+ add_def_obj(def->fielddef, obj);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * OneofDescriptor.each(&block) => nil
+ *
+ * Iterates through fields in this oneof, yielding to the block on each one.
+ */
+VALUE OneofDescriptor_each(VALUE _self, VALUE field) {
+ DEFINE_SELF(OneofDescriptor, self, _self);
+ upb_oneof_iter it;
+ for (upb_oneof_begin(&it, self->oneofdef);
+ !upb_oneof_done(&it);
+ upb_oneof_next(&it)) {
+ const upb_fielddef* f = upb_oneof_iter_field(&it);
+ VALUE obj = get_def_obj(f);
+ rb_yield(obj);
+ }
+ return Qnil;
+}
+
+// -----------------------------------------------------------------------------
+// EnumDescriptor.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(EnumDescriptor, "Google::Protobuf::EnumDescriptor");
+
+void EnumDescriptor_mark(void* _self) {
+ EnumDescriptor* self = _self;
+ rb_gc_mark(self->module);
+}
+
+void EnumDescriptor_free(void* _self) {
+ EnumDescriptor* self = _self;
+ upb_enumdef_unref(self->enumdef, &self->enumdef);
+ xfree(self);
+}
+
+/*
+ * call-seq:
+ * EnumDescriptor.new => enum_descriptor
+ *
+ * Creates a new, empty, enum descriptor. Must be added to a pool before the
+ * enum type can be used. The enum type may only be modified prior to adding to
+ * a pool.
+ */
+VALUE EnumDescriptor_alloc(VALUE klass) {
+ EnumDescriptor* self = ALLOC(EnumDescriptor);
+ VALUE ret = TypedData_Wrap_Struct(klass, &_EnumDescriptor_type, self);
+ self->enumdef = upb_enumdef_new(&self->enumdef);
+ self->module = Qnil;
+ return ret;
+}
+
+void EnumDescriptor_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "EnumDescriptor", rb_cObject);
+ rb_define_alloc_func(klass, EnumDescriptor_alloc);
+ rb_define_method(klass, "name", EnumDescriptor_name, 0);
+ rb_define_method(klass, "name=", EnumDescriptor_name_set, 1);
+ rb_define_method(klass, "add_value", EnumDescriptor_add_value, 2);
+ rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1);
+ rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1);
+ rb_define_method(klass, "each", EnumDescriptor_each, 0);
+ rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
+ rb_include_module(klass, rb_mEnumerable);
+ cEnumDescriptor = klass;
+ rb_gc_register_address(&cEnumDescriptor);
+}
+
+/*
+ * call-seq:
+ * EnumDescriptor.name => name
+ *
+ * Returns the name of this enum type.
+ */
+VALUE EnumDescriptor_name(VALUE _self) {
+ DEFINE_SELF(EnumDescriptor, self, _self);
+ return rb_str_maybe_null(upb_enumdef_fullname(self->enumdef));
+}
+
+/*
+ * call-seq:
+ * EnumDescriptor.name = name
+ *
+ * Sets the name of this enum type. Cannot be called if the enum type has
+ * already been added to a pool.
+ */
+VALUE EnumDescriptor_name_set(VALUE _self, VALUE str) {
+ DEFINE_SELF(EnumDescriptor, self, _self);
+ upb_enumdef* mut_def = check_enum_notfrozen(self->enumdef);
+ const char* name = get_str(str);
+ CHECK_UPB(upb_enumdef_setfullname(mut_def, name, &status),
+ "Error setting EnumDescriptor name");
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * EnumDescriptor.add_value(key, value)
+ *
+ * Adds a new key => value mapping to this enum type. Key must be given as a
+ * Ruby symbol. Cannot be called if the enum type has already been added to a
+ * pool. Will raise an exception if the key or value is already in use.
+ */
+VALUE EnumDescriptor_add_value(VALUE _self, VALUE name, VALUE number) {
+ DEFINE_SELF(EnumDescriptor, self, _self);
+ upb_enumdef* mut_def = check_enum_notfrozen(self->enumdef);
+ const char* name_str = rb_id2name(SYM2ID(name));
+ int32_t val = NUM2INT(number);
+ CHECK_UPB(upb_enumdef_addval(mut_def, name_str, val, &status),
+ "Error adding value to enum");
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * EnumDescriptor.lookup_name(name) => value
+ *
+ * Returns the numeric value corresponding to the given key name (as a Ruby
+ * symbol), or nil if none.
+ */
+VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) {
+ DEFINE_SELF(EnumDescriptor, self, _self);
+ const char* name_str= rb_id2name(SYM2ID(name));
+ int32_t val = 0;
+ if (upb_enumdef_ntoiz(self->enumdef, name_str, &val)) {
+ return INT2NUM(val);
+ } else {
+ return Qnil;
+ }
+}
+
+/*
+ * call-seq:
+ * EnumDescriptor.lookup_value(name) => value
+ *
+ * Returns the key name (as a Ruby symbol) corresponding to the integer value,
+ * or nil if none.
+ */
+VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) {
+ DEFINE_SELF(EnumDescriptor, self, _self);
+ int32_t val = NUM2INT(number);
+ const char* name = upb_enumdef_iton(self->enumdef, val);
+ if (name != NULL) {
+ return ID2SYM(rb_intern(name));
+ } else {
+ return Qnil;
+ }
+}
+
+/*
+ * call-seq:
+ * EnumDescriptor.each(&block)
+ *
+ * Iterates over key => value mappings in this enum's definition, yielding to
+ * the block with (key, value) arguments for each one.
+ */
+VALUE EnumDescriptor_each(VALUE _self) {
+ DEFINE_SELF(EnumDescriptor, self, _self);
+
+ upb_enum_iter it;
+ for (upb_enum_begin(&it, self->enumdef);
+ !upb_enum_done(&it);
+ upb_enum_next(&it)) {
+ VALUE key = ID2SYM(rb_intern(upb_enum_iter_name(&it)));
+ VALUE number = INT2NUM(upb_enum_iter_number(&it));
+ rb_yield_values(2, key, number);
+ }
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * EnumDescriptor.enummodule => module
+ *
+ * Returns the Ruby module corresponding to this enum type. Cannot be called
+ * until the enum descriptor has been added to a pool.
+ */
+VALUE EnumDescriptor_enummodule(VALUE _self) {
+ DEFINE_SELF(EnumDescriptor, self, _self);
+ if (!upb_def_isfrozen((const upb_def*)self->enumdef)) {
+ rb_raise(rb_eRuntimeError,
+ "Cannot fetch enum module from an EnumDescriptor not yet "
+ "in a pool.");
+ }
+ if (self->module == Qnil) {
+ self->module = build_module_from_enumdesc(self);
+ }
+ return self->module;
+}
+
+// -----------------------------------------------------------------------------
+// MessageBuilderContext.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(MessageBuilderContext,
+ "Google::Protobuf::Internal::MessageBuilderContext");
+
+void MessageBuilderContext_mark(void* _self) {
+ MessageBuilderContext* self = _self;
+ rb_gc_mark(self->descriptor);
+ rb_gc_mark(self->builder);
+}
+
+void MessageBuilderContext_free(void* _self) {
+ MessageBuilderContext* self = _self;
+ xfree(self);
+}
+
+VALUE MessageBuilderContext_alloc(VALUE klass) {
+ MessageBuilderContext* self = ALLOC(MessageBuilderContext);
+ VALUE ret = TypedData_Wrap_Struct(
+ klass, &_MessageBuilderContext_type, self);
+ self->descriptor = Qnil;
+ self->builder = Qnil;
+ return ret;
+}
+
+void MessageBuilderContext_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "MessageBuilderContext", rb_cObject);
+ rb_define_alloc_func(klass, MessageBuilderContext_alloc);
+ rb_define_method(klass, "initialize",
+ MessageBuilderContext_initialize, 2);
+ rb_define_method(klass, "optional", MessageBuilderContext_optional, -1);
+ rb_define_method(klass, "required", MessageBuilderContext_required, -1);
+ rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1);
+ rb_define_method(klass, "map", MessageBuilderContext_map, -1);
+ rb_define_method(klass, "oneof", MessageBuilderContext_oneof, 1);
+ cMessageBuilderContext = klass;
+ rb_gc_register_address(&cMessageBuilderContext);
+}
+
+/*
+ * call-seq:
+ * MessageBuilderContext.new(desc, builder) => context
+ *
+ * Create a new message builder context around the given message descriptor and
+ * builder context. This class is intended to serve as a DSL context to be used
+ * with #instance_eval.
+ */
+VALUE MessageBuilderContext_initialize(VALUE _self,
+ VALUE msgdef,
+ VALUE builder) {
+ DEFINE_SELF(MessageBuilderContext, self, _self);
+ self->descriptor = msgdef;
+ self->builder = builder;
+ return Qnil;
+}
+
+static VALUE msgdef_add_field(VALUE msgdef,
+ const char* label, VALUE name,
+ VALUE type, VALUE number,
+ VALUE type_class) {
+ VALUE fielddef = rb_class_new_instance(0, NULL, cFieldDescriptor);
+ VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
+
+ rb_funcall(fielddef, rb_intern("label="), 1, ID2SYM(rb_intern(label)));
+ rb_funcall(fielddef, rb_intern("name="), 1, name_str);
+ rb_funcall(fielddef, rb_intern("type="), 1, type);
+ rb_funcall(fielddef, rb_intern("number="), 1, number);
+
+ if (type_class != Qnil) {
+ if (TYPE(type_class) != T_STRING) {
+ rb_raise(rb_eArgError, "Expected string for type class");
+ }
+ // Make it an absolute type name by prepending a dot.
+ type_class = rb_str_append(rb_str_new2("."), type_class);
+ rb_funcall(fielddef, rb_intern("submsg_name="), 1, type_class);
+ }
+
+ rb_funcall(msgdef, rb_intern("add_field"), 1, fielddef);
+ return fielddef;
+}
+
+/*
+ * call-seq:
+ * MessageBuilderContext.optional(name, type, number, type_class = nil)
+ *
+ * Defines a new optional field on this message type with the given type, tag
+ * number, and type class (for message and enum fields). The type must be a Ruby
+ * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+ * string, if present (as accepted by FieldDescriptor#submsg_name=).
+ */
+VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
+ DEFINE_SELF(MessageBuilderContext, self, _self);
+
+ if (argc < 3) {
+ rb_raise(rb_eArgError, "Expected at least 3 arguments.");
+ }
+ VALUE name = argv[0];
+ VALUE type = argv[1];
+ VALUE number = argv[2];
+ VALUE type_class = (argc > 3) ? argv[3] : Qnil;
+
+ return msgdef_add_field(self->descriptor, "optional",
+ name, type, number, type_class);
+}
+
+/*
+ * call-seq:
+ * MessageBuilderContext.required(name, type, number, type_class = nil)
+ *
+ * Defines a new required field on this message type with the given type, tag
+ * number, and type class (for message and enum fields). The type must be a Ruby
+ * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+ * string, if present (as accepted by FieldDescriptor#submsg_name=).
+ *
+ * Proto3 does not have required fields, but this method exists for
+ * completeness. Any attempt to add a message type with required fields to a
+ * pool will currently result in an error.
+ */
+VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) {
+ DEFINE_SELF(MessageBuilderContext, self, _self);
+
+ if (argc < 3) {
+ rb_raise(rb_eArgError, "Expected at least 3 arguments.");
+ }
+ VALUE name = argv[0];
+ VALUE type = argv[1];
+ VALUE number = argv[2];
+ VALUE type_class = (argc > 3) ? argv[3] : Qnil;
+
+ return msgdef_add_field(self->descriptor, "required",
+ name, type, number, type_class);
+}
+
+/*
+ * call-seq:
+ * MessageBuilderContext.repeated(name, type, number, type_class = nil)
+ *
+ * Defines a new repeated field on this message type with the given type, tag
+ * number, and type class (for message and enum fields). The type must be a Ruby
+ * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+ * string, if present (as accepted by FieldDescriptor#submsg_name=).
+ */
+VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self) {
+ DEFINE_SELF(MessageBuilderContext, self, _self);
+
+ if (argc < 3) {
+ rb_raise(rb_eArgError, "Expected at least 3 arguments.");
+ }
+ VALUE name = argv[0];
+ VALUE type = argv[1];
+ VALUE number = argv[2];
+ VALUE type_class = (argc > 3) ? argv[3] : Qnil;
+
+ return msgdef_add_field(self->descriptor, "repeated",
+ name, type, number, type_class);
+}
+
+/*
+ * call-seq:
+ * MessageBuilderContext.map(name, key_type, value_type, number,
+ * value_type_class = nil)
+ *
+ * Defines a new map field on this message type with the given key and value
+ * types, tag number, and type class (for message and enum value types). The key
+ * type must be :int32/:uint32/:int64/:uint64, :bool, or :string. The value type
+ * type must be a Ruby symbol (as accepted by FieldDescriptor#type=) and the
+ * type_class must be a string, if present (as accepted by
+ * FieldDescriptor#submsg_name=).
+ */
+VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
+ DEFINE_SELF(MessageBuilderContext, self, _self);
+
+ if (argc < 4) {
+ rb_raise(rb_eArgError, "Expected at least 4 arguments.");
+ }
+ VALUE name = argv[0];
+ VALUE key_type = argv[1];
+ VALUE value_type = argv[2];
+ VALUE number = argv[3];
+ VALUE type_class = (argc > 4) ? argv[4] : Qnil;
+
+ // Validate the key type. We can't accept enums, messages, or floats/doubles
+ // as map keys. (We exclude these explicitly, and the field-descriptor setter
+ // below then ensures that the type is one of the remaining valid options.)
+ if (SYM2ID(key_type) == rb_intern("float") ||
+ SYM2ID(key_type) == rb_intern("double") ||
+ SYM2ID(key_type) == rb_intern("enum") ||
+ SYM2ID(key_type) == rb_intern("message")) {
+ rb_raise(rb_eArgError,
+ "Cannot add a map field with a float, double, enum, or message "
+ "type.");
+ }
+
+ // Create a new message descriptor for the map entry message, and create a
+ // repeated submessage field here with that type.
+ VALUE mapentry_desc = rb_class_new_instance(0, NULL, cDescriptor);
+ VALUE mapentry_desc_name = rb_funcall(self->descriptor, rb_intern("name"), 0);
+ mapentry_desc_name = rb_str_cat2(mapentry_desc_name, "_MapEntry_");
+ mapentry_desc_name = rb_str_cat2(mapentry_desc_name,
+ rb_id2name(SYM2ID(name)));
+ Descriptor_name_set(mapentry_desc, mapentry_desc_name);
+
+ // The 'mapentry' attribute has no Ruby setter because we do not want the user
+ // attempting to DIY the setup below; we want to ensure that the fields are
+ // correct. So we reach into the msgdef here to set the bit manually.
+ Descriptor* mapentry_desc_self = ruby_to_Descriptor(mapentry_desc);
+ upb_msgdef_setmapentry((upb_msgdef*)mapentry_desc_self->msgdef, true);
+
+ // optional <type> key = 1;
+ VALUE key_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
+ FieldDescriptor_name_set(key_field, rb_str_new2("key"));
+ FieldDescriptor_label_set(key_field, ID2SYM(rb_intern("optional")));
+ FieldDescriptor_number_set(key_field, INT2NUM(1));
+ FieldDescriptor_type_set(key_field, key_type);
+ Descriptor_add_field(mapentry_desc, key_field);
+
+ // optional <type> value = 2;
+ VALUE value_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
+ FieldDescriptor_name_set(value_field, rb_str_new2("value"));
+ FieldDescriptor_label_set(value_field, ID2SYM(rb_intern("optional")));
+ FieldDescriptor_number_set(value_field, INT2NUM(2));
+ FieldDescriptor_type_set(value_field, value_type);
+ if (type_class != Qnil) {
+ VALUE submsg_name = rb_str_new2("."); // prepend '.' to make name absolute.
+ submsg_name = rb_str_append(submsg_name, type_class);
+ FieldDescriptor_submsg_name_set(value_field, submsg_name);
+ }
+ Descriptor_add_field(mapentry_desc, value_field);
+
+ // Add the map-entry message type to the current builder, and use the type to
+ // create the map field itself.
+ Builder* builder_self = ruby_to_Builder(self->builder);
+ rb_ary_push(builder_self->pending_list, mapentry_desc);
+
+ VALUE map_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
+ VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
+ FieldDescriptor_name_set(map_field, name_str);
+ FieldDescriptor_number_set(map_field, number);
+ FieldDescriptor_label_set(map_field, ID2SYM(rb_intern("repeated")));
+ FieldDescriptor_type_set(map_field, ID2SYM(rb_intern("message")));
+ VALUE submsg_name = rb_str_new2("."); // prepend '.' to make name absolute.
+ submsg_name = rb_str_append(submsg_name, mapentry_desc_name);
+ FieldDescriptor_submsg_name_set(map_field, submsg_name);
+ Descriptor_add_field(self->descriptor, map_field);
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * MessageBuilderContext.oneof(name, &block) => nil
+ *
+ * Creates a new OneofDescriptor with the given name, creates a
+ * OneofBuilderContext attached to that OneofDescriptor, evaluates the given
+ * block in the context of that OneofBuilderContext with #instance_eval, and
+ * then adds the oneof to the message.
+ *
+ * This is the recommended, idiomatic way to build oneof definitions.
+ */
+VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name) {
+ DEFINE_SELF(MessageBuilderContext, self, _self);
+ VALUE oneofdef = rb_class_new_instance(0, NULL, cOneofDescriptor);
+ VALUE args[2] = { oneofdef, self->builder };
+ VALUE ctx = rb_class_new_instance(2, args, cOneofBuilderContext);
+ VALUE block = rb_block_proc();
+ VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
+ rb_funcall(oneofdef, rb_intern("name="), 1, name_str);
+ rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+ Descriptor_add_oneof(self->descriptor, oneofdef);
+
+ return Qnil;
+}
+
+// -----------------------------------------------------------------------------
+// OneofBuilderContext.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(OneofBuilderContext,
+ "Google::Protobuf::Internal::OneofBuilderContext");
+
+void OneofBuilderContext_mark(void* _self) {
+ OneofBuilderContext* self = _self;
+ rb_gc_mark(self->descriptor);
+ rb_gc_mark(self->builder);
+}
+
+void OneofBuilderContext_free(void* _self) {
+ OneofBuilderContext* self = _self;
+ xfree(self);
+}
+
+VALUE OneofBuilderContext_alloc(VALUE klass) {
+ OneofBuilderContext* self = ALLOC(OneofBuilderContext);
+ VALUE ret = TypedData_Wrap_Struct(
+ klass, &_OneofBuilderContext_type, self);
+ self->descriptor = Qnil;
+ self->builder = Qnil;
+ return ret;
+}
+
+void OneofBuilderContext_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "OneofBuilderContext", rb_cObject);
+ rb_define_alloc_func(klass, OneofBuilderContext_alloc);
+ rb_define_method(klass, "initialize",
+ OneofBuilderContext_initialize, 2);
+ rb_define_method(klass, "optional", OneofBuilderContext_optional, -1);
+ cOneofBuilderContext = klass;
+ rb_gc_register_address(&cOneofBuilderContext);
+}
+
+/*
+ * call-seq:
+ * OneofBuilderContext.new(desc, builder) => context
+ *
+ * Create a new oneof builder context around the given oneof descriptor and
+ * builder context. This class is intended to serve as a DSL context to be used
+ * with #instance_eval.
+ */
+VALUE OneofBuilderContext_initialize(VALUE _self,
+ VALUE oneofdef,
+ VALUE builder) {
+ DEFINE_SELF(OneofBuilderContext, self, _self);
+ self->descriptor = oneofdef;
+ self->builder = builder;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * OneofBuilderContext.optional(name, type, number, type_class = nil)
+ *
+ * Defines a new optional field in this oneof with the given type, tag number,
+ * and type class (for message and enum fields). The type must be a Ruby symbol
+ * (as accepted by FieldDescriptor#type=) and the type_class must be a string,
+ * if present (as accepted by FieldDescriptor#submsg_name=).
+ */
+VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
+ DEFINE_SELF(OneofBuilderContext, self, _self);
+
+ if (argc < 3) {
+ rb_raise(rb_eArgError, "Expected at least 3 arguments.");
+ }
+ VALUE name = argv[0];
+ VALUE type = argv[1];
+ VALUE number = argv[2];
+ VALUE type_class = (argc > 3) ? argv[3] : Qnil;
+
+ return msgdef_add_field(self->descriptor, "optional",
+ name, type, number, type_class);
+}
+
+// -----------------------------------------------------------------------------
+// EnumBuilderContext.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(EnumBuilderContext,
+ "Google::Protobuf::Internal::EnumBuilderContext");
+
+void EnumBuilderContext_mark(void* _self) {
+ EnumBuilderContext* self = _self;
+ rb_gc_mark(self->enumdesc);
+}
+
+void EnumBuilderContext_free(void* _self) {
+ EnumBuilderContext* self = _self;
+ xfree(self);
+}
+
+VALUE EnumBuilderContext_alloc(VALUE klass) {
+ EnumBuilderContext* self = ALLOC(EnumBuilderContext);
+ VALUE ret = TypedData_Wrap_Struct(
+ klass, &_EnumBuilderContext_type, self);
+ self->enumdesc = Qnil;
+ return ret;
+}
+
+void EnumBuilderContext_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "EnumBuilderContext", rb_cObject);
+ rb_define_alloc_func(klass, EnumBuilderContext_alloc);
+ rb_define_method(klass, "initialize",
+ EnumBuilderContext_initialize, 1);
+ rb_define_method(klass, "value", EnumBuilderContext_value, 2);
+ cEnumBuilderContext = klass;
+ rb_gc_register_address(&cEnumBuilderContext);
+}
+
+/*
+ * call-seq:
+ * EnumBuilderContext.new(enumdesc) => context
+ *
+ * Create a new builder context around the given enum descriptor. This class is
+ * intended to serve as a DSL context to be used with #instance_eval.
+ */
+VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdef) {
+ DEFINE_SELF(EnumBuilderContext, self, _self);
+ self->enumdesc = enumdef;
+ return Qnil;
+}
+
+static VALUE enumdef_add_value(VALUE enumdef,
+ VALUE name, VALUE number) {
+ rb_funcall(enumdef, rb_intern("add_value"), 2, name, number);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * EnumBuilder.add_value(name, number)
+ *
+ * Adds the given name => number mapping to the enum type. Name must be a Ruby
+ * symbol.
+ */
+VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) {
+ DEFINE_SELF(EnumBuilderContext, self, _self);
+ return enumdef_add_value(self->enumdesc, name, number);
+}
+
+// -----------------------------------------------------------------------------
+// Builder.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(Builder, "Google::Protobuf::Internal::Builder");
+
+void Builder_mark(void* _self) {
+ Builder* self = _self;
+ rb_gc_mark(self->pending_list);
+}
+
+void Builder_free(void* _self) {
+ Builder* self = _self;
+ xfree(self->defs);
+ xfree(self);
+}
+
+/*
+ * call-seq:
+ * Builder.new => builder
+ *
+ * Creates a new Builder. A Builder can accumulate a set of new message and enum
+ * descriptors and atomically register them into a pool in a way that allows for
+ * (co)recursive type references.
+ */
+VALUE Builder_alloc(VALUE klass) {
+ Builder* self = ALLOC(Builder);
+ VALUE ret = TypedData_Wrap_Struct(
+ klass, &_Builder_type, self);
+ self->pending_list = rb_ary_new();
+ self->defs = NULL;
+ return ret;
+}
+
+void Builder_register(VALUE module) {
+ VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
+ rb_define_alloc_func(klass, Builder_alloc);
+ rb_define_method(klass, "add_message", Builder_add_message, 1);
+ rb_define_method(klass, "add_enum", Builder_add_enum, 1);
+ rb_define_method(klass, "finalize_to_pool", Builder_finalize_to_pool, 1);
+ cBuilder = klass;
+ rb_gc_register_address(&cBuilder);
+}
+
+/*
+ * call-seq:
+ * Builder.add_message(name, &block)
+ *
+ * Creates a new, empty descriptor with the given name, and invokes the block in
+ * the context of a MessageBuilderContext on that descriptor. The block can then
+ * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
+ * methods to define the message fields.
+ *
+ * This is the recommended, idiomatic way to build message definitions.
+ */
+VALUE Builder_add_message(VALUE _self, VALUE name) {
+ DEFINE_SELF(Builder, self, _self);
+ VALUE msgdef = rb_class_new_instance(0, NULL, cDescriptor);
+ VALUE args[2] = { msgdef, _self };
+ VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
+ VALUE block = rb_block_proc();
+ rb_funcall(msgdef, rb_intern("name="), 1, name);
+ rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+ rb_ary_push(self->pending_list, msgdef);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Builder.add_enum(name, &block)
+ *
+ * Creates a new, empty enum descriptor with the given name, and invokes the block in
+ * the context of an EnumBuilderContext on that descriptor. The block can then
+ * call EnumBuilderContext#add_value to define the enum values.
+ *
+ * This is the recommended, idiomatic way to build enum definitions.
+ */
+VALUE Builder_add_enum(VALUE _self, VALUE name) {
+ DEFINE_SELF(Builder, self, _self);
+ VALUE enumdef = rb_class_new_instance(0, NULL, cEnumDescriptor);
+ VALUE ctx = rb_class_new_instance(1, &enumdef, cEnumBuilderContext);
+ VALUE block = rb_block_proc();
+ rb_funcall(enumdef, rb_intern("name="), 1, name);
+ rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+ rb_ary_push(self->pending_list, enumdef);
+ return Qnil;
+}
+
+static void validate_msgdef(const upb_msgdef* msgdef) {
+ // Verify that no required fields exist. proto3 does not support these.
+ upb_msg_field_iter it;
+ for (upb_msg_field_begin(&it, msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+ if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
+ rb_raise(rb_eTypeError, "Required fields are unsupported in proto3.");
+ }
+ }
+}
+
+static void validate_enumdef(const upb_enumdef* enumdef) {
+ // Verify that an entry exists with integer value 0. (This is the default
+ // value.)
+ const char* lookup = upb_enumdef_iton(enumdef, 0);
+ if (lookup == NULL) {
+ rb_raise(rb_eTypeError,
+ "Enum definition does not contain a value for '0'.");
+ }
+}
+
+/*
+ * call-seq:
+ * Builder.finalize_to_pool(pool)
+ *
+ * Adds all accumulated message and enum descriptors created in this builder
+ * context to the given pool. The operation occurs atomically, and all
+ * descriptors can refer to each other (including in cycles). This is the only
+ * way to build (co)recursive message definitions.
+ *
+ * This method is usually called automatically by DescriptorPool#build after it
+ * invokes the given user block in the context of the builder. The user should
+ * not normally need to call this manually because a Builder is not normally
+ * created manually.
+ */
+VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb) {
+ DEFINE_SELF(Builder, self, _self);
+
+ DescriptorPool* pool = ruby_to_DescriptorPool(pool_rb);
+
+ REALLOC_N(self->defs, upb_def*, RARRAY_LEN(self->pending_list));
+
+ for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) {
+ VALUE def_rb = rb_ary_entry(self->pending_list, i);
+ if (CLASS_OF(def_rb) == cDescriptor) {
+ self->defs[i] = (upb_def*)ruby_to_Descriptor(def_rb)->msgdef;
+ validate_msgdef((const upb_msgdef*)self->defs[i]);
+ } else if (CLASS_OF(def_rb) == cEnumDescriptor) {
+ self->defs[i] = (upb_def*)ruby_to_EnumDescriptor(def_rb)->enumdef;
+ validate_enumdef((const upb_enumdef*)self->defs[i]);
+ }
+ }
+
+ CHECK_UPB(upb_symtab_add(pool->symtab, (upb_def**)self->defs,
+ RARRAY_LEN(self->pending_list), NULL, &status),
+ "Unable to add defs to DescriptorPool");
+
+ for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) {
+ VALUE def_rb = rb_ary_entry(self->pending_list, i);
+ add_def_obj(self->defs[i], def_rb);
+ }
+
+ self->pending_list = rb_ary_new();
+ return Qnil;
+}
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c
new file mode 100644
index 00000000..5730504d
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/encode_decode.c
@@ -0,0 +1,1167 @@
+// 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Parsing.
+// -----------------------------------------------------------------------------
+
+#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs)
+
+// Creates a handlerdata that simply contains the offset for this field.
+static const void* newhandlerdata(upb_handlers* h, uint32_t ofs) {
+ size_t* hd_ofs = ALLOC(size_t);
+ *hd_ofs = ofs;
+ upb_handlers_addcleanup(h, hd_ofs, free);
+ return hd_ofs;
+}
+
+typedef struct {
+ size_t ofs;
+ const upb_msgdef *md;
+} submsg_handlerdata_t;
+
+// Creates a handlerdata that contains offset and submessage type information.
+static const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs,
+ const upb_fielddef* f) {
+ submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t);
+ hd->ofs = ofs;
+ hd->md = upb_fielddef_msgsubdef(f);
+ upb_handlers_addcleanup(h, hd, free);
+ return hd;
+}
+
+typedef struct {
+ size_t ofs; // union data slot
+ size_t case_ofs; // oneof_case field
+ uint32_t oneof_case_num; // oneof-case number to place in oneof_case field
+ const upb_msgdef *md; // msgdef, for oneof submessage handler
+} oneof_handlerdata_t;
+
+static const void *newoneofhandlerdata(upb_handlers *h,
+ uint32_t ofs,
+ uint32_t case_ofs,
+ const upb_fielddef *f) {
+ oneof_handlerdata_t *hd = ALLOC(oneof_handlerdata_t);
+ hd->ofs = ofs;
+ hd->case_ofs = case_ofs;
+ // We reuse the field tag number as a oneof union discriminant tag. Note that
+ // we don't expose these numbers to the user, so the only requirement is that
+ // we have some unique ID for each union case/possibility. The field tag
+ // numbers are already present and are easy to use so there's no reason to
+ // create a separate ID space. In addition, using the field tag number here
+ // lets us easily look up the field in the oneof accessor.
+ hd->oneof_case_num = upb_fielddef_number(f);
+ if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) {
+ hd->md = upb_fielddef_msgsubdef(f);
+ } else {
+ hd->md = NULL;
+ }
+ upb_handlers_addcleanup(h, hd, free);
+ return hd;
+}
+
+// A handler that starts a repeated field. Gets the Repeated*Field instance for
+// this field (such an instance always exists even in an empty message).
+static void *startseq_handler(void* closure, const void* hd) {
+ MessageHeader* msg = closure;
+ const size_t *ofs = hd;
+ return (void*)DEREF(msg, *ofs, VALUE);
+}
+
+// Handlers that append primitive values to a repeated field.
+#define DEFINE_APPEND_HANDLER(type, ctype) \
+ static bool append##type##_handler(void *closure, const void *hd, \
+ ctype val) { \
+ VALUE ary = (VALUE)closure; \
+ RepeatedField_push_native(ary, &val); \
+ return true; \
+ }
+
+DEFINE_APPEND_HANDLER(bool, bool)
+DEFINE_APPEND_HANDLER(int32, int32_t)
+DEFINE_APPEND_HANDLER(uint32, uint32_t)
+DEFINE_APPEND_HANDLER(float, float)
+DEFINE_APPEND_HANDLER(int64, int64_t)
+DEFINE_APPEND_HANDLER(uint64, uint64_t)
+DEFINE_APPEND_HANDLER(double, double)
+
+// Appends a string to a repeated field.
+static void* appendstr_handler(void *closure,
+ const void *hd,
+ size_t size_hint) {
+ VALUE ary = (VALUE)closure;
+ VALUE str = rb_str_new2("");
+ rb_enc_associate(str, kRubyStringUtf8Encoding);
+ RepeatedField_push(ary, str);
+ return (void*)str;
+}
+
+// Appends a 'bytes' string to a repeated field.
+static void* appendbytes_handler(void *closure,
+ const void *hd,
+ size_t size_hint) {
+ VALUE ary = (VALUE)closure;
+ VALUE str = rb_str_new2("");
+ rb_enc_associate(str, kRubyString8bitEncoding);
+ RepeatedField_push(ary, str);
+ return (void*)str;
+}
+
+// Sets a non-repeated string field in a message.
+static void* str_handler(void *closure,
+ const void *hd,
+ size_t size_hint) {
+ MessageHeader* msg = closure;
+ const size_t *ofs = hd;
+ VALUE str = rb_str_new2("");
+ rb_enc_associate(str, kRubyStringUtf8Encoding);
+ DEREF(msg, *ofs, VALUE) = str;
+ return (void*)str;
+}
+
+// Sets a non-repeated 'bytes' field in a message.
+static void* bytes_handler(void *closure,
+ const void *hd,
+ size_t size_hint) {
+ MessageHeader* msg = closure;
+ const size_t *ofs = hd;
+ VALUE str = rb_str_new2("");
+ rb_enc_associate(str, kRubyString8bitEncoding);
+ DEREF(msg, *ofs, VALUE) = str;
+ return (void*)str;
+}
+
+static size_t stringdata_handler(void* closure, const void* hd,
+ const char* str, size_t len,
+ const upb_bufhandle* handle) {
+ VALUE rb_str = (VALUE)closure;
+ rb_str_cat(rb_str, str, len);
+ return len;
+}
+
+// Appends a submessage to a repeated field (a regular Ruby array for now).
+static void *appendsubmsg_handler(void *closure, const void *hd) {
+ VALUE ary = (VALUE)closure;
+ const submsg_handlerdata_t *submsgdata = hd;
+ VALUE subdesc =
+ get_def_obj((void*)submsgdata->md);
+ VALUE subklass = Descriptor_msgclass(subdesc);
+
+ VALUE submsg_rb = rb_class_new_instance(0, NULL, subklass);
+ RepeatedField_push(ary, submsg_rb);
+
+ MessageHeader* submsg;
+ TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
+ return submsg;
+}
+
+// Sets a non-repeated submessage field in a message.
+static void *submsg_handler(void *closure, const void *hd) {
+ MessageHeader* msg = closure;
+ const submsg_handlerdata_t* submsgdata = hd;
+ VALUE subdesc =
+ get_def_obj((void*)submsgdata->md);
+ VALUE subklass = Descriptor_msgclass(subdesc);
+
+ if (DEREF(msg, submsgdata->ofs, VALUE) == Qnil) {
+ DEREF(msg, submsgdata->ofs, VALUE) =
+ rb_class_new_instance(0, NULL, subklass);
+ }
+
+ VALUE submsg_rb = DEREF(msg, submsgdata->ofs, VALUE);
+ MessageHeader* submsg;
+ TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
+ return submsg;
+}
+
+// Handler data for startmap/endmap handlers.
+typedef struct {
+ size_t ofs;
+ upb_fieldtype_t key_field_type;
+ upb_fieldtype_t value_field_type;
+
+ // We know that we can hold this reference because the handlerdata has the
+ // same lifetime as the upb_handlers struct, and the upb_handlers struct holds
+ // a reference to the upb_msgdef, which in turn has references to its subdefs.
+ const upb_def* value_field_subdef;
+} map_handlerdata_t;
+
+// Temporary frame for map parsing: at the beginning of a map entry message, a
+// submsg handler allocates a frame to hold (i) a reference to the Map object
+// into which this message will be inserted and (ii) storage slots to
+// temporarily hold the key and value for this map entry until the end of the
+// submessage. When the submessage ends, another handler is called to insert the
+// value into the map.
+typedef struct {
+ VALUE map;
+ char key_storage[NATIVE_SLOT_MAX_SIZE];
+ char value_storage[NATIVE_SLOT_MAX_SIZE];
+} map_parse_frame_t;
+
+// Handler to begin a map entry: allocates a temporary frame. This is the
+// 'startsubmsg' handler on the msgdef that contains the map field.
+static void *startmapentry_handler(void *closure, const void *hd) {
+ MessageHeader* msg = closure;
+ const map_handlerdata_t* mapdata = hd;
+ VALUE map_rb = DEREF(msg, mapdata->ofs, VALUE);
+
+ map_parse_frame_t* frame = ALLOC(map_parse_frame_t);
+ frame->map = map_rb;
+
+ native_slot_init(mapdata->key_field_type, &frame->key_storage);
+ native_slot_init(mapdata->value_field_type, &frame->value_storage);
+
+ return frame;
+}
+
+// Handler to end a map entry: inserts the value defined during the message into
+// the map. This is the 'endmsg' handler on the map entry msgdef.
+static bool endmap_handler(void *closure, const void *hd, upb_status* s) {
+ map_parse_frame_t* frame = closure;
+ const map_handlerdata_t* mapdata = hd;
+
+ VALUE key = native_slot_get(
+ mapdata->key_field_type, Qnil,
+ &frame->key_storage);
+
+ VALUE value_field_typeclass = Qnil;
+ if (mapdata->value_field_type == UPB_TYPE_MESSAGE ||
+ mapdata->value_field_type == UPB_TYPE_ENUM) {
+ value_field_typeclass = get_def_obj(mapdata->value_field_subdef);
+ }
+
+ VALUE value = native_slot_get(
+ mapdata->value_field_type, value_field_typeclass,
+ &frame->value_storage);
+
+ Map_index_set(frame->map, key, value);
+ free(frame);
+
+ return true;
+}
+
+// Allocates a new map_handlerdata_t given the map entry message definition. If
+// the offset of the field within the parent message is also given, that is
+// added to the handler data as well. Note that this is called *twice* per map
+// field: once in the parent message handler setup when setting the startsubmsg
+// handler and once in the map entry message handler setup when setting the
+// key/value and endmsg handlers. The reason is that there is no easy way to
+// pass the handlerdata down to the sub-message handler setup.
+static map_handlerdata_t* new_map_handlerdata(
+ size_t ofs,
+ const upb_msgdef* mapentry_def,
+ Descriptor* desc) {
+
+ map_handlerdata_t* hd = ALLOC(map_handlerdata_t);
+ hd->ofs = ofs;
+ const upb_fielddef* key_field = upb_msgdef_itof(mapentry_def,
+ MAP_KEY_FIELD);
+ assert(key_field != NULL);
+ hd->key_field_type = upb_fielddef_type(key_field);
+ const upb_fielddef* value_field = upb_msgdef_itof(mapentry_def,
+ MAP_VALUE_FIELD);
+ assert(value_field != NULL);
+ hd->value_field_type = upb_fielddef_type(value_field);
+ hd->value_field_subdef = upb_fielddef_subdef(value_field);
+
+ return hd;
+}
+
+// Handlers that set primitive values in oneofs.
+#define DEFINE_ONEOF_HANDLER(type, ctype) \
+ static bool oneof##type##_handler(void *closure, const void *hd, \
+ ctype val) { \
+ const oneof_handlerdata_t *oneofdata = hd; \
+ DEREF(closure, oneofdata->case_ofs, uint32_t) = \
+ oneofdata->oneof_case_num; \
+ DEREF(closure, oneofdata->ofs, ctype) = val; \
+ return true; \
+ }
+
+DEFINE_ONEOF_HANDLER(bool, bool)
+DEFINE_ONEOF_HANDLER(int32, int32_t)
+DEFINE_ONEOF_HANDLER(uint32, uint32_t)
+DEFINE_ONEOF_HANDLER(float, float)
+DEFINE_ONEOF_HANDLER(int64, int64_t)
+DEFINE_ONEOF_HANDLER(uint64, uint64_t)
+DEFINE_ONEOF_HANDLER(double, double)
+
+#undef DEFINE_ONEOF_HANDLER
+
+// Handlers for strings in a oneof.
+static void *oneofstr_handler(void *closure,
+ const void *hd,
+ size_t size_hint) {
+ MessageHeader* msg = closure;
+ const oneof_handlerdata_t *oneofdata = hd;
+ VALUE str = rb_str_new2("");
+ rb_enc_associate(str, kRubyStringUtf8Encoding);
+ DEREF(msg, oneofdata->case_ofs, uint32_t) =
+ oneofdata->oneof_case_num;
+ DEREF(msg, oneofdata->ofs, VALUE) = str;
+ return (void*)str;
+}
+
+static void *oneofbytes_handler(void *closure,
+ const void *hd,
+ size_t size_hint) {
+ MessageHeader* msg = closure;
+ const oneof_handlerdata_t *oneofdata = hd;
+ VALUE str = rb_str_new2("");
+ rb_enc_associate(str, kRubyString8bitEncoding);
+ DEREF(msg, oneofdata->case_ofs, uint32_t) =
+ oneofdata->oneof_case_num;
+ DEREF(msg, oneofdata->ofs, VALUE) = str;
+ return (void*)str;
+}
+
+// Handler for a submessage field in a oneof.
+static void *oneofsubmsg_handler(void *closure,
+ const void *hd) {
+ MessageHeader* msg = closure;
+ const oneof_handlerdata_t *oneofdata = hd;
+ uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);
+
+ VALUE subdesc =
+ get_def_obj((void*)oneofdata->md);
+ VALUE subklass = Descriptor_msgclass(subdesc);
+
+ if (oldcase != oneofdata->oneof_case_num ||
+ DEREF(msg, oneofdata->ofs, VALUE) == Qnil) {
+ DEREF(msg, oneofdata->ofs, VALUE) =
+ rb_class_new_instance(0, NULL, subklass);
+ }
+ // Set the oneof case *after* allocating the new class instance -- otherwise,
+ // if the Ruby GC is invoked as part of a call into the VM, it might invoke
+ // our mark routines, and our mark routines might see the case value
+ // indicating a VALUE is present and expect a valid VALUE. See comment in
+ // layout_set() for more detail: basically, the change to the value and the
+ // case must be atomic w.r.t. the Ruby VM.
+ DEREF(msg, oneofdata->case_ofs, uint32_t) =
+ oneofdata->oneof_case_num;
+
+ VALUE submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
+ MessageHeader* submsg;
+ TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
+ return submsg;
+}
+
+// Set up handlers for a repeated field.
+static void add_handlers_for_repeated_field(upb_handlers *h,
+ const upb_fielddef *f,
+ size_t offset) {
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
+ upb_handlers_setstartseq(h, f, startseq_handler, &attr);
+ upb_handlerattr_uninit(&attr);
+
+ switch (upb_fielddef_type(f)) {
+
+#define SET_HANDLER(utype, ltype) \
+ case utype: \
+ upb_handlers_set##ltype(h, f, append##ltype##_handler, NULL); \
+ break;
+
+ SET_HANDLER(UPB_TYPE_BOOL, bool);
+ SET_HANDLER(UPB_TYPE_INT32, int32);
+ SET_HANDLER(UPB_TYPE_UINT32, uint32);
+ SET_HANDLER(UPB_TYPE_ENUM, int32);
+ SET_HANDLER(UPB_TYPE_FLOAT, float);
+ SET_HANDLER(UPB_TYPE_INT64, int64);
+ SET_HANDLER(UPB_TYPE_UINT64, uint64);
+ SET_HANDLER(UPB_TYPE_DOUBLE, double);
+
+#undef SET_HANDLER
+
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES: {
+ bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
+ upb_handlers_setstartstr(h, f, is_bytes ?
+ appendbytes_handler : appendstr_handler,
+ NULL);
+ upb_handlers_setstring(h, f, stringdata_handler, NULL);
+ break;
+ }
+ case UPB_TYPE_MESSAGE: {
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, f));
+ upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
+ upb_handlerattr_uninit(&attr);
+ break;
+ }
+ }
+}
+
+// Set up handlers for a singular field.
+static void add_handlers_for_singular_field(upb_handlers *h,
+ const upb_fielddef *f,
+ size_t offset) {
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_BOOL:
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_ENUM:
+ case UPB_TYPE_FLOAT:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT64:
+ case UPB_TYPE_DOUBLE:
+ upb_shim_set(h, f, offset, -1);
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES: {
+ bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
+ upb_handlers_setstartstr(h, f,
+ is_bytes ? bytes_handler : str_handler,
+ &attr);
+ upb_handlers_setstring(h, f, stringdata_handler, &attr);
+ upb_handlerattr_uninit(&attr);
+ break;
+ }
+ case UPB_TYPE_MESSAGE: {
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, offset, f));
+ upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
+ upb_handlerattr_uninit(&attr);
+ break;
+ }
+ }
+}
+
+// Adds handlers to a map field.
+static void add_handlers_for_mapfield(upb_handlers* h,
+ const upb_fielddef* fielddef,
+ size_t offset,
+ Descriptor* desc) {
+ const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef);
+ map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
+ upb_handlers_addcleanup(h, hd, free);
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, hd);
+ upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr);
+ upb_handlerattr_uninit(&attr);
+}
+
+// Adds handlers to a map-entry msgdef.
+static void add_handlers_for_mapentry(const upb_msgdef* msgdef,
+ upb_handlers* h,
+ Descriptor* desc) {
+ const upb_fielddef* key_field = map_entry_key(msgdef);
+ const upb_fielddef* value_field = map_entry_value(msgdef);
+ map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc);
+ upb_handlers_addcleanup(h, hd, free);
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, hd);
+ upb_handlers_setendmsg(h, endmap_handler, &attr);
+
+ add_handlers_for_singular_field(
+ h, key_field,
+ offsetof(map_parse_frame_t, key_storage));
+ add_handlers_for_singular_field(
+ h, value_field,
+ offsetof(map_parse_frame_t, value_storage));
+}
+
+// Set up handlers for a oneof field.
+static void add_handlers_for_oneof_field(upb_handlers *h,
+ const upb_fielddef *f,
+ size_t offset,
+ size_t oneof_case_offset) {
+
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(
+ &attr, newoneofhandlerdata(h, offset, oneof_case_offset, f));
+
+ switch (upb_fielddef_type(f)) {
+
+#define SET_HANDLER(utype, ltype) \
+ case utype: \
+ upb_handlers_set##ltype(h, f, oneof##ltype##_handler, &attr); \
+ break;
+
+ SET_HANDLER(UPB_TYPE_BOOL, bool);
+ SET_HANDLER(UPB_TYPE_INT32, int32);
+ SET_HANDLER(UPB_TYPE_UINT32, uint32);
+ SET_HANDLER(UPB_TYPE_ENUM, int32);
+ SET_HANDLER(UPB_TYPE_FLOAT, float);
+ SET_HANDLER(UPB_TYPE_INT64, int64);
+ SET_HANDLER(UPB_TYPE_UINT64, uint64);
+ SET_HANDLER(UPB_TYPE_DOUBLE, double);
+
+#undef SET_HANDLER
+
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES: {
+ bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
+ upb_handlers_setstartstr(h, f, is_bytes ?
+ oneofbytes_handler : oneofstr_handler,
+ &attr);
+ upb_handlers_setstring(h, f, stringdata_handler, NULL);
+ break;
+ }
+ case UPB_TYPE_MESSAGE: {
+ upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr);
+ break;
+ }
+ }
+
+ upb_handlerattr_uninit(&attr);
+}
+
+
+static void add_handlers_for_message(const void *closure, upb_handlers *h) {
+ const upb_msgdef* msgdef = upb_handlers_msgdef(h);
+ Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef));
+
+ // If this is a mapentry message type, set up a special set of handlers and
+ // bail out of the normal (user-defined) message type handling.
+ if (upb_msgdef_mapentry(msgdef)) {
+ add_handlers_for_mapentry(msgdef, h, desc);
+ return;
+ }
+
+ // Ensure layout exists. We may be invoked to create handlers for a given
+ // message if we are included as a submsg of another message type before our
+ // class is actually built, so to work around this, we just create the layout
+ // (and handlers, in the class-building function) on-demand.
+ if (desc->layout == NULL) {
+ desc->layout = create_layout(desc->msgdef);
+ }
+
+ upb_msg_field_iter i;
+ for (upb_msg_field_begin(&i, desc->msgdef);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ const upb_fielddef *f = upb_msg_iter_field(&i);
+ size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset +
+ sizeof(MessageHeader);
+
+ if (upb_fielddef_containingoneof(f)) {
+ size_t oneof_case_offset =
+ desc->layout->fields[upb_fielddef_index(f)].case_offset +
+ sizeof(MessageHeader);
+ add_handlers_for_oneof_field(h, f, offset, oneof_case_offset);
+ } else if (is_map_field(f)) {
+ add_handlers_for_mapfield(h, f, offset, desc);
+ } else if (upb_fielddef_isseq(f)) {
+ add_handlers_for_repeated_field(h, f, offset);
+ } else {
+ add_handlers_for_singular_field(h, f, offset);
+ }
+ }
+}
+
+// Creates upb handlers for populating a message.
+static const upb_handlers *new_fill_handlers(Descriptor* desc,
+ const void* owner) {
+ // TODO(cfallin, haberman): once upb gets a caching/memoization layer for
+ // handlers, reuse subdef handlers so that e.g. if we already parse
+ // B-with-field-of-type-C, we don't have to rebuild the whole hierarchy to
+ // parse A-with-field-of-type-B-with-field-of-type-C.
+ return upb_handlers_newfrozen(desc->msgdef, owner,
+ add_handlers_for_message, NULL);
+}
+
+// Constructs the handlers for filling a message's data into an in-memory
+// object.
+const upb_handlers* get_fill_handlers(Descriptor* desc) {
+ if (!desc->fill_handlers) {
+ desc->fill_handlers =
+ new_fill_handlers(desc, &desc->fill_handlers);
+ }
+ return desc->fill_handlers;
+}
+
+// Constructs the upb decoder method for parsing messages of this type.
+// This is called from the message class creation code.
+const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor* desc,
+ const void* owner) {
+ const upb_handlers* handlers = get_fill_handlers(desc);
+ upb_pbdecodermethodopts opts;
+ upb_pbdecodermethodopts_init(&opts, handlers);
+
+ const upb_pbdecodermethod *ret = upb_pbdecodermethod_new(&opts, owner);
+ return ret;
+}
+
+static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
+ if (desc->fill_method == NULL) {
+ desc->fill_method = new_fillmsg_decodermethod(
+ desc, &desc->fill_method);
+ }
+ return desc->fill_method;
+}
+
+/*
+ * call-seq:
+ * MessageClass.decode(data) => message
+ *
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
+ * format) under the interpretration given by this message class's definition
+ * and returns a message object with the corresponding field values.
+ */
+VALUE Message_decode(VALUE klass, VALUE data) {
+ VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+ Descriptor* desc = ruby_to_Descriptor(descriptor);
+ VALUE msgklass = Descriptor_msgclass(descriptor);
+
+ if (TYPE(data) != T_STRING) {
+ rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
+ }
+
+ VALUE msg_rb = rb_class_new_instance(0, NULL, msgklass);
+ MessageHeader* msg;
+ TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+
+ const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
+ const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
+ upb_pbdecoder decoder;
+ upb_sink sink;
+ upb_status status = UPB_STATUS_INIT;
+
+ upb_pbdecoder_init(&decoder, method, &status);
+ upb_sink_reset(&sink, h, msg);
+ upb_pbdecoder_resetoutput(&decoder, &sink);
+ upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
+ upb_pbdecoder_input(&decoder));
+
+ upb_pbdecoder_uninit(&decoder);
+ if (!upb_ok(&status)) {
+ rb_raise(rb_eRuntimeError, "Error occurred during parsing: %s.",
+ upb_status_errmsg(&status));
+ }
+
+ return msg_rb;
+}
+
+/*
+ * call-seq:
+ * MessageClass.decode_json(data) => message
+ *
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
+ * format) under the interpretration given by this message class's definition
+ * and returns a message object with the corresponding field values.
+ */
+VALUE Message_decode_json(VALUE klass, VALUE data) {
+ VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+ Descriptor* desc = ruby_to_Descriptor(descriptor);
+ VALUE msgklass = Descriptor_msgclass(descriptor);
+
+ if (TYPE(data) != T_STRING) {
+ rb_raise(rb_eArgError, "Expected string for JSON data.");
+ }
+ // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
+ // convert, because string handlers pass data directly to message string
+ // fields.
+
+ VALUE msg_rb = rb_class_new_instance(0, NULL, msgklass);
+ MessageHeader* msg;
+ TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+
+ upb_status status = UPB_STATUS_INIT;
+ upb_json_parser parser;
+ upb_json_parser_init(&parser, &status);
+
+ upb_sink sink;
+ upb_sink_reset(&sink, get_fill_handlers(desc), msg);
+ upb_json_parser_resetoutput(&parser, &sink);
+ upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
+ upb_json_parser_input(&parser));
+
+ upb_json_parser_uninit(&parser);
+ if (!upb_ok(&status)) {
+ rb_raise(rb_eRuntimeError, "Error occurred during parsing: %s.",
+ upb_status_errmsg(&status));
+ }
+
+ return msg_rb;
+}
+
+// -----------------------------------------------------------------------------
+// Serializing.
+// -----------------------------------------------------------------------------
+//
+// The code below also comes from upb's prototype Ruby binding, developed by
+// haberman@.
+
+/* stringsink *****************************************************************/
+
+// This should probably be factored into a common upb component.
+
+typedef struct {
+ upb_byteshandler handler;
+ upb_bytessink sink;
+ char *ptr;
+ size_t len, size;
+} stringsink;
+
+static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) {
+ stringsink *sink = _sink;
+ sink->len = 0;
+ return sink;
+}
+
+static size_t stringsink_string(void *_sink, const void *hd, const char *ptr,
+ size_t len, const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+
+ stringsink *sink = _sink;
+ size_t new_size = sink->size;
+
+ while (sink->len + len > new_size) {
+ new_size *= 2;
+ }
+
+ if (new_size != sink->size) {
+ sink->ptr = realloc(sink->ptr, new_size);
+ sink->size = new_size;
+ }
+
+ memcpy(sink->ptr + sink->len, ptr, len);
+ sink->len += len;
+
+ return len;
+}
+
+void stringsink_init(stringsink *sink) {
+ upb_byteshandler_init(&sink->handler);
+ upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL);
+ upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL);
+
+ upb_bytessink_reset(&sink->sink, &sink->handler, sink);
+
+ sink->size = 32;
+ sink->ptr = malloc(sink->size);
+ sink->len = 0;
+}
+
+void stringsink_uninit(stringsink *sink) {
+ free(sink->ptr);
+}
+
+/* msgvisitor *****************************************************************/
+
+// TODO: If/when we support proto2 semantics in addition to the current proto3
+// semantics, which means that we have true field presence, we will want to
+// modify msgvisitor so that it emits all present fields rather than all
+// non-default-value fields.
+//
+// Likewise, when implementing JSON serialization, we may need to have a
+// 'verbose' mode that outputs all fields and a 'concise' mode that outputs only
+// those with non-default values.
+
+static void putmsg(VALUE msg, const Descriptor* desc,
+ upb_sink *sink, int depth);
+
+static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
+ upb_selector_t ret;
+ bool ok = upb_handlers_getselector(f, type, &ret);
+ UPB_ASSERT_VAR(ok, ok);
+ return ret;
+}
+
+static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) {
+ if (str == Qnil) return;
+
+ assert(BUILTIN_TYPE(str) == RUBY_T_STRING);
+ upb_sink subsink;
+
+ // Ensure that the string has the correct encoding. We also check at field-set
+ // time, but the user may have mutated the string object since then.
+ native_slot_validate_string_encoding(upb_fielddef_type(f), str);
+
+ upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str),
+ &subsink);
+ upb_sink_putstring(&subsink, getsel(f, UPB_HANDLER_STRING), RSTRING_PTR(str),
+ RSTRING_LEN(str), NULL);
+ upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR));
+}
+
+static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
+ int depth) {
+ if (submsg == Qnil) return;
+
+ upb_sink subsink;
+ VALUE descriptor = rb_iv_get(submsg, kDescriptorInstanceVar);
+ Descriptor* subdesc = ruby_to_Descriptor(descriptor);
+
+ upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
+ putmsg(submsg, subdesc, &subsink, depth + 1);
+ upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
+}
+
+static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
+ int depth) {
+ if (ary == Qnil) return;
+
+ upb_sink subsink;
+
+ upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
+
+ upb_fieldtype_t type = upb_fielddef_type(f);
+ upb_selector_t sel = 0;
+ if (upb_fielddef_isprimitive(f)) {
+ sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+ }
+
+ int size = NUM2INT(RepeatedField_length(ary));
+ for (int i = 0; i < size; i++) {
+ void* memory = RepeatedField_index_native(ary, i);
+ switch (type) {
+#define T(upbtypeconst, upbtype, ctype) \
+ case upbtypeconst: \
+ upb_sink_put##upbtype(&subsink, sel, *((ctype *)memory)); \
+ break;
+
+ T(UPB_TYPE_FLOAT, float, float)
+ T(UPB_TYPE_DOUBLE, double, double)
+ T(UPB_TYPE_BOOL, bool, int8_t)
+ case UPB_TYPE_ENUM:
+ T(UPB_TYPE_INT32, int32, int32_t)
+ T(UPB_TYPE_UINT32, uint32, uint32_t)
+ T(UPB_TYPE_INT64, int64, int64_t)
+ T(UPB_TYPE_UINT64, uint64, uint64_t)
+
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ putstr(*((VALUE *)memory), f, &subsink);
+ break;
+ case UPB_TYPE_MESSAGE:
+ putsubmsg(*((VALUE *)memory), f, &subsink, depth);
+ break;
+
+#undef T
+
+ }
+ }
+ upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
+}
+
+static void put_ruby_value(VALUE value,
+ const upb_fielddef *f,
+ VALUE type_class,
+ int depth,
+ upb_sink *sink) {
+ upb_selector_t sel = 0;
+ if (upb_fielddef_isprimitive(f)) {
+ sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+ }
+
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32:
+ upb_sink_putint32(sink, sel, NUM2INT(value));
+ break;
+ case UPB_TYPE_INT64:
+ upb_sink_putint64(sink, sel, NUM2LL(value));
+ break;
+ case UPB_TYPE_UINT32:
+ upb_sink_putuint32(sink, sel, NUM2UINT(value));
+ break;
+ case UPB_TYPE_UINT64:
+ upb_sink_putuint64(sink, sel, NUM2ULL(value));
+ break;
+ case UPB_TYPE_FLOAT:
+ upb_sink_putfloat(sink, sel, NUM2DBL(value));
+ break;
+ case UPB_TYPE_DOUBLE:
+ upb_sink_putdouble(sink, sel, NUM2DBL(value));
+ break;
+ case UPB_TYPE_ENUM: {
+ if (TYPE(value) == T_SYMBOL) {
+ value = rb_funcall(type_class, rb_intern("resolve"), 1, value);
+ }
+ upb_sink_putint32(sink, sel, NUM2INT(value));
+ break;
+ }
+ case UPB_TYPE_BOOL:
+ upb_sink_putbool(sink, sel, value == Qtrue);
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ putstr(value, f, sink);
+ break;
+ case UPB_TYPE_MESSAGE:
+ putsubmsg(value, f, sink, depth);
+ }
+}
+
+static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
+ int depth) {
+ if (map == Qnil) return;
+ Map* self = ruby_to_Map(map);
+
+ upb_sink subsink;
+
+ upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
+
+ assert(upb_fielddef_type(f) == UPB_TYPE_MESSAGE);
+ const upb_fielddef* key_field = map_field_key(f);
+ const upb_fielddef* value_field = map_field_value(f);
+
+ Map_iter it;
+ for (Map_begin(map, &it); !Map_done(&it); Map_next(&it)) {
+ VALUE key = Map_iter_key(&it);
+ VALUE value = Map_iter_value(&it);
+
+ upb_sink entry_sink;
+ upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG), &entry_sink);
+ upb_sink_startmsg(&entry_sink);
+
+ put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink);
+ put_ruby_value(value, value_field, self->value_type_class, depth + 1,
+ &entry_sink);
+
+ upb_status status;
+ upb_sink_endmsg(&entry_sink, &status);
+ upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
+ }
+
+ upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
+}
+
+static void putmsg(VALUE msg_rb, const Descriptor* desc,
+ upb_sink *sink, int depth) {
+ upb_sink_startmsg(sink);
+
+ // Protect against cycles (possible because users may freely reassign message
+ // and repeated fields) by imposing a maximum recursion depth.
+ if (depth > UPB_SINK_MAX_NESTING) {
+ rb_raise(rb_eRuntimeError,
+ "Maximum recursion depth exceeded during encoding.");
+ }
+
+ MessageHeader* msg;
+ TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+
+ upb_msg_field_iter i;
+ for (upb_msg_field_begin(&i, desc->msgdef);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ upb_fielddef *f = upb_msg_iter_field(&i);
+ uint32_t offset =
+ desc->layout->fields[upb_fielddef_index(f)].offset +
+ sizeof(MessageHeader);
+
+ if (upb_fielddef_containingoneof(f)) {
+ uint32_t oneof_case_offset =
+ desc->layout->fields[upb_fielddef_index(f)].case_offset +
+ sizeof(MessageHeader);
+ // For a oneof, check that this field is actually present -- skip all the
+ // below if not.
+ if (DEREF(msg, oneof_case_offset, uint32_t) !=
+ upb_fielddef_number(f)) {
+ continue;
+ }
+ // Otherwise, fall through to the appropriate singular-field handler
+ // below.
+ }
+
+ if (is_map_field(f)) {
+ VALUE map = DEREF(msg, offset, VALUE);
+ if (map != Qnil) {
+ putmap(map, f, sink, depth);
+ }
+ } else if (upb_fielddef_isseq(f)) {
+ VALUE ary = DEREF(msg, offset, VALUE);
+ if (ary != Qnil) {
+ putary(ary, f, sink, depth);
+ }
+ } else if (upb_fielddef_isstring(f)) {
+ VALUE str = DEREF(msg, offset, VALUE);
+ if (RSTRING_LEN(str) > 0) {
+ putstr(str, f, sink);
+ }
+ } else if (upb_fielddef_issubmsg(f)) {
+ putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth);
+ } else {
+ upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+
+#define T(upbtypeconst, upbtype, ctype, default_value) \
+ case upbtypeconst: { \
+ ctype value = DEREF(msg, offset, ctype); \
+ if (value != default_value) { \
+ upb_sink_put##upbtype(sink, sel, value); \
+ } \
+ } \
+ break;
+
+ switch (upb_fielddef_type(f)) {
+ T(UPB_TYPE_FLOAT, float, float, 0.0)
+ T(UPB_TYPE_DOUBLE, double, double, 0.0)
+ T(UPB_TYPE_BOOL, bool, uint8_t, 0)
+ case UPB_TYPE_ENUM:
+ T(UPB_TYPE_INT32, int32, int32_t, 0)
+ T(UPB_TYPE_UINT32, uint32, uint32_t, 0)
+ T(UPB_TYPE_INT64, int64, int64_t, 0)
+ T(UPB_TYPE_UINT64, uint64, uint64_t, 0)
+
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ case UPB_TYPE_MESSAGE: rb_raise(rb_eRuntimeError, "Internal error.");
+ }
+
+#undef T
+
+ }
+ }
+
+ upb_status status;
+ upb_sink_endmsg(sink, &status);
+}
+
+static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
+ if (desc->pb_serialize_handlers == NULL) {
+ desc->pb_serialize_handlers =
+ upb_pb_encoder_newhandlers(desc->msgdef, &desc->pb_serialize_handlers);
+ }
+ return desc->pb_serialize_handlers;
+}
+
+static const upb_handlers* msgdef_json_serialize_handlers(Descriptor* desc) {
+ if (desc->json_serialize_handlers == NULL) {
+ desc->json_serialize_handlers =
+ upb_json_printer_newhandlers(
+ desc->msgdef, &desc->json_serialize_handlers);
+ }
+ return desc->json_serialize_handlers;
+}
+
+/*
+ * call-seq:
+ * MessageClass.encode(msg) => bytes
+ *
+ * Encodes the given message object to its serialized form in protocol buffers
+ * wire format.
+ */
+VALUE Message_encode(VALUE klass, VALUE msg_rb) {
+ VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+ Descriptor* desc = ruby_to_Descriptor(descriptor);
+
+ stringsink sink;
+ stringsink_init(&sink);
+
+ const upb_handlers* serialize_handlers =
+ msgdef_pb_serialize_handlers(desc);
+
+ upb_pb_encoder encoder;
+ upb_pb_encoder_init(&encoder, serialize_handlers);
+ upb_pb_encoder_resetoutput(&encoder, &sink.sink);
+
+ putmsg(msg_rb, desc, upb_pb_encoder_input(&encoder), 0);
+
+ VALUE ret = rb_str_new(sink.ptr, sink.len);
+
+ upb_pb_encoder_uninit(&encoder);
+ stringsink_uninit(&sink);
+
+ return ret;
+}
+
+/*
+ * call-seq:
+ * MessageClass.encode_json(msg) => json_string
+ *
+ * Encodes the given message object into its serialized JSON representation.
+ */
+VALUE Message_encode_json(VALUE klass, VALUE msg_rb) {
+ VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+ Descriptor* desc = ruby_to_Descriptor(descriptor);
+
+ stringsink sink;
+ stringsink_init(&sink);
+
+ const upb_handlers* serialize_handlers =
+ msgdef_json_serialize_handlers(desc);
+
+ upb_json_printer printer;
+ upb_json_printer_init(&printer, serialize_handlers);
+ upb_json_printer_resetoutput(&printer, &sink.sink);
+
+ putmsg(msg_rb, desc, upb_json_printer_input(&printer), 0);
+
+ VALUE ret = rb_str_new(sink.ptr, sink.len);
+
+ upb_json_printer_uninit(&printer);
+ stringsink_uninit(&sink);
+
+ return ret;
+}
+
+/*
+ * call-seq:
+ * Google::Protobuf.encode(msg) => bytes
+ *
+ * Encodes the given message object to protocol buffers wire format. This is an
+ * alternative to the #encode method on msg's class.
+ */
+VALUE Google_Protobuf_encode(VALUE self, VALUE msg_rb) {
+ VALUE klass = CLASS_OF(msg_rb);
+ return Message_encode(klass, msg_rb);
+}
+
+/*
+ * call-seq:
+ * Google::Protobuf.encode_json(msg) => json_string
+ *
+ * Encodes the given message object to its JSON representation. This is an
+ * alternative to the #encode_json method on msg's class.
+ */
+VALUE Google_Protobuf_encode_json(VALUE self, VALUE msg_rb) {
+ VALUE klass = CLASS_OF(msg_rb);
+ return Message_encode_json(klass, msg_rb);
+}
+
+/*
+ * call-seq:
+ * Google::Protobuf.decode(class, bytes) => msg
+ *
+ * Decodes the given bytes as protocol buffers wire format under the
+ * interpretation given by the given class's message definition. This is an
+ * alternative to the #decode method on the given class.
+ */
+VALUE Google_Protobuf_decode(VALUE self, VALUE klass, VALUE msg_rb) {
+ return Message_decode(klass, msg_rb);
+}
+
+/*
+ * call-seq:
+ * Google::Protobuf.decode_json(class, json_string) => msg
+ *
+ * Decodes the given JSON string under the interpretation given by the given
+ * class's message definition. This is an alternative to the #decode_json method
+ * on the given class.
+ */
+VALUE Google_Protobuf_decode_json(VALUE self, VALUE klass, VALUE msg_rb) {
+ return Message_decode_json(klass, msg_rb);
+}
diff --git a/ruby/ext/google/protobuf_c/extconf.rb b/ruby/ext/google/protobuf_c/extconf.rb
new file mode 100644
index 00000000..8d60392c
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/extconf.rb
@@ -0,0 +1,10 @@
+#!/usr/bin/ruby
+
+require 'mkmf'
+
+$CFLAGS += " -O3 -std=c99 -Wno-unused-function -DNDEBUG "
+
+$objs = ["protobuf.o", "defs.o", "storage.o", "message.o",
+ "repeated_field.o", "map.o", "encode_decode.o", "upb.o"]
+
+create_makefile("google/protobuf_c")
diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c
new file mode 100644
index 00000000..12e7a9d9
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/map.c
@@ -0,0 +1,805 @@
+// 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Basic map operations on top of upb's strtable.
+//
+// Note that we roll our own `Map` container here because, as for
+// `RepeatedField`, we want a strongly-typed container. This is so that any user
+// errors due to incorrect map key or value types are raised as close as
+// possible to the error site, rather than at some deferred point (e.g.,
+// serialization).
+//
+// We build our `Map` on top of upb_strtable so that we're able to take
+// advantage of the native_slot storage abstraction, as RepeatedField does.
+// (This is not quite a perfect mapping -- see the key conversions below -- but
+// gives us full support and error-checking for all value types for free.)
+// -----------------------------------------------------------------------------
+
+// Map values are stored using the native_slot abstraction (as with repeated
+// field values), but keys are a bit special. Since we use a strtable, we need
+// to store keys as sequences of bytes such that equality of those bytes maps
+// one-to-one to equality of keys. We store strings directly (i.e., they map to
+// their own bytes) and integers as native integers (using the native_slot
+// abstraction).
+
+// Note that there is another tradeoff here in keeping string keys as native
+// strings rather than Ruby strings: traversing the Map requires conversion to
+// Ruby string values on every traversal, potentially creating more garbage. We
+// should consider ways to cache a Ruby version of the key if this becomes an
+// issue later.
+
+// Forms a key to use with the underlying strtable from a Ruby key value. |buf|
+// must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to
+// construct a key byte sequence if needed. |out_key| and |out_length| provide
+// the resulting key data/length.
+#define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t)
+static void table_key(Map* self, VALUE key,
+ char* buf,
+ const char** out_key,
+ size_t* out_length) {
+ switch (self->key_type) {
+ case UPB_TYPE_BYTES:
+ case UPB_TYPE_STRING:
+ // Strings: use string content directly.
+ Check_Type(key, T_STRING);
+ native_slot_validate_string_encoding(self->key_type, key);
+ *out_key = RSTRING_PTR(key);
+ *out_length = RSTRING_LEN(key);
+ break;
+
+ case UPB_TYPE_BOOL:
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_UINT64:
+ native_slot_set(self->key_type, Qnil, buf, key);
+ *out_key = buf;
+ *out_length = native_slot_size(self->key_type);
+ break;
+
+ default:
+ // Map constructor should not allow a Map with another key type to be
+ // constructed.
+ assert(false);
+ break;
+ }
+}
+
+static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) {
+ switch (self->key_type) {
+ case UPB_TYPE_BYTES:
+ case UPB_TYPE_STRING: {
+ VALUE ret = rb_str_new(buf, length);
+ rb_enc_associate(ret,
+ (self->key_type == UPB_TYPE_BYTES) ?
+ kRubyString8bitEncoding : kRubyStringUtf8Encoding);
+ return ret;
+ }
+
+ case UPB_TYPE_BOOL:
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_UINT64:
+ return native_slot_get(self->key_type, Qnil, buf);
+
+ default:
+ assert(false);
+ return Qnil;
+ }
+}
+
+static void* value_memory(upb_value* v) {
+ return (void*)(&v->val.uint64);
+}
+
+// -----------------------------------------------------------------------------
+// Map container type.
+// -----------------------------------------------------------------------------
+
+const rb_data_type_t Map_type = {
+ "Google::Protobuf::Map",
+ { Map_mark, Map_free, NULL },
+};
+
+VALUE cMap;
+
+Map* ruby_to_Map(VALUE _self) {
+ Map* self;
+ TypedData_Get_Struct(_self, Map, &Map_type, self);
+ return self;
+}
+
+void Map_mark(void* _self) {
+ Map* self = _self;
+
+ rb_gc_mark(self->value_type_class);
+
+ if (self->value_type == UPB_TYPE_STRING ||
+ self->value_type == UPB_TYPE_BYTES ||
+ self->value_type == UPB_TYPE_MESSAGE) {
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &self->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+ upb_value v = upb_strtable_iter_value(&it);
+ void* mem = value_memory(&v);
+ native_slot_mark(self->value_type, mem);
+ }
+ }
+}
+
+void Map_free(void* _self) {
+ Map* self = _self;
+ upb_strtable_uninit(&self->table);
+ xfree(self);
+}
+
+VALUE Map_alloc(VALUE klass) {
+ Map* self = ALLOC(Map);
+ memset(self, 0, sizeof(Map));
+ self->value_type_class = Qnil;
+ VALUE ret = TypedData_Wrap_Struct(klass, &Map_type, self);
+ return ret;
+}
+
+static bool needs_typeclass(upb_fieldtype_t type) {
+ switch (type) {
+ case UPB_TYPE_MESSAGE:
+ case UPB_TYPE_ENUM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * call-seq:
+ * Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
+ * => new map
+ *
+ * Allocates a new Map container. This constructor may be called with 2, 3, or 4
+ * arguments. The first two arguments are always present and are symbols (taking
+ * on the same values as field-type symbols in message descriptors) that
+ * indicate the type of the map key and value fields.
+ *
+ * The supported key types are: :int32, :int64, :uint32, :uint64, :bool,
+ * :string, :bytes.
+ *
+ * The supported value types are: :int32, :int64, :uint32, :uint64, :bool,
+ * :string, :bytes, :enum, :message.
+ *
+ * The third argument, value_typeclass, must be present if value_type is :enum
+ * or :message. As in RepeatedField#new, this argument must be a message class
+ * (for :message) or enum module (for :enum).
+ *
+ * The last argument, if present, provides initial content for map. Note that
+ * this may be an ordinary Ruby hashmap or another Map instance with identical
+ * key and value types. Also note that this argument may be present whether or
+ * not value_typeclass is present (and it is unambiguously separate from
+ * value_typeclass because value_typeclass's presence is strictly determined by
+ * value_type). The contents of this initial hashmap or Map instance are
+ * shallow-copied into the new Map: the original map is unmodified, but
+ * references to underlying objects will be shared if the value type is a
+ * message type.
+ */
+VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+
+ // We take either two args (:key_type, :value_type), three args (:key_type,
+ // :value_type, "ValueMessageType"), or four args (the above plus an initial
+ // hashmap).
+ if (argc < 2 || argc > 4) {
+ rb_raise(rb_eArgError, "Map constructor expects 2, 3 or 4 arguments.");
+ }
+
+ self->key_type = ruby_to_fieldtype(argv[0]);
+ self->value_type = ruby_to_fieldtype(argv[1]);
+
+ // Check that the key type is an allowed type.
+ switch (self->key_type) {
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_UINT64:
+ case UPB_TYPE_BOOL:
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ // These are OK.
+ break;
+ default:
+ rb_raise(rb_eArgError, "Invalid key type for map.");
+ }
+
+ int init_value_arg = 2;
+ if (needs_typeclass(self->value_type) && argc > 2) {
+ self->value_type_class = argv[2];
+ validate_type_class(self->value_type, self->value_type_class);
+ init_value_arg = 3;
+ }
+
+ // Table value type is always UINT64: this ensures enough space to store the
+ // native_slot value.
+ if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) {
+ rb_raise(rb_eRuntimeError, "Could not allocate table.");
+ }
+
+ if (argc > init_value_arg) {
+ Map_merge_into_self(_self, argv[init_value_arg]);
+ }
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Map.each(&block)
+ *
+ * Invokes &block on each |key, value| pair in the map, in unspecified order.
+ * Note that Map also includes Enumerable; map thus acts like a normal Ruby
+ * sequence.
+ */
+VALUE Map_each(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &self->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+
+ VALUE key = table_key_to_ruby(
+ self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
+
+ upb_value v = upb_strtable_iter_value(&it);
+ void* mem = value_memory(&v);
+ VALUE value = native_slot_get(self->value_type,
+ self->value_type_class,
+ mem);
+
+ rb_yield_values(2, key, value);
+ }
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Map.keys => [list_of_keys]
+ *
+ * Returns the list of keys contained in the map, in unspecified order.
+ */
+VALUE Map_keys(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+
+ VALUE ret = rb_ary_new();
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &self->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+
+ VALUE key = table_key_to_ruby(
+ self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
+
+ rb_ary_push(ret, key);
+ }
+
+ return ret;
+}
+
+/*
+ * call-seq:
+ * Map.values => [list_of_values]
+ *
+ * Returns the list of values contained in the map, in unspecified order.
+ */
+VALUE Map_values(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+
+ VALUE ret = rb_ary_new();
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &self->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+
+ upb_value v = upb_strtable_iter_value(&it);
+ void* mem = value_memory(&v);
+ VALUE value = native_slot_get(self->value_type,
+ self->value_type_class,
+ mem);
+
+ rb_ary_push(ret, value);
+ }
+
+ return ret;
+}
+
+/*
+ * call-seq:
+ * Map.[](key) => value
+ *
+ * Accesses the element at the given key. Throws an exception if the key type is
+ * incorrect. Returns nil when the key is not present in the map.
+ */
+VALUE Map_index(VALUE _self, VALUE key) {
+ Map* self = ruby_to_Map(_self);
+
+ char keybuf[TABLE_KEY_BUF_LENGTH];
+ const char* keyval = NULL;
+ size_t length = 0;
+ table_key(self, key, keybuf, &keyval, &length);
+
+ upb_value v;
+ if (upb_strtable_lookup2(&self->table, keyval, length, &v)) {
+ void* mem = value_memory(&v);
+ return native_slot_get(self->value_type, self->value_type_class, mem);
+ } else {
+ return Qnil;
+ }
+}
+
+/*
+ * call-seq:
+ * Map.[]=(key, value) => value
+ *
+ * Inserts or overwrites the value at the given key with the given new value.
+ * Throws an exception if the key type is incorrect. Returns the new value that
+ * was just inserted.
+ */
+VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
+ Map* self = ruby_to_Map(_self);
+
+ char keybuf[TABLE_KEY_BUF_LENGTH];
+ const char* keyval = NULL;
+ size_t length = 0;
+ table_key(self, key, keybuf, &keyval, &length);
+
+ upb_value v;
+ void* mem = value_memory(&v);
+ native_slot_set(self->value_type, self->value_type_class, mem, value);
+
+ // Replace any existing value by issuing a 'remove' operation first.
+ upb_strtable_remove2(&self->table, keyval, length, NULL);
+ if (!upb_strtable_insert2(&self->table, keyval, length, v)) {
+ rb_raise(rb_eRuntimeError, "Could not insert into table");
+ }
+
+ // Ruby hashmap's :[]= method also returns the inserted value.
+ return value;
+}
+
+/*
+ * call-seq:
+ * Map.has_key?(key) => bool
+ *
+ * Returns true if the given key is present in the map. Throws an exception if
+ * the key has the wrong type.
+ */
+VALUE Map_has_key(VALUE _self, VALUE key) {
+ Map* self = ruby_to_Map(_self);
+
+ char keybuf[TABLE_KEY_BUF_LENGTH];
+ const char* keyval = NULL;
+ size_t length = 0;
+ table_key(self, key, keybuf, &keyval, &length);
+
+ if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) {
+ return Qtrue;
+ } else {
+ return Qfalse;
+ }
+}
+
+/*
+ * call-seq:
+ * Map.delete(key) => old_value
+ *
+ * Deletes the value at the given key, if any, returning either the old value or
+ * nil if none was present. Throws an exception if the key is of the wrong type.
+ */
+VALUE Map_delete(VALUE _self, VALUE key) {
+ Map* self = ruby_to_Map(_self);
+
+ char keybuf[TABLE_KEY_BUF_LENGTH];
+ const char* keyval = NULL;
+ size_t length = 0;
+ table_key(self, key, keybuf, &keyval, &length);
+
+ upb_value v;
+ if (upb_strtable_remove2(&self->table, keyval, length, &v)) {
+ void* mem = value_memory(&v);
+ return native_slot_get(self->value_type, self->value_type_class, mem);
+ } else {
+ return Qnil;
+ }
+}
+
+/*
+ * call-seq:
+ * Map.clear
+ *
+ * Removes all entries from the map.
+ */
+VALUE Map_clear(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+
+ // Uninit and reinit the table -- this is faster than iterating and doing a
+ // delete-lookup on each key.
+ upb_strtable_uninit(&self->table);
+ if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) {
+ rb_raise(rb_eRuntimeError, "Unable to re-initialize table");
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Map.length
+ *
+ * Returns the number of entries (key-value pairs) in the map.
+ */
+VALUE Map_length(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+ return ULL2NUM(upb_strtable_count(&self->table));
+}
+
+static VALUE Map_new_this_type(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+ VALUE new_map = Qnil;
+ VALUE key_type = fieldtype_to_ruby(self->key_type);
+ VALUE value_type = fieldtype_to_ruby(self->value_type);
+ if (self->value_type_class != Qnil) {
+ new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3,
+ key_type, value_type, self->value_type_class);
+ } else {
+ new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
+ key_type, value_type);
+ }
+ return new_map;
+}
+
+/*
+ * call-seq:
+ * Map.dup => new_map
+ *
+ * Duplicates this map with a shallow copy. References to all non-primitive
+ * element objects (e.g., submessages) are shared.
+ */
+VALUE Map_dup(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+ VALUE new_map = Map_new_this_type(_self);
+ Map* new_self = ruby_to_Map(new_map);
+
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &self->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+
+ upb_value v = upb_strtable_iter_value(&it);
+ void* mem = value_memory(&v);
+ upb_value dup;
+ void* dup_mem = value_memory(&dup);
+ native_slot_dup(self->value_type, dup_mem, mem);
+
+ if (!upb_strtable_insert2(&new_self->table,
+ upb_strtable_iter_key(&it),
+ upb_strtable_iter_keylength(&it),
+ dup)) {
+ rb_raise(rb_eRuntimeError, "Error inserting value into new table");
+ }
+ }
+
+ return new_map;
+}
+
+// Used by Google::Protobuf.deep_copy but not exposed directly.
+VALUE Map_deep_copy(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+ VALUE new_map = Map_new_this_type(_self);
+ Map* new_self = ruby_to_Map(new_map);
+
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &self->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+
+ upb_value v = upb_strtable_iter_value(&it);
+ void* mem = value_memory(&v);
+ upb_value dup;
+ void* dup_mem = value_memory(&dup);
+ native_slot_deep_copy(self->value_type, dup_mem, mem);
+
+ if (!upb_strtable_insert2(&new_self->table,
+ upb_strtable_iter_key(&it),
+ upb_strtable_iter_keylength(&it),
+ dup)) {
+ rb_raise(rb_eRuntimeError, "Error inserting value into new table");
+ }
+ }
+
+ return new_map;
+}
+
+/*
+ * call-seq:
+ * Map.==(other) => boolean
+ *
+ * Compares this map to another. Maps are equal if they have identical key sets,
+ * and for each key, the values in both maps compare equal. Elements are
+ * compared as per normal Ruby semantics, by calling their :== methods (or
+ * performing a more efficient comparison for primitive types).
+ *
+ * Maps with dissimilar key types or value types/typeclasses are never equal,
+ * even if value comparison (for example, between integers and floats) would
+ * have otherwise indicated that every element has equal value.
+ */
+VALUE Map_eq(VALUE _self, VALUE _other) {
+ Map* self = ruby_to_Map(_self);
+
+ // Allow comparisons to Ruby hashmaps by converting to a temporary Map
+ // instance. Slow, but workable.
+ if (TYPE(_other) == T_HASH) {
+ VALUE other_map = Map_new_this_type(_self);
+ Map_merge_into_self(other_map, _other);
+ _other = other_map;
+ }
+
+ Map* other = ruby_to_Map(_other);
+
+ if (self == other) {
+ return Qtrue;
+ }
+ if (self->key_type != other->key_type ||
+ self->value_type != other->value_type ||
+ self->value_type_class != other->value_type_class) {
+ return Qfalse;
+ }
+ if (upb_strtable_count(&self->table) != upb_strtable_count(&other->table)) {
+ return Qfalse;
+ }
+
+ // For each member of self, check that an equal member exists at the same key
+ // in other.
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &self->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+
+ upb_value v = upb_strtable_iter_value(&it);
+ void* mem = value_memory(&v);
+ upb_value other_v;
+ void* other_mem = value_memory(&other_v);
+
+ if (!upb_strtable_lookup2(&other->table,
+ upb_strtable_iter_key(&it),
+ upb_strtable_iter_keylength(&it),
+ &other_v)) {
+ // Not present in other map.
+ return Qfalse;
+ }
+
+ if (!native_slot_eq(self->value_type, mem, other_mem)) {
+ // Present, but value not equal.
+ return Qfalse;
+ }
+ }
+
+ return Qtrue;
+}
+
+/*
+ * call-seq:
+ * Map.hash => hash_value
+ *
+ * Returns a hash value based on this map's contents.
+ */
+VALUE Map_hash(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+
+ st_index_t h = rb_hash_start(0);
+ VALUE hash_sym = rb_intern("hash");
+
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &self->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+ VALUE key = table_key_to_ruby(
+ self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
+
+ upb_value v = upb_strtable_iter_value(&it);
+ void* mem = value_memory(&v);
+ VALUE value = native_slot_get(self->value_type,
+ self->value_type_class,
+ mem);
+
+ h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0)));
+ h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0)));
+ }
+
+ return INT2FIX(h);
+}
+
+/*
+ * call-seq:
+ * Map.inspect => string
+ *
+ * Returns a string representing this map's elements. It will be formatted as
+ * "{key => value, key => value, ...}", with each key and value string
+ * representation computed by its own #inspect method.
+ */
+VALUE Map_inspect(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+
+ VALUE str = rb_str_new2("{");
+
+ bool first = true;
+ VALUE inspect_sym = rb_intern("inspect");
+
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &self->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+ VALUE key = table_key_to_ruby(
+ self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
+
+ upb_value v = upb_strtable_iter_value(&it);
+ void* mem = value_memory(&v);
+ VALUE value = native_slot_get(self->value_type,
+ self->value_type_class,
+ mem);
+
+ if (!first) {
+ str = rb_str_cat2(str, ", ");
+ } else {
+ first = false;
+ }
+ str = rb_str_append(str, rb_funcall(key, inspect_sym, 0));
+ str = rb_str_cat2(str, "=>");
+ str = rb_str_append(str, rb_funcall(value, inspect_sym, 0));
+ }
+
+ str = rb_str_cat2(str, "}");
+ return str;
+}
+
+/*
+ * call-seq:
+ * Map.merge(other_map) => map
+ *
+ * Copies key/value pairs from other_map into a copy of this map. If a key is
+ * set in other_map and this map, the value from other_map overwrites the value
+ * in the new copy of this map. Returns the new copy of this map with merged
+ * contents.
+ */
+VALUE Map_merge(VALUE _self, VALUE hashmap) {
+ VALUE dupped = Map_dup(_self);
+ return Map_merge_into_self(dupped, hashmap);
+}
+
+static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) {
+ Map_index_set(self, key, value);
+ return ST_CONTINUE;
+}
+
+// Used only internally -- shared by #merge and #initialize.
+VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
+ if (TYPE(hashmap) == T_HASH) {
+ rb_hash_foreach(hashmap, merge_into_self_callback, _self);
+ } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
+ RTYPEDDATA_TYPE(hashmap) == &Map_type) {
+
+ Map* self = ruby_to_Map(_self);
+ Map* other = ruby_to_Map(hashmap);
+
+ if (self->key_type != other->key_type ||
+ self->value_type != other->value_type ||
+ self->value_type_class != other->value_type_class) {
+ rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
+ }
+
+ upb_strtable_iter it;
+ for (upb_strtable_begin(&it, &other->table);
+ !upb_strtable_done(&it);
+ upb_strtable_next(&it)) {
+
+ // Replace any existing value by issuing a 'remove' operation first.
+ upb_value oldv;
+ upb_strtable_remove2(&self->table,
+ upb_strtable_iter_key(&it),
+ upb_strtable_iter_keylength(&it),
+ &oldv);
+
+ upb_value v = upb_strtable_iter_value(&it);
+ upb_strtable_insert2(&self->table,
+ upb_strtable_iter_key(&it),
+ upb_strtable_iter_keylength(&it),
+ v);
+ }
+ } else {
+ rb_raise(rb_eArgError, "Unknown type merging into Map");
+ }
+ return _self;
+}
+
+// Internal method: map iterator initialization (used for serialization).
+void Map_begin(VALUE _self, Map_iter* iter) {
+ Map* self = ruby_to_Map(_self);
+ iter->self = self;
+ upb_strtable_begin(&iter->it, &self->table);
+}
+
+void Map_next(Map_iter* iter) {
+ upb_strtable_next(&iter->it);
+}
+
+bool Map_done(Map_iter* iter) {
+ return upb_strtable_done(&iter->it);
+}
+
+VALUE Map_iter_key(Map_iter* iter) {
+ return table_key_to_ruby(
+ iter->self,
+ upb_strtable_iter_key(&iter->it),
+ upb_strtable_iter_keylength(&iter->it));
+}
+
+VALUE Map_iter_value(Map_iter* iter) {
+ upb_value v = upb_strtable_iter_value(&iter->it);
+ void* mem = value_memory(&v);
+ return native_slot_get(iter->self->value_type,
+ iter->self->value_type_class,
+ mem);
+}
+
+void Map_register(VALUE module) {
+ VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
+ rb_define_alloc_func(klass, Map_alloc);
+ cMap = klass;
+ rb_gc_register_address(&cMap);
+
+ rb_define_method(klass, "initialize", Map_init, -1);
+ rb_define_method(klass, "each", Map_each, 0);
+ rb_define_method(klass, "keys", Map_keys, 0);
+ rb_define_method(klass, "values", Map_values, 0);
+ rb_define_method(klass, "[]", Map_index, 1);
+ rb_define_method(klass, "[]=", Map_index_set, 2);
+ rb_define_method(klass, "has_key?", Map_has_key, 1);
+ rb_define_method(klass, "delete", Map_delete, 1);
+ rb_define_method(klass, "clear", Map_clear, 0);
+ rb_define_method(klass, "length", Map_length, 0);
+ rb_define_method(klass, "dup", Map_dup, 0);
+ rb_define_method(klass, "==", Map_eq, 1);
+ rb_define_method(klass, "hash", Map_hash, 0);
+ rb_define_method(klass, "inspect", Map_inspect, 0);
+ rb_define_method(klass, "merge", Map_merge, 1);
+ rb_include_module(klass, rb_mEnumerable);
+}
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
new file mode 100644
index 00000000..7e58a617
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -0,0 +1,516 @@
+// 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Class/module creation from msgdefs and enumdefs, respectively.
+// -----------------------------------------------------------------------------
+
+void* Message_data(void* msg) {
+ return ((uint8_t *)msg) + sizeof(MessageHeader);
+}
+
+void Message_mark(void* _self) {
+ MessageHeader* self = (MessageHeader *)_self;
+ layout_mark(self->descriptor->layout, Message_data(self));
+}
+
+void Message_free(void* self) {
+ xfree(self);
+}
+
+rb_data_type_t Message_type = {
+ "Message",
+ { Message_mark, Message_free, NULL },
+};
+
+VALUE Message_alloc(VALUE klass) {
+ VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+ Descriptor* desc = ruby_to_Descriptor(descriptor);
+ MessageHeader* msg = (MessageHeader*)ALLOC_N(
+ uint8_t, sizeof(MessageHeader) + desc->layout->size);
+ memset(Message_data(msg), 0, desc->layout->size);
+
+ // We wrap first so that everything in the message object is GC-rooted in case
+ // a collection happens during object creation in layout_init().
+ VALUE ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
+ msg->descriptor = desc;
+ rb_iv_set(ret, kDescriptorInstanceVar, descriptor);
+
+ layout_init(desc->layout, Message_data(msg));
+
+ return ret;
+}
+
+static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
+ // If no fields in the oneof, always nil.
+ if (upb_oneofdef_numfields(o) == 0) {
+ return Qnil;
+ }
+ // Grab the first field in the oneof so we can get its layout info to find the
+ // oneof_case field.
+ upb_oneof_iter it;
+ upb_oneof_begin(&it, o);
+ assert(!upb_oneof_done(&it));
+ const upb_fielddef* first_field = upb_oneof_iter_field(&it);
+ assert(upb_fielddef_containingoneof(first_field) != NULL);
+
+ size_t case_ofs =
+ self->descriptor->layout->
+ fields[upb_fielddef_index(first_field)].case_offset;
+ uint32_t oneof_case = *((uint32_t*)(Message_data(self) + case_ofs));
+
+ if (oneof_case == ONEOF_CASE_NONE) {
+ return Qnil;
+ }
+
+ // oneof_case is a field index, so find that field.
+ const upb_fielddef* f = upb_oneofdef_itof(o, oneof_case);
+ assert(f != NULL);
+
+ return ID2SYM(rb_intern(upb_fielddef_name(f)));
+}
+
+/*
+ * call-seq:
+ * Message.method_missing(*args)
+ *
+ * Provides accessors and setters for message fields according to their field
+ * names. For any field whose name does not conflict with a built-in method, an
+ * accessor is provided with the same name as the field, and a setter is
+ * provided with the name of the field plus the '=' suffix. Thus, given a
+ * message instance 'msg' with field 'foo', the following code is valid:
+ *
+ * msg.foo = 42
+ * puts msg.foo
+ *
+ * This method also provides read-only accessors for oneofs. If a oneof exists
+ * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
+ * the name of the field in that oneof that is currently set, or nil if none.
+ */
+VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
+ MessageHeader* self;
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+ if (argc < 1) {
+ rb_raise(rb_eArgError, "Expected method name as first argument.");
+ }
+ VALUE method_name = argv[0];
+ if (!SYMBOL_P(method_name)) {
+ rb_raise(rb_eArgError, "Expected symbol as method name.");
+ }
+ VALUE method_str = rb_id2str(SYM2ID(method_name));
+ char* name = RSTRING_PTR(method_str);
+ size_t name_len = RSTRING_LEN(method_str);
+ bool setter = false;
+
+ // Setters have names that end in '='.
+ if (name[name_len - 1] == '=') {
+ setter = true;
+ name_len--;
+ }
+
+ // Check for a oneof name first.
+ const upb_oneofdef* o = upb_msgdef_ntoo(self->descriptor->msgdef,
+ name, name_len);
+ if (o != NULL) {
+ if (setter) {
+ rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
+ }
+ return which_oneof_field(self, o);
+ }
+
+ // Otherwise, check for a field with that name.
+ const upb_fielddef* f = upb_msgdef_ntof(self->descriptor->msgdef,
+ name, name_len);
+
+ if (f == NULL) {
+ rb_raise(rb_eArgError, "Unknown field");
+ }
+
+ if (setter) {
+ if (argc < 2) {
+ rb_raise(rb_eArgError, "No value provided to setter.");
+ }
+ layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
+ return Qnil;
+ } else {
+ return layout_get(self->descriptor->layout, Message_data(self), f);
+ }
+}
+
+int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
+ MessageHeader* self;
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+ if (!SYMBOL_P(key)) {
+ rb_raise(rb_eArgError,
+ "Expected symbols as hash keys in initialization map.");
+ }
+
+ VALUE method_str = rb_id2str(SYM2ID(key));
+ char* name = RSTRING_PTR(method_str);
+ const upb_fielddef* f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
+ if (f == NULL) {
+ rb_raise(rb_eArgError,
+ "Unknown field name in initialization map entry.");
+ }
+
+ if (is_map_field(f)) {
+ if (TYPE(val) != T_HASH) {
+ rb_raise(rb_eArgError,
+ "Expected Hash object as initializer value for map field.");
+ }
+ VALUE map = layout_get(self->descriptor->layout, Message_data(self), f);
+ Map_merge_into_self(map, val);
+ } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
+ if (TYPE(val) != T_ARRAY) {
+ rb_raise(rb_eArgError,
+ "Expected array as initializer value for repeated field.");
+ }
+ VALUE ary = layout_get(self->descriptor->layout, Message_data(self), f);
+ for (int i = 0; i < RARRAY_LEN(val); i++) {
+ RepeatedField_push(ary, rb_ary_entry(val, i));
+ }
+ } else {
+ layout_set(self->descriptor->layout, Message_data(self), f, val);
+ }
+ return 0;
+}
+
+/*
+ * call-seq:
+ * Message.new(kwargs) => new_message
+ *
+ * Creates a new instance of the given message class. Keyword arguments may be
+ * provided with keywords corresponding to field names.
+ *
+ * Note that no literal Message class exists. Only concrete classes per message
+ * type exist, as provided by the #msgclass method on Descriptors after they
+ * have been added to a pool. The method definitions described here on the
+ * Message class are provided on each concrete message class.
+ */
+VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
+ if (argc == 0) {
+ return Qnil;
+ }
+ if (argc != 1) {
+ rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
+ }
+ VALUE hash_args = argv[0];
+ if (TYPE(hash_args) != T_HASH) {
+ rb_raise(rb_eArgError, "Expected hash arguments.");
+ }
+
+ rb_hash_foreach(hash_args, Message_initialize_kwarg, _self);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Message.dup => new_message
+ *
+ * Performs a shallow copy of this message and returns the new copy.
+ */
+VALUE Message_dup(VALUE _self) {
+ MessageHeader* self;
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+ VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
+ MessageHeader* new_msg_self;
+ TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
+
+ layout_dup(self->descriptor->layout,
+ Message_data(new_msg_self),
+ Message_data(self));
+
+ return new_msg;
+}
+
+// Internal only; used by Google::Protobuf.deep_copy.
+VALUE Message_deep_copy(VALUE _self) {
+ MessageHeader* self;
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+ VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
+ MessageHeader* new_msg_self;
+ TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
+
+ layout_deep_copy(self->descriptor->layout,
+ Message_data(new_msg_self),
+ Message_data(self));
+
+ return new_msg;
+}
+
+/*
+ * call-seq:
+ * Message.==(other) => boolean
+ *
+ * Performs a deep comparison of this message with another. Messages are equal
+ * if they have the same type and if each field is equal according to the :==
+ * method's semantics (a more efficient comparison may actually be done if the
+ * field is of a primitive type).
+ */
+VALUE Message_eq(VALUE _self, VALUE _other) {
+ MessageHeader* self;
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+ MessageHeader* other;
+ TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
+
+ if (self->descriptor != other->descriptor) {
+ return Qfalse;
+ }
+
+ return layout_eq(self->descriptor->layout,
+ Message_data(self),
+ Message_data(other));
+}
+
+/*
+ * call-seq:
+ * Message.hash => hash_value
+ *
+ * Returns a hash value that represents this message's field values.
+ */
+VALUE Message_hash(VALUE _self) {
+ MessageHeader* self;
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+ return layout_hash(self->descriptor->layout, Message_data(self));
+}
+
+/*
+ * call-seq:
+ * Message.inspect => string
+ *
+ * Returns a human-readable string representing this message. It will be
+ * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
+ * field's value is represented according to its own #inspect method.
+ */
+VALUE Message_inspect(VALUE _self) {
+ MessageHeader* self;
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+ VALUE str = rb_str_new2("<");
+ str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self))));
+ str = rb_str_cat2(str, ": ");
+ str = rb_str_append(str, layout_inspect(
+ self->descriptor->layout, Message_data(self)));
+ str = rb_str_cat2(str, ">");
+ return str;
+}
+
+/*
+ * call-seq:
+ * Message.[](index) => value
+ *
+ * Accesses a field's value by field name. The provided field name should be a
+ * string.
+ */
+VALUE Message_index(VALUE _self, VALUE field_name) {
+ MessageHeader* self;
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+ Check_Type(field_name, T_STRING);
+ const upb_fielddef* field =
+ upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
+ if (field == NULL) {
+ return Qnil;
+ }
+ return layout_get(self->descriptor->layout, Message_data(self), field);
+}
+
+/*
+ * call-seq:
+ * Message.[]=(index, value)
+ *
+ * Sets a field's value by field name. The provided field name should be a
+ * string.
+ */
+VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
+ MessageHeader* self;
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+ Check_Type(field_name, T_STRING);
+ const upb_fielddef* field =
+ upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
+ if (field == NULL) {
+ rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
+ }
+ layout_set(self->descriptor->layout, Message_data(self), field, value);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Message.descriptor => descriptor
+ *
+ * Class method that returns the Descriptor instance corresponding to this
+ * message class's type.
+ */
+VALUE Message_descriptor(VALUE klass) {
+ return rb_iv_get(klass, kDescriptorInstanceVar);
+}
+
+VALUE build_class_from_descriptor(Descriptor* desc) {
+ if (desc->layout == NULL) {
+ desc->layout = create_layout(desc->msgdef);
+ }
+ if (desc->fill_method == NULL) {
+ desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
+ }
+
+ const char* name = upb_msgdef_fullname(desc->msgdef);
+ if (name == NULL) {
+ rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
+ }
+
+ VALUE klass = rb_define_class_id(
+ // Docs say this parameter is ignored. User will assign return value to
+ // their own toplevel constant class name.
+ rb_intern("Message"),
+ rb_cObject);
+ rb_iv_set(klass, kDescriptorInstanceVar, get_def_obj(desc->msgdef));
+ rb_define_alloc_func(klass, Message_alloc);
+ rb_define_method(klass, "method_missing",
+ Message_method_missing, -1);
+ rb_define_method(klass, "initialize", Message_initialize, -1);
+ rb_define_method(klass, "dup", Message_dup, 0);
+ // Also define #clone so that we don't inherit Object#clone.
+ rb_define_method(klass, "clone", Message_dup, 0);
+ rb_define_method(klass, "==", Message_eq, 1);
+ rb_define_method(klass, "hash", Message_hash, 0);
+ rb_define_method(klass, "inspect", Message_inspect, 0);
+ rb_define_method(klass, "[]", Message_index, 1);
+ rb_define_method(klass, "[]=", Message_index_set, 2);
+ rb_define_singleton_method(klass, "decode", Message_decode, 1);
+ rb_define_singleton_method(klass, "encode", Message_encode, 1);
+ rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1);
+ rb_define_singleton_method(klass, "encode_json", Message_encode_json, 1);
+ rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
+ return klass;
+}
+
+/*
+ * call-seq:
+ * Enum.lookup(number) => name
+ *
+ * This module method, provided on each generated enum module, looks up an enum
+ * value by number and returns its name as a Ruby symbol, or nil if not found.
+ */
+VALUE enum_lookup(VALUE self, VALUE number) {
+ int32_t num = NUM2INT(number);
+ VALUE desc = rb_iv_get(self, kDescriptorInstanceVar);
+ EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
+
+ const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
+ if (name == NULL) {
+ return Qnil;
+ } else {
+ return ID2SYM(rb_intern(name));
+ }
+}
+
+/*
+ * call-seq:
+ * Enum.resolve(name) => number
+ *
+ * This module method, provided on each generated enum module, looks up an enum
+ * value by name (as a Ruby symbol) and returns its name, or nil if not found.
+ */
+VALUE enum_resolve(VALUE self, VALUE sym) {
+ const char* name = rb_id2name(SYM2ID(sym));
+ VALUE desc = rb_iv_get(self, kDescriptorInstanceVar);
+ EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
+
+ int32_t num = 0;
+ bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num);
+ if (!found) {
+ return Qnil;
+ } else {
+ return INT2NUM(num);
+ }
+}
+
+/*
+ * call-seq:
+ * Enum.descriptor
+ *
+ * This module method, provided on each generated enum module, returns the
+ * EnumDescriptor corresponding to this enum type.
+ */
+VALUE enum_descriptor(VALUE self) {
+ return rb_iv_get(self, kDescriptorInstanceVar);
+}
+
+VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
+ VALUE mod = rb_define_module_id(
+ rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
+
+ upb_enum_iter it;
+ for (upb_enum_begin(&it, enumdesc->enumdef);
+ !upb_enum_done(&it);
+ upb_enum_next(&it)) {
+ const char* name = upb_enum_iter_name(&it);
+ int32_t value = upb_enum_iter_number(&it);
+ if (name[0] < 'A' || name[0] > 'Z') {
+ rb_raise(rb_eTypeError,
+ "Enum value '%s' does not start with an uppercase letter "
+ "as is required for Ruby constants.",
+ name);
+ }
+ rb_define_const(mod, name, INT2NUM(value));
+ }
+
+ rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
+ rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
+ rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
+ rb_iv_set(mod, kDescriptorInstanceVar, get_def_obj(enumdesc->enumdef));
+
+ return mod;
+}
+
+/*
+ * call-seq:
+ * Google::Protobuf.deep_copy(obj) => copy_of_obj
+ *
+ * Performs a deep copy of a RepeatedField instance, a Map instance, or a
+ * message object, recursively copying its members.
+ */
+VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
+ VALUE klass = CLASS_OF(obj);
+ if (klass == cRepeatedField) {
+ return RepeatedField_deep_copy(obj);
+ } else if (klass == cMap) {
+ return Map_deep_copy(obj);
+ } else {
+ return Message_deep_copy(obj);
+ }
+}
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
new file mode 100644
index 00000000..d2d35033
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -0,0 +1,105 @@
+// 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
+// instances.
+// -----------------------------------------------------------------------------
+
+// This is a hash table from def objects (encoded by converting pointers to
+// Ruby integers) to MessageDef/EnumDef instances (as Ruby values).
+VALUE upb_def_to_ruby_obj_map;
+
+void add_def_obj(const void* def, VALUE value) {
+ rb_hash_aset(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def), value);
+}
+
+VALUE get_def_obj(const void* def) {
+ return rb_hash_aref(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def));
+}
+
+// -----------------------------------------------------------------------------
+// Utilities.
+// -----------------------------------------------------------------------------
+
+// Raises a Ruby error if |status| is not OK, using its error message.
+void check_upb_status(const upb_status* status, const char* msg) {
+ if (!upb_ok(status)) {
+ rb_raise(rb_eRuntimeError, "%s: %s\n", msg, upb_status_errmsg(status));
+ }
+}
+
+// String encodings: we look these up once, at load time, and then cache them
+// here.
+rb_encoding* kRubyStringUtf8Encoding;
+rb_encoding* kRubyStringASCIIEncoding;
+rb_encoding* kRubyString8bitEncoding;
+
+// -----------------------------------------------------------------------------
+// Initialization/entry point.
+// -----------------------------------------------------------------------------
+
+// This must be named "Init_protobuf_c" because the Ruby module is named
+// "protobuf_c" -- the VM looks for this symbol in our .so.
+void Init_protobuf_c() {
+ VALUE google = rb_define_module("Google");
+ VALUE protobuf = rb_define_module_under(google, "Protobuf");
+ VALUE internal = rb_define_module_under(protobuf, "Internal");
+ DescriptorPool_register(protobuf);
+ Descriptor_register(protobuf);
+ FieldDescriptor_register(protobuf);
+ OneofDescriptor_register(protobuf);
+ EnumDescriptor_register(protobuf);
+ MessageBuilderContext_register(internal);
+ OneofBuilderContext_register(internal);
+ EnumBuilderContext_register(internal);
+ Builder_register(internal);
+ RepeatedField_register(protobuf);
+ Map_register(protobuf);
+
+ rb_define_singleton_method(protobuf, "encode", Google_Protobuf_encode, 1);
+ rb_define_singleton_method(protobuf, "decode", Google_Protobuf_decode, 2);
+ rb_define_singleton_method(protobuf, "encode_json",
+ Google_Protobuf_encode_json, 1);
+ rb_define_singleton_method(protobuf, "decode_json",
+ Google_Protobuf_decode_json, 2);
+
+ rb_define_singleton_method(protobuf, "deep_copy",
+ Google_Protobuf_deep_copy, 1);
+
+ kRubyStringUtf8Encoding = rb_utf8_encoding();
+ kRubyStringASCIIEncoding = rb_usascii_encoding();
+ kRubyString8bitEncoding = rb_ascii8bit_encoding();
+
+ upb_def_to_ruby_obj_map = rb_hash_new();
+ rb_gc_register_address(&upb_def_to_ruby_obj_map);
+}
diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h
new file mode 100644
index 00000000..d8a327aa
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/protobuf.h
@@ -0,0 +1,533 @@
+// 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_RUBY_PROTOBUF_H__
+#define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
+
+#include <ruby/ruby.h>
+#include <ruby/vm.h>
+#include <ruby/encoding.h>
+
+#include "upb.h"
+
+// Forward decls.
+struct DescriptorPool;
+struct Descriptor;
+struct FieldDescriptor;
+struct EnumDescriptor;
+struct MessageLayout;
+struct MessageField;
+struct MessageHeader;
+struct MessageBuilderContext;
+struct EnumBuilderContext;
+struct Builder;
+
+typedef struct DescriptorPool DescriptorPool;
+typedef struct Descriptor Descriptor;
+typedef struct FieldDescriptor FieldDescriptor;
+typedef struct OneofDescriptor OneofDescriptor;
+typedef struct EnumDescriptor EnumDescriptor;
+typedef struct MessageLayout MessageLayout;
+typedef struct MessageField MessageField;
+typedef struct MessageHeader MessageHeader;
+typedef struct MessageBuilderContext MessageBuilderContext;
+typedef struct OneofBuilderContext OneofBuilderContext;
+typedef struct EnumBuilderContext EnumBuilderContext;
+typedef struct Builder Builder;
+
+/*
+ It can be a bit confusing how the C structs defined below and the Ruby
+ objects interact and hold references to each other. First, a few principles:
+
+ - Ruby's "TypedData" abstraction lets a Ruby VALUE hold a pointer to a C
+ struct (or arbitrary memory chunk), own it, and free it when collected.
+ Thus, each struct below will have a corresponding Ruby object
+ wrapping/owning it.
+
+ - To get back from an underlying upb {msg,enum}def to the Ruby object, we
+ keep a global hashmap, accessed by get_def_obj/add_def_obj below.
+
+ The in-memory structure is then something like:
+
+ Ruby | upb
+ |
+ DescriptorPool ------------|-----------> upb_symtab____________________
+ | | (message types) \
+ | v \
+ Descriptor ---------------|-----------> upb_msgdef (enum types)|
+ |--> msgclass | | ^ |
+ | (dynamically built) | | | (submsg fields) |
+ |--> MessageLayout | | | /
+ |--------------------------|> decoder method| | /
+ \--------------------------|> serialize | | /
+ | handlers v | /
+ FieldDescriptor -----------|-----------> upb_fielddef /
+ | | /
+ | v (enum fields) /
+ EnumDescriptor ------------|-----------> upb_enumdef <----------'
+ |
+ |
+ ^ | \___/
+ `---------------|-----------------' (get_def_obj map)
+ */
+
+// -----------------------------------------------------------------------------
+// Ruby class structure definitions.
+// -----------------------------------------------------------------------------
+
+struct DescriptorPool {
+ upb_symtab* symtab;
+};
+
+struct Descriptor {
+ const upb_msgdef* msgdef;
+ MessageLayout* layout;
+ VALUE klass; // begins as nil
+ const upb_handlers* fill_handlers;
+ const upb_pbdecodermethod* fill_method;
+ const upb_handlers* pb_serialize_handlers;
+ const upb_handlers* json_serialize_handlers;
+ // Handlers hold type class references for sub-message fields directly in some
+ // cases. We need to keep these rooted because they might otherwise be
+ // collected.
+ VALUE typeclass_references;
+};
+
+struct FieldDescriptor {
+ const upb_fielddef* fielddef;
+};
+
+struct OneofDescriptor {
+ const upb_oneofdef* oneofdef;
+};
+
+struct EnumDescriptor {
+ const upb_enumdef* enumdef;
+ VALUE module; // begins as nil
+};
+
+struct MessageBuilderContext {
+ VALUE descriptor;
+ VALUE builder;
+};
+
+struct OneofBuilderContext {
+ VALUE descriptor;
+ VALUE builder;
+};
+
+struct EnumBuilderContext {
+ VALUE enumdesc;
+};
+
+struct Builder {
+ VALUE pending_list;
+ upb_def** defs; // used only while finalizing
+};
+
+extern VALUE cDescriptorPool;
+extern VALUE cDescriptor;
+extern VALUE cFieldDescriptor;
+extern VALUE cEnumDescriptor;
+extern VALUE cMessageBuilderContext;
+extern VALUE cOneofBuilderContext;
+extern VALUE cEnumBuilderContext;
+extern VALUE cBuilder;
+
+extern const char* kDescriptorInstanceVar;
+
+// We forward-declare all of the Ruby method implementations here because we
+// sometimes call the methods directly across .c files, rather than going
+// through Ruby's method dispatching (e.g. during message parse). It's cleaner
+// to keep the list of object methods together than to split them between
+// static-in-file definitions and header declarations.
+
+void DescriptorPool_mark(void* _self);
+void DescriptorPool_free(void* _self);
+VALUE DescriptorPool_alloc(VALUE klass);
+void DescriptorPool_register(VALUE module);
+DescriptorPool* ruby_to_DescriptorPool(VALUE value);
+VALUE DescriptorPool_add(VALUE _self, VALUE def);
+VALUE DescriptorPool_build(VALUE _self);
+VALUE DescriptorPool_lookup(VALUE _self, VALUE name);
+VALUE DescriptorPool_generated_pool(VALUE _self);
+
+void Descriptor_mark(void* _self);
+void Descriptor_free(void* _self);
+VALUE Descriptor_alloc(VALUE klass);
+void Descriptor_register(VALUE module);
+Descriptor* ruby_to_Descriptor(VALUE value);
+VALUE Descriptor_name(VALUE _self);
+VALUE Descriptor_name_set(VALUE _self, VALUE str);
+VALUE Descriptor_each(VALUE _self);
+VALUE Descriptor_lookup(VALUE _self, VALUE name);
+VALUE Descriptor_add_field(VALUE _self, VALUE obj);
+VALUE Descriptor_add_oneof(VALUE _self, VALUE obj);
+VALUE Descriptor_each_oneof(VALUE _self);
+VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name);
+VALUE Descriptor_msgclass(VALUE _self);
+extern const rb_data_type_t _Descriptor_type;
+
+void FieldDescriptor_mark(void* _self);
+void FieldDescriptor_free(void* _self);
+VALUE FieldDescriptor_alloc(VALUE klass);
+void FieldDescriptor_register(VALUE module);
+FieldDescriptor* ruby_to_FieldDescriptor(VALUE value);
+VALUE FieldDescriptor_name(VALUE _self);
+VALUE FieldDescriptor_name_set(VALUE _self, VALUE str);
+VALUE FieldDescriptor_type(VALUE _self);
+VALUE FieldDescriptor_type_set(VALUE _self, VALUE type);
+VALUE FieldDescriptor_label(VALUE _self);
+VALUE FieldDescriptor_label_set(VALUE _self, VALUE label);
+VALUE FieldDescriptor_number(VALUE _self);
+VALUE FieldDescriptor_number_set(VALUE _self, VALUE number);
+VALUE FieldDescriptor_submsg_name(VALUE _self);
+VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value);
+VALUE FieldDescriptor_subtype(VALUE _self);
+VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb);
+VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value);
+upb_fieldtype_t ruby_to_fieldtype(VALUE type);
+VALUE fieldtype_to_ruby(upb_fieldtype_t type);
+
+void OneofDescriptor_mark(void* _self);
+void OneofDescriptor_free(void* _self);
+VALUE OneofDescriptor_alloc(VALUE klass);
+void OneofDescriptor_register(VALUE module);
+OneofDescriptor* ruby_to_OneofDescriptor(VALUE value);
+VALUE OneofDescriptor_name(VALUE _self);
+VALUE OneofDescriptor_name_set(VALUE _self, VALUE value);
+VALUE OneofDescriptor_add_field(VALUE _self, VALUE field);
+VALUE OneofDescriptor_each(VALUE _self, VALUE field);
+
+void EnumDescriptor_mark(void* _self);
+void EnumDescriptor_free(void* _self);
+VALUE EnumDescriptor_alloc(VALUE klass);
+void EnumDescriptor_register(VALUE module);
+EnumDescriptor* ruby_to_EnumDescriptor(VALUE value);
+VALUE EnumDescriptor_name(VALUE _self);
+VALUE EnumDescriptor_name_set(VALUE _self, VALUE str);
+VALUE EnumDescriptor_add_value(VALUE _self, VALUE name, VALUE number);
+VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name);
+VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number);
+VALUE EnumDescriptor_each(VALUE _self);
+VALUE EnumDescriptor_enummodule(VALUE _self);
+extern const rb_data_type_t _EnumDescriptor_type;
+
+void MessageBuilderContext_mark(void* _self);
+void MessageBuilderContext_free(void* _self);
+VALUE MessageBuilderContext_alloc(VALUE klass);
+void MessageBuilderContext_register(VALUE module);
+MessageBuilderContext* ruby_to_MessageBuilderContext(VALUE value);
+VALUE MessageBuilderContext_initialize(VALUE _self,
+ VALUE descriptor,
+ VALUE builder);
+VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self);
+VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self);
+VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self);
+VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self);
+VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name);
+
+void OneofBuilderContext_mark(void* _self);
+void OneofBuilderContext_free(void* _self);
+VALUE OneofBuilderContext_alloc(VALUE klass);
+void OneofBuilderContext_register(VALUE module);
+OneofBuilderContext* ruby_to_OneofBuilderContext(VALUE value);
+VALUE OneofBuilderContext_initialize(VALUE _self,
+ VALUE descriptor,
+ VALUE builder);
+VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self);
+
+void EnumBuilderContext_mark(void* _self);
+void EnumBuilderContext_free(void* _self);
+VALUE EnumBuilderContext_alloc(VALUE klass);
+void EnumBuilderContext_register(VALUE module);
+EnumBuilderContext* ruby_to_EnumBuilderContext(VALUE value);
+VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdesc);
+VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number);
+
+void Builder_mark(void* _self);
+void Builder_free(void* _self);
+VALUE Builder_alloc(VALUE klass);
+void Builder_register(VALUE module);
+Builder* ruby_to_Builder(VALUE value);
+VALUE Builder_add_message(VALUE _self, VALUE name);
+VALUE Builder_add_enum(VALUE _self, VALUE name);
+VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb);
+
+// -----------------------------------------------------------------------------
+// Native slot storage abstraction.
+// -----------------------------------------------------------------------------
+
+#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t)
+
+size_t native_slot_size(upb_fieldtype_t type);
+void native_slot_set(upb_fieldtype_t type,
+ VALUE type_class,
+ void* memory,
+ VALUE value);
+// Atomically (with respect to Ruby VM calls) either update the value and set a
+// oneof case, or do neither. If |case_memory| is null, then no case value is
+// set.
+void native_slot_set_value_and_case(upb_fieldtype_t type,
+ VALUE type_class,
+ void* memory,
+ VALUE value,
+ uint32_t* case_memory,
+ uint32_t case_number);
+VALUE native_slot_get(upb_fieldtype_t type,
+ VALUE type_class,
+ const void* memory);
+void native_slot_init(upb_fieldtype_t type, void* memory);
+void native_slot_mark(upb_fieldtype_t type, void* memory);
+void native_slot_dup(upb_fieldtype_t type, void* to, void* from);
+void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from);
+bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2);
+
+void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value);
+void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE value);
+
+extern rb_encoding* kRubyStringUtf8Encoding;
+extern rb_encoding* kRubyStringASCIIEncoding;
+extern rb_encoding* kRubyString8bitEncoding;
+
+VALUE field_type_class(const upb_fielddef* field);
+
+#define MAP_KEY_FIELD 1
+#define MAP_VALUE_FIELD 2
+
+// Oneof case slot value to indicate that no oneof case is set. The value `0` is
+// safe because field numbers are used as case identifiers, and no field can
+// have a number of 0.
+#define ONEOF_CASE_NONE 0
+
+// These operate on a map field (i.e., a repeated field of submessages whose
+// submessage type is a map-entry msgdef).
+bool is_map_field(const upb_fielddef* field);
+const upb_fielddef* map_field_key(const upb_fielddef* field);
+const upb_fielddef* map_field_value(const upb_fielddef* field);
+
+// These operate on a map-entry msgdef.
+const upb_fielddef* map_entry_key(const upb_msgdef* msgdef);
+const upb_fielddef* map_entry_value(const upb_msgdef* msgdef);
+
+// -----------------------------------------------------------------------------
+// Repeated field container type.
+// -----------------------------------------------------------------------------
+
+typedef struct {
+ upb_fieldtype_t field_type;
+ VALUE field_type_class;
+ void* elements;
+ int size;
+ int capacity;
+} RepeatedField;
+
+void RepeatedField_mark(void* self);
+void RepeatedField_free(void* self);
+VALUE RepeatedField_alloc(VALUE klass);
+VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self);
+void RepeatedField_register(VALUE module);
+
+extern const rb_data_type_t RepeatedField_type;
+extern VALUE cRepeatedField;
+
+RepeatedField* ruby_to_RepeatedField(VALUE value);
+
+VALUE RepeatedField_each(VALUE _self);
+VALUE RepeatedField_index(VALUE _self, VALUE _index);
+void* RepeatedField_index_native(VALUE _self, int index);
+VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val);
+void RepeatedField_reserve(RepeatedField* self, int new_size);
+VALUE RepeatedField_push(VALUE _self, VALUE val);
+void RepeatedField_push_native(VALUE _self, void* data);
+VALUE RepeatedField_pop(VALUE _self);
+VALUE RepeatedField_insert(int argc, VALUE* argv, VALUE _self);
+VALUE RepeatedField_replace(VALUE _self, VALUE list);
+VALUE RepeatedField_clear(VALUE _self);
+VALUE RepeatedField_length(VALUE _self);
+VALUE RepeatedField_dup(VALUE _self);
+VALUE RepeatedField_deep_copy(VALUE _self);
+VALUE RepeatedField_eq(VALUE _self, VALUE _other);
+VALUE RepeatedField_hash(VALUE _self);
+VALUE RepeatedField_inspect(VALUE _self);
+VALUE RepeatedField_plus(VALUE _self, VALUE list);
+
+// Defined in repeated_field.c; also used by Map.
+void validate_type_class(upb_fieldtype_t type, VALUE klass);
+
+// -----------------------------------------------------------------------------
+// Map container type.
+// -----------------------------------------------------------------------------
+
+typedef struct {
+ upb_fieldtype_t key_type;
+ upb_fieldtype_t value_type;
+ VALUE value_type_class;
+ upb_strtable table;
+} Map;
+
+void Map_mark(void* self);
+void Map_free(void* self);
+VALUE Map_alloc(VALUE klass);
+VALUE Map_init(int argc, VALUE* argv, VALUE self);
+void Map_register(VALUE module);
+
+extern const rb_data_type_t Map_type;
+extern VALUE cMap;
+
+Map* ruby_to_Map(VALUE value);
+
+VALUE Map_each(VALUE _self);
+VALUE Map_keys(VALUE _self);
+VALUE Map_values(VALUE _self);
+VALUE Map_index(VALUE _self, VALUE key);
+VALUE Map_index_set(VALUE _self, VALUE key, VALUE value);
+VALUE Map_has_key(VALUE _self, VALUE key);
+VALUE Map_delete(VALUE _self, VALUE key);
+VALUE Map_clear(VALUE _self);
+VALUE Map_length(VALUE _self);
+VALUE Map_dup(VALUE _self);
+VALUE Map_deep_copy(VALUE _self);
+VALUE Map_eq(VALUE _self, VALUE _other);
+VALUE Map_hash(VALUE _self);
+VALUE Map_inspect(VALUE _self);
+VALUE Map_merge(VALUE _self, VALUE hashmap);
+VALUE Map_merge_into_self(VALUE _self, VALUE hashmap);
+
+typedef struct {
+ Map* self;
+ upb_strtable_iter it;
+} Map_iter;
+
+void Map_begin(VALUE _self, Map_iter* iter);
+void Map_next(Map_iter* iter);
+bool Map_done(Map_iter* iter);
+VALUE Map_iter_key(Map_iter* iter);
+VALUE Map_iter_value(Map_iter* iter);
+
+// -----------------------------------------------------------------------------
+// Message layout / storage.
+// -----------------------------------------------------------------------------
+
+#define MESSAGE_FIELD_NO_CASE ((size_t)-1)
+
+struct MessageField {
+ size_t offset;
+ size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE.
+};
+
+struct MessageLayout {
+ const upb_msgdef* msgdef;
+ MessageField* fields;
+ size_t size;
+};
+
+MessageLayout* create_layout(const upb_msgdef* msgdef);
+void free_layout(MessageLayout* layout);
+VALUE layout_get(MessageLayout* layout,
+ const void* storage,
+ const upb_fielddef* field);
+void layout_set(MessageLayout* layout,
+ void* storage,
+ const upb_fielddef* field,
+ VALUE val);
+void layout_init(MessageLayout* layout, void* storage);
+void layout_mark(MessageLayout* layout, void* storage);
+void layout_dup(MessageLayout* layout, void* to, void* from);
+void layout_deep_copy(MessageLayout* layout, void* to, void* from);
+VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2);
+VALUE layout_hash(MessageLayout* layout, void* storage);
+VALUE layout_inspect(MessageLayout* layout, void* storage);
+
+// -----------------------------------------------------------------------------
+// Message class creation.
+// -----------------------------------------------------------------------------
+
+struct MessageHeader {
+ Descriptor* descriptor; // kept alive by self.class.descriptor reference.
+ // Data comes after this.
+};
+
+extern rb_data_type_t Message_type;
+
+VALUE build_class_from_descriptor(Descriptor* descriptor);
+void* Message_data(void* msg);
+void Message_mark(void* self);
+void Message_free(void* self);
+VALUE Message_alloc(VALUE klass);
+VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self);
+VALUE Message_initialize(int argc, VALUE* argv, VALUE _self);
+VALUE Message_dup(VALUE _self);
+VALUE Message_deep_copy(VALUE _self);
+VALUE Message_eq(VALUE _self, VALUE _other);
+VALUE Message_hash(VALUE _self);
+VALUE Message_inspect(VALUE _self);
+VALUE Message_index(VALUE _self, VALUE field_name);
+VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value);
+VALUE Message_descriptor(VALUE klass);
+VALUE Message_decode(VALUE klass, VALUE data);
+VALUE Message_encode(VALUE klass, VALUE msg_rb);
+VALUE Message_decode_json(VALUE klass, VALUE data);
+VALUE Message_encode_json(VALUE klass, VALUE msg_rb);
+
+VALUE Google_Protobuf_encode(VALUE self, VALUE msg_rb);
+VALUE Google_Protobuf_decode(VALUE self, VALUE klass, VALUE msg_rb);
+VALUE Google_Protobuf_encode_json(VALUE self, VALUE msg_rb);
+VALUE Google_Protobuf_decode_json(VALUE self, VALUE klass, VALUE msg_rb);
+
+VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj);
+
+VALUE build_module_from_enumdesc(EnumDescriptor* enumdef);
+VALUE enum_lookup(VALUE self, VALUE number);
+VALUE enum_resolve(VALUE self, VALUE sym);
+
+const upb_pbdecodermethod *new_fillmsg_decodermethod(
+ Descriptor* descriptor, const void *owner);
+
+// -----------------------------------------------------------------------------
+// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
+// instances.
+// -----------------------------------------------------------------------------
+void add_def_obj(const void* def, VALUE value);
+VALUE get_def_obj(const void* def);
+
+// -----------------------------------------------------------------------------
+// Utilities.
+// -----------------------------------------------------------------------------
+
+void check_upb_status(const upb_status* status, const char* msg);
+
+#define CHECK_UPB(code, msg) do { \
+ upb_status status = UPB_STATUS_INIT; \
+ code; \
+ check_upb_status(&status, msg); \
+} while (0)
+
+#endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c
new file mode 100644
index 00000000..8cf2e29b
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/repeated_field.c
@@ -0,0 +1,598 @@
+// 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Repeated field container type.
+// -----------------------------------------------------------------------------
+
+const rb_data_type_t RepeatedField_type = {
+ "Google::Protobuf::RepeatedField",
+ { RepeatedField_mark, RepeatedField_free, NULL },
+};
+
+VALUE cRepeatedField;
+
+RepeatedField* ruby_to_RepeatedField(VALUE _self) {
+ RepeatedField* self;
+ TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self);
+ return self;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.each(&block)
+ *
+ * Invokes the block once for each element of the repeated field. RepeatedField
+ * also includes Enumerable; combined with this method, the repeated field thus
+ * acts like an ordinary Ruby sequence.
+ */
+VALUE RepeatedField_each(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ upb_fieldtype_t field_type = self->field_type;
+ VALUE field_type_class = self->field_type_class;
+ int element_size = native_slot_size(field_type);
+
+ size_t off = 0;
+ for (int i = 0; i < self->size; i++, off += element_size) {
+ void* memory = (void *) (((uint8_t *)self->elements) + off);
+ VALUE val = native_slot_get(field_type, field_type_class, memory);
+ rb_yield(val);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.[](index) => value
+ *
+ * Accesses the element at the given index. Throws an exception on out-of-bounds
+ * errors.
+ */
+VALUE RepeatedField_index(VALUE _self, VALUE _index) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ int element_size = native_slot_size(self->field_type);
+ upb_fieldtype_t field_type = self->field_type;
+ VALUE field_type_class = self->field_type_class;
+
+ int index = NUM2INT(_index);
+ if (index < 0 || index >= self->size) {
+ rb_raise(rb_eRangeError, "Index out of range");
+ }
+
+ void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
+ return native_slot_get(field_type, field_type_class, memory);
+}
+
+/*
+ * call-seq:
+ * RepeatedField.[]=(index, value)
+ *
+ * Sets the element at the given index. On out-of-bounds assignments, extends
+ * the array and fills the hole (if any) with default values.
+ */
+VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ upb_fieldtype_t field_type = self->field_type;
+ VALUE field_type_class = self->field_type_class;
+ int element_size = native_slot_size(field_type);
+
+ int index = NUM2INT(_index);
+ if (index < 0 || index >= (INT_MAX - 1)) {
+ rb_raise(rb_eRangeError, "Index out of range");
+ }
+ if (index >= self->size) {
+ RepeatedField_reserve(self, index + 1);
+ upb_fieldtype_t field_type = self->field_type;
+ int element_size = native_slot_size(field_type);
+ for (int i = self->size; i <= index; i++) {
+ void* elem = (void *)(((uint8_t *)self->elements) + i * element_size);
+ native_slot_init(field_type, elem);
+ }
+ self->size = index + 1;
+ }
+
+ void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
+ native_slot_set(field_type, field_type_class, memory, val);
+ return Qnil;
+}
+
+static int kInitialSize = 8;
+
+void RepeatedField_reserve(RepeatedField* self, int new_size) {
+ if (new_size <= self->capacity) {
+ return;
+ }
+ if (self->capacity == 0) {
+ self->capacity = kInitialSize;
+ }
+ while (self->capacity < new_size) {
+ self->capacity *= 2;
+ }
+ void* old_elems = self->elements;
+ int elem_size = native_slot_size(self->field_type);
+ self->elements = ALLOC_N(uint8_t, elem_size * self->capacity);
+ if (old_elems != NULL) {
+ memcpy(self->elements, old_elems, self->size * elem_size);
+ xfree(old_elems);
+ }
+}
+
+/*
+ * call-seq:
+ * RepeatedField.push(value)
+ *
+ * Adds a new element to the repeated field.
+ */
+VALUE RepeatedField_push(VALUE _self, VALUE val) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ upb_fieldtype_t field_type = self->field_type;
+ int element_size = native_slot_size(field_type);
+ RepeatedField_reserve(self, self->size + 1);
+ int index = self->size;
+ void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
+ native_slot_set(field_type, self->field_type_class, memory, val);
+ // native_slot_set may raise an error; bump index only after set.
+ self->size++;
+ return _self;
+}
+
+// Used by parsing handlers.
+void RepeatedField_push_native(VALUE _self, void* data) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ upb_fieldtype_t field_type = self->field_type;
+ int element_size = native_slot_size(field_type);
+ RepeatedField_reserve(self, self->size + 1);
+ int index = self->size;
+ void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
+ memcpy(memory, data, element_size);
+ self->size++;
+}
+
+void* RepeatedField_index_native(VALUE _self, int index) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ upb_fieldtype_t field_type = self->field_type;
+ int element_size = native_slot_size(field_type);
+ return ((uint8_t *)self->elements) + index * element_size;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.pop => value
+ *
+ * Removes the last element and returns it. Throws an exception if the repeated
+ * field is empty.
+ */
+VALUE RepeatedField_pop(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ upb_fieldtype_t field_type = self->field_type;
+ VALUE field_type_class = self->field_type_class;
+ int element_size = native_slot_size(field_type);
+ if (self->size == 0) {
+ rb_raise(rb_eRangeError, "Pop from empty repeated field is not allowed.");
+ }
+ int index = self->size - 1;
+ void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
+ VALUE ret = native_slot_get(field_type, field_type_class, memory);
+ self->size--;
+ return ret;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.insert(*args)
+ *
+ * Pushes each arg in turn onto the end of the repeated field.
+ */
+VALUE RepeatedField_insert(int argc, VALUE* argv, VALUE _self) {
+ for (int i = 0; i < argc; i++) {
+ RepeatedField_push(_self, argv[i]);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.replace(list)
+ *
+ * Replaces the contents of the repeated field with the given list of elements.
+ */
+VALUE RepeatedField_replace(VALUE _self, VALUE list) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ Check_Type(list, T_ARRAY);
+ self->size = 0;
+ for (int i = 0; i < RARRAY_LEN(list); i++) {
+ RepeatedField_push(_self, rb_ary_entry(list, i));
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.clear
+ *
+ * Clears (removes all elements from) this repeated field.
+ */
+VALUE RepeatedField_clear(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ self->size = 0;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.length
+ *
+ * Returns the length of this repeated field.
+ */
+VALUE RepeatedField_length(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ return INT2NUM(self->size);
+}
+
+static VALUE RepeatedField_new_this_type(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ VALUE new_rptfield = Qnil;
+ VALUE element_type = fieldtype_to_ruby(self->field_type);
+ if (self->field_type_class != Qnil) {
+ new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
+ element_type, self->field_type_class);
+ } else {
+ new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 1,
+ element_type);
+ }
+ return new_rptfield;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.dup => repeated_field
+ *
+ * Duplicates this repeated field with a shallow copy. References to all
+ * non-primitive element objects (e.g., submessages) are shared.
+ */
+VALUE RepeatedField_dup(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ VALUE new_rptfield = RepeatedField_new_this_type(_self);
+ RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
+ RepeatedField_reserve(new_rptfield_self, self->size);
+ upb_fieldtype_t field_type = self->field_type;
+ size_t elem_size = native_slot_size(field_type);
+ size_t off = 0;
+ for (int i = 0; i < self->size; i++, off += elem_size) {
+ void* to_mem = (uint8_t *)new_rptfield_self->elements + off;
+ void* from_mem = (uint8_t *)self->elements + off;
+ native_slot_dup(field_type, to_mem, from_mem);
+ new_rptfield_self->size++;
+ }
+
+ return new_rptfield;
+}
+
+// Internal only: used by Google::Protobuf.deep_copy.
+VALUE RepeatedField_deep_copy(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ VALUE new_rptfield = RepeatedField_new_this_type(_self);
+ RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
+ RepeatedField_reserve(new_rptfield_self, self->size);
+ upb_fieldtype_t field_type = self->field_type;
+ size_t elem_size = native_slot_size(field_type);
+ size_t off = 0;
+ for (int i = 0; i < self->size; i++, off += elem_size) {
+ void* to_mem = (uint8_t *)new_rptfield_self->elements + off;
+ void* from_mem = (uint8_t *)self->elements + off;
+ native_slot_deep_copy(field_type, to_mem, from_mem);
+ new_rptfield_self->size++;
+ }
+
+ return new_rptfield;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.to_ary => array
+ *
+ * Used when converted implicitly into array, e.g. compared to an Array.
+ * Also called as a fallback of Object#to_a
+ */
+VALUE RepeatedField_to_ary(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ upb_fieldtype_t field_type = self->field_type;
+
+ size_t elem_size = native_slot_size(field_type);
+ size_t off = 0;
+ VALUE ary = rb_ary_new2(self->size);
+ for (int i = 0; i < self->size; i++, off += elem_size) {
+ void* mem = ((uint8_t *)self->elements) + off;
+ VALUE elem = native_slot_get(field_type, self->field_type_class, mem);
+
+ rb_ary_push(ary, elem);
+ }
+ return ary;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.==(other) => boolean
+ *
+ * Compares this repeated field to another. Repeated fields are equal if their
+ * element types are equal, their lengths are equal, and each element is equal.
+ * Elements are compared as per normal Ruby semantics, by calling their :==
+ * methods (or performing a more efficient comparison for primitive types).
+ *
+ * Repeated fields with dissimilar element types are never equal, even if value
+ * comparison (for example, between integers and floats) would have otherwise
+ * indicated that every element has equal value.
+ */
+VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
+ if (_self == _other) {
+ return Qtrue;
+ }
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+
+ if (TYPE(_other) == T_ARRAY) {
+ VALUE self_ary = RepeatedField_to_ary(_self);
+ return rb_equal(self_ary, _other);
+ }
+
+ RepeatedField* other = ruby_to_RepeatedField(_other);
+ if (self->field_type != other->field_type ||
+ self->field_type_class != other->field_type_class ||
+ self->size != other->size) {
+ return Qfalse;
+ }
+
+ upb_fieldtype_t field_type = self->field_type;
+ size_t elem_size = native_slot_size(field_type);
+ size_t off = 0;
+ for (int i = 0; i < self->size; i++, off += elem_size) {
+ void* self_mem = ((uint8_t *)self->elements) + off;
+ void* other_mem = ((uint8_t *)other->elements) + off;
+ if (!native_slot_eq(field_type, self_mem, other_mem)) {
+ return Qfalse;
+ }
+ }
+ return Qtrue;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.hash => hash_value
+ *
+ * Returns a hash value computed from this repeated field's elements.
+ */
+VALUE RepeatedField_hash(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+
+ VALUE hash = LL2NUM(0);
+
+ upb_fieldtype_t field_type = self->field_type;
+ VALUE field_type_class = self->field_type_class;
+ size_t elem_size = native_slot_size(field_type);
+ size_t off = 0;
+ for (int i = 0; i < self->size; i++, off += elem_size) {
+ void* mem = ((uint8_t *)self->elements) + off;
+ VALUE elem = native_slot_get(field_type, field_type_class, mem);
+ hash = rb_funcall(hash, rb_intern("<<"), 1, INT2NUM(2));
+ hash = rb_funcall(hash, rb_intern("^"), 1,
+ rb_funcall(elem, rb_intern("hash"), 0));
+ }
+
+ return hash;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.inspect => string
+ *
+ * Returns a string representing this repeated field's elements. It will be
+ * formated as "[<element>, <element>, ...]", with each element's string
+ * representation computed by its own #inspect method.
+ */
+VALUE RepeatedField_inspect(VALUE _self) {
+ VALUE self_ary = RepeatedField_to_ary(_self);
+ return rb_funcall(self_ary, rb_intern("inspect"), 0);
+}
+
+/*
+ * call-seq:
+ * RepeatedField.+(other) => repeated field
+ *
+ * Returns a new repeated field that contains the concatenated list of this
+ * repeated field's elements and other's elements. The other (second) list may
+ * be either another repeated field or a Ruby array.
+ */
+VALUE RepeatedField_plus(VALUE _self, VALUE list) {
+ VALUE dupped = RepeatedField_dup(_self);
+
+ if (TYPE(list) == T_ARRAY) {
+ for (int i = 0; i < RARRAY_LEN(list); i++) {
+ VALUE elem = rb_ary_entry(list, i);
+ RepeatedField_push(dupped, elem);
+ }
+ } else if (RB_TYPE_P(list, T_DATA) && RTYPEDDATA_P(list) &&
+ RTYPEDDATA_TYPE(list) == &RepeatedField_type) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ RepeatedField* list_rptfield = ruby_to_RepeatedField(list);
+ if (self->field_type != list_rptfield->field_type ||
+ self->field_type_class != list_rptfield->field_type_class) {
+ rb_raise(rb_eArgError,
+ "Attempt to append RepeatedField with different element type.");
+ }
+ for (int i = 0; i < list_rptfield->size; i++) {
+ void* mem = RepeatedField_index_native(list, i);
+ RepeatedField_push_native(dupped, mem);
+ }
+ } else {
+ rb_raise(rb_eArgError, "Unknown type appending to RepeatedField");
+ }
+
+ return dupped;
+}
+
+void validate_type_class(upb_fieldtype_t type, VALUE klass) {
+ if (rb_iv_get(klass, kDescriptorInstanceVar) == Qnil) {
+ rb_raise(rb_eArgError,
+ "Type class has no descriptor. Please pass a "
+ "class or enum as returned by the DescriptorPool.");
+ }
+ if (type == UPB_TYPE_MESSAGE) {
+ VALUE desc = rb_iv_get(klass, kDescriptorInstanceVar);
+ if (!RB_TYPE_P(desc, T_DATA) || !RTYPEDDATA_P(desc) ||
+ RTYPEDDATA_TYPE(desc) != &_Descriptor_type) {
+ rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
+ }
+ if (rb_get_alloc_func(klass) != &Message_alloc) {
+ rb_raise(rb_eArgError,
+ "Message class was not returned by the DescriptorPool.");
+ }
+ } else if (type == UPB_TYPE_ENUM) {
+ VALUE enumdesc = rb_iv_get(klass, kDescriptorInstanceVar);
+ if (!RB_TYPE_P(enumdesc, T_DATA) || !RTYPEDDATA_P(enumdesc) ||
+ RTYPEDDATA_TYPE(enumdesc) != &_EnumDescriptor_type) {
+ rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
+ }
+ }
+}
+
+void RepeatedField_init_args(int argc, VALUE* argv,
+ VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ VALUE ary = Qnil;
+ if (argc < 1) {
+ rb_raise(rb_eArgError, "Expected at least 1 argument.");
+ }
+ self->field_type = ruby_to_fieldtype(argv[0]);
+
+ if (self->field_type == UPB_TYPE_MESSAGE ||
+ self->field_type == UPB_TYPE_ENUM) {
+ if (argc < 2) {
+ rb_raise(rb_eArgError, "Expected at least 2 arguments for message/enum.");
+ }
+ self->field_type_class = argv[1];
+ if (argc > 2) {
+ ary = argv[2];
+ }
+ validate_type_class(self->field_type, self->field_type_class);
+ } else {
+ if (argc > 2) {
+ rb_raise(rb_eArgError, "Too many arguments: expected 1 or 2.");
+ }
+ if (argc > 1) {
+ ary = argv[1];
+ }
+ }
+
+ if (ary != Qnil) {
+ if (!RB_TYPE_P(ary, T_ARRAY)) {
+ rb_raise(rb_eArgError, "Expected array as initialize argument");
+ }
+ for (int i = 0; i < RARRAY_LEN(ary); i++) {
+ RepeatedField_push(_self, rb_ary_entry(ary, i));
+ }
+ }
+}
+
+// Mark, free, alloc, init and class setup functions.
+
+void RepeatedField_mark(void* _self) {
+ RepeatedField* self = (RepeatedField*)_self;
+ rb_gc_mark(self->field_type_class);
+ upb_fieldtype_t field_type = self->field_type;
+ int element_size = native_slot_size(field_type);
+ for (int i = 0; i < self->size; i++) {
+ void* memory = (((uint8_t *)self->elements) + i * element_size);
+ native_slot_mark(self->field_type, memory);
+ }
+}
+
+void RepeatedField_free(void* _self) {
+ RepeatedField* self = (RepeatedField*)_self;
+ xfree(self->elements);
+ xfree(self);
+}
+
+/*
+ * call-seq:
+ * RepeatedField.new(type, type_class = nil, initial_elems = [])
+ *
+ * Creates a new repeated field. The provided type must be a Ruby symbol, and
+ * can take on the same values as those accepted by FieldDescriptor#type=. If
+ * the type is :message or :enum, type_class must be non-nil, and must be the
+ * Ruby class or module returned by Descriptor#msgclass or
+ * EnumDescriptor#enummodule, respectively. An initial list of elements may also
+ * be provided.
+ */
+VALUE RepeatedField_alloc(VALUE klass) {
+ RepeatedField* self = ALLOC(RepeatedField);
+ self->elements = NULL;
+ self->size = 0;
+ self->capacity = 0;
+ self->field_type = -1;
+ self->field_type_class = Qnil;
+ VALUE ret = TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
+ return ret;
+}
+
+VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self) {
+ RepeatedField_init_args(argc, argv, self);
+ return Qnil;
+}
+
+void RepeatedField_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "RepeatedField", rb_cObject);
+ rb_define_alloc_func(klass, RepeatedField_alloc);
+ cRepeatedField = klass;
+ rb_gc_register_address(&cRepeatedField);
+
+ rb_define_method(klass, "initialize",
+ RepeatedField_init, -1);
+ rb_define_method(klass, "each", RepeatedField_each, 0);
+ rb_define_method(klass, "[]", RepeatedField_index, 1);
+ rb_define_method(klass, "[]=", RepeatedField_index_set, 2);
+ rb_define_method(klass, "push", RepeatedField_push, 1);
+ rb_define_method(klass, "<<", RepeatedField_push, 1);
+ rb_define_method(klass, "pop", RepeatedField_pop, 0);
+ rb_define_method(klass, "insert", RepeatedField_insert, -1);
+ rb_define_method(klass, "replace", RepeatedField_replace, 1);
+ rb_define_method(klass, "clear", RepeatedField_clear, 0);
+ rb_define_method(klass, "length", RepeatedField_length, 0);
+ rb_define_method(klass, "dup", RepeatedField_dup, 0);
+ // Also define #clone so that we don't inherit Object#clone.
+ rb_define_method(klass, "clone", RepeatedField_dup, 0);
+ rb_define_method(klass, "==", RepeatedField_eq, 1);
+ rb_define_method(klass, "to_ary", RepeatedField_to_ary, 0);
+ rb_define_method(klass, "hash", RepeatedField_hash, 0);
+ rb_define_method(klass, "inspect", RepeatedField_inspect, 0);
+ rb_define_method(klass, "+", RepeatedField_plus, 1);
+ rb_include_module(klass, rb_mEnumerable);
+}
diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c
new file mode 100644
index 00000000..5b1549d2
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/storage.c
@@ -0,0 +1,848 @@
+// 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.
+
+#include "protobuf.h"
+
+#include <math.h>
+
+#include <ruby/encoding.h>
+
+// -----------------------------------------------------------------------------
+// Ruby <-> native slot management.
+// -----------------------------------------------------------------------------
+
+#define DEREF(memory, type) *(type*)(memory)
+
+size_t native_slot_size(upb_fieldtype_t type) {
+ switch (type) {
+ case UPB_TYPE_FLOAT: return 4;
+ case UPB_TYPE_DOUBLE: return 8;
+ case UPB_TYPE_BOOL: return 1;
+ case UPB_TYPE_STRING: return sizeof(VALUE);
+ case UPB_TYPE_BYTES: return sizeof(VALUE);
+ case UPB_TYPE_MESSAGE: return sizeof(VALUE);
+ case UPB_TYPE_ENUM: return 4;
+ case UPB_TYPE_INT32: return 4;
+ case UPB_TYPE_INT64: return 8;
+ case UPB_TYPE_UINT32: return 4;
+ case UPB_TYPE_UINT64: return 8;
+ default: return 0;
+ }
+}
+
+static bool is_ruby_num(VALUE value) {
+ return (TYPE(value) == T_FLOAT ||
+ TYPE(value) == T_FIXNUM ||
+ TYPE(value) == T_BIGNUM);
+}
+
+void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
+ if (!is_ruby_num(val)) {
+ rb_raise(rb_eTypeError, "Expected number type for integral field.");
+ }
+
+ // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
+ // bound; we just need to do precision checks (i.e., disallow rounding) and
+ // check for < 0 on unsigned types.
+ if (TYPE(val) == T_FLOAT) {
+ double dbl_val = NUM2DBL(val);
+ if (floor(dbl_val) != dbl_val) {
+ rb_raise(rb_eRangeError,
+ "Non-integral floating point value assigned to integer field.");
+ }
+ }
+ if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
+ if (NUM2DBL(val) < 0) {
+ rb_raise(rb_eRangeError,
+ "Assigning negative value to unsigned integer field.");
+ }
+ }
+}
+
+void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value) {
+ bool bad_encoding = false;
+ rb_encoding* string_encoding = rb_enc_from_index(ENCODING_GET(value));
+ if (type == UPB_TYPE_STRING) {
+ bad_encoding =
+ string_encoding != kRubyStringUtf8Encoding &&
+ string_encoding != kRubyStringASCIIEncoding;
+ } else {
+ bad_encoding =
+ string_encoding != kRubyString8bitEncoding;
+ }
+ // Check that encoding is UTF-8 or ASCII (for string fields) or ASCII-8BIT
+ // (for bytes fields).
+ if (bad_encoding) {
+ rb_raise(rb_eTypeError, "Encoding for '%s' fields must be %s (was %s)",
+ (type == UPB_TYPE_STRING) ? "string" : "bytes",
+ (type == UPB_TYPE_STRING) ? "UTF-8 or ASCII" : "ASCII-8BIT",
+ rb_enc_name(string_encoding));
+ }
+}
+
+void native_slot_set(upb_fieldtype_t type, VALUE type_class,
+ void* memory, VALUE value) {
+ native_slot_set_value_and_case(type, type_class, memory, value, NULL, 0);
+}
+
+void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
+ void* memory, VALUE value,
+ uint32_t* case_memory,
+ uint32_t case_number) {
+ // Note that in order to atomically change the value in memory and the case
+ // value (w.r.t. Ruby VM calls), we must set the value at |memory| only after
+ // all Ruby VM calls are complete. The case is then set at the bottom of this
+ // function.
+ switch (type) {
+ case UPB_TYPE_FLOAT:
+ if (!is_ruby_num(value)) {
+ rb_raise(rb_eTypeError, "Expected number type for float field.");
+ }
+ DEREF(memory, float) = NUM2DBL(value);
+ break;
+ case UPB_TYPE_DOUBLE:
+ if (!is_ruby_num(value)) {
+ rb_raise(rb_eTypeError, "Expected number type for double field.");
+ }
+ DEREF(memory, double) = NUM2DBL(value);
+ break;
+ case UPB_TYPE_BOOL: {
+ int8_t val = -1;
+ if (value == Qtrue) {
+ val = 1;
+ } else if (value == Qfalse) {
+ val = 0;
+ } else {
+ rb_raise(rb_eTypeError, "Invalid argument for boolean field.");
+ }
+ DEREF(memory, int8_t) = val;
+ break;
+ }
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES: {
+ if (CLASS_OF(value) != rb_cString) {
+ rb_raise(rb_eTypeError, "Invalid argument for string field.");
+ }
+ native_slot_validate_string_encoding(type, value);
+ DEREF(memory, VALUE) = value;
+ break;
+ }
+ case UPB_TYPE_MESSAGE: {
+ if (CLASS_OF(value) != type_class) {
+ rb_raise(rb_eTypeError,
+ "Invalid type %s to assign to submessage field.",
+ rb_class2name(CLASS_OF(value)));
+ }
+ DEREF(memory, VALUE) = value;
+ break;
+ }
+ case UPB_TYPE_ENUM: {
+ if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
+ rb_raise(rb_eTypeError,
+ "Expected number or symbol type for enum field.");
+ }
+ int32_t int_val = 0;
+ if (TYPE(value) == T_SYMBOL) {
+ // Ensure that the given symbol exists in the enum module.
+ VALUE lookup = rb_funcall(type_class, rb_intern("resolve"), 1, value);
+ if (lookup == Qnil) {
+ rb_raise(rb_eRangeError, "Unknown symbol value for enum field.");
+ } else {
+ int_val = NUM2INT(lookup);
+ }
+ } else {
+ native_slot_check_int_range_precision(UPB_TYPE_INT32, value);
+ int_val = NUM2INT(value);
+ }
+ DEREF(memory, int32_t) = int_val;
+ break;
+ }
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_UINT64:
+ native_slot_check_int_range_precision(type, value);
+ switch (type) {
+ case UPB_TYPE_INT32:
+ DEREF(memory, int32_t) = NUM2INT(value);
+ break;
+ case UPB_TYPE_INT64:
+ DEREF(memory, int64_t) = NUM2LL(value);
+ break;
+ case UPB_TYPE_UINT32:
+ DEREF(memory, uint32_t) = NUM2UINT(value);
+ break;
+ case UPB_TYPE_UINT64:
+ DEREF(memory, uint64_t) = NUM2ULL(value);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (case_memory != NULL) {
+ *case_memory = case_number;
+ }
+}
+
+VALUE native_slot_get(upb_fieldtype_t type,
+ VALUE type_class,
+ const void* memory) {
+ switch (type) {
+ case UPB_TYPE_FLOAT:
+ return DBL2NUM(DEREF(memory, float));
+ case UPB_TYPE_DOUBLE:
+ return DBL2NUM(DEREF(memory, double));
+ case UPB_TYPE_BOOL:
+ return DEREF(memory, int8_t) ? Qtrue : Qfalse;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ case UPB_TYPE_MESSAGE:
+ return DEREF(memory, VALUE);
+ case UPB_TYPE_ENUM: {
+ int32_t val = DEREF(memory, int32_t);
+ VALUE symbol = enum_lookup(type_class, INT2NUM(val));
+ if (symbol == Qnil) {
+ return INT2NUM(val);
+ } else {
+ return symbol;
+ }
+ }
+ case UPB_TYPE_INT32:
+ return INT2NUM(DEREF(memory, int32_t));
+ case UPB_TYPE_INT64:
+ return LL2NUM(DEREF(memory, int64_t));
+ case UPB_TYPE_UINT32:
+ return UINT2NUM(DEREF(memory, uint32_t));
+ case UPB_TYPE_UINT64:
+ return ULL2NUM(DEREF(memory, uint64_t));
+ default:
+ return Qnil;
+ }
+}
+
+void native_slot_init(upb_fieldtype_t type, void* memory) {
+ switch (type) {
+ case UPB_TYPE_FLOAT:
+ DEREF(memory, float) = 0.0;
+ break;
+ case UPB_TYPE_DOUBLE:
+ DEREF(memory, double) = 0.0;
+ break;
+ case UPB_TYPE_BOOL:
+ DEREF(memory, int8_t) = 0;
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ DEREF(memory, VALUE) = rb_str_new2("");
+ rb_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES) ?
+ kRubyString8bitEncoding : kRubyStringUtf8Encoding);
+ break;
+ case UPB_TYPE_MESSAGE:
+ DEREF(memory, VALUE) = Qnil;
+ break;
+ case UPB_TYPE_ENUM:
+ case UPB_TYPE_INT32:
+ DEREF(memory, int32_t) = 0;
+ break;
+ case UPB_TYPE_INT64:
+ DEREF(memory, int64_t) = 0;
+ break;
+ case UPB_TYPE_UINT32:
+ DEREF(memory, uint32_t) = 0;
+ break;
+ case UPB_TYPE_UINT64:
+ DEREF(memory, uint64_t) = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void native_slot_mark(upb_fieldtype_t type, void* memory) {
+ switch (type) {
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ case UPB_TYPE_MESSAGE:
+ rb_gc_mark(DEREF(memory, VALUE));
+ break;
+ default:
+ break;
+ }
+}
+
+void native_slot_dup(upb_fieldtype_t type, void* to, void* from) {
+ memcpy(to, from, native_slot_size(type));
+}
+
+void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from) {
+ switch (type) {
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES: {
+ VALUE from_val = DEREF(from, VALUE);
+ DEREF(to, VALUE) = (from_val != Qnil) ?
+ rb_funcall(from_val, rb_intern("dup"), 0) : Qnil;
+ break;
+ }
+ case UPB_TYPE_MESSAGE: {
+ VALUE from_val = DEREF(from, VALUE);
+ DEREF(to, VALUE) = (from_val != Qnil) ?
+ Message_deep_copy(from_val) : Qnil;
+ break;
+ }
+ default:
+ memcpy(to, from, native_slot_size(type));
+ }
+}
+
+bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2) {
+ switch (type) {
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ case UPB_TYPE_MESSAGE: {
+ VALUE val1 = DEREF(mem1, VALUE);
+ VALUE val2 = DEREF(mem2, VALUE);
+ VALUE ret = rb_funcall(val1, rb_intern("=="), 1, val2);
+ return ret == Qtrue;
+ }
+ default:
+ return !memcmp(mem1, mem2, native_slot_size(type));
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Map field utilities.
+// -----------------------------------------------------------------------------
+
+bool is_map_field(const upb_fielddef* field) {
+ if (upb_fielddef_label(field) != UPB_LABEL_REPEATED ||
+ upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
+ return false;
+ }
+ const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
+ return upb_msgdef_mapentry(subdef);
+}
+
+const upb_fielddef* map_field_key(const upb_fielddef* field) {
+ assert(is_map_field(field));
+ const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
+ return map_entry_key(subdef);
+}
+
+const upb_fielddef* map_field_value(const upb_fielddef* field) {
+ assert(is_map_field(field));
+ const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
+ return map_entry_value(subdef);
+}
+
+const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) {
+ const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD);
+ assert(key_field != NULL);
+ return key_field;
+}
+
+const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) {
+ const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD);
+ assert(value_field != NULL);
+ return value_field;
+}
+
+// -----------------------------------------------------------------------------
+// Memory layout management.
+// -----------------------------------------------------------------------------
+
+static size_t align_up_to(size_t offset, size_t granularity) {
+ // Granularity must be a power of two.
+ return (offset + granularity - 1) & ~(granularity - 1);
+}
+
+MessageLayout* create_layout(const upb_msgdef* msgdef) {
+ MessageLayout* layout = ALLOC(MessageLayout);
+ int nfields = upb_msgdef_numfields(msgdef);
+ layout->fields = ALLOC_N(MessageField, nfields);
+
+ upb_msg_field_iter it;
+ size_t off = 0;
+ for (upb_msg_field_begin(&it, msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+
+ if (upb_fielddef_containingoneof(field)) {
+ // Oneofs are handled separately below.
+ continue;
+ }
+
+ // Allocate |field_size| bytes for this field in the layout.
+ size_t field_size = 0;
+ if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+ field_size = sizeof(VALUE);
+ } else {
+ field_size = native_slot_size(upb_fielddef_type(field));
+ }
+ // Align current offset up to |size| granularity.
+ off = align_up_to(off, field_size);
+ layout->fields[upb_fielddef_index(field)].offset = off;
+ layout->fields[upb_fielddef_index(field)].case_offset = MESSAGE_FIELD_NO_CASE;
+ off += field_size;
+ }
+
+ // Handle oneofs now -- we iterate over oneofs specifically and allocate only
+ // one slot per oneof.
+ //
+ // We assign all value slots first, then pack the 'case' fields at the end,
+ // since in the common case (modern 64-bit platform) these are 8 bytes and 4
+ // bytes respectively and we want to avoid alignment overhead.
+ //
+ // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value
+ // space for oneof cases is conceptually as wide as field tag numbers. In
+ // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K
+ // members (8 or 16 bits respectively), so conceivably we could assign
+ // consecutive case numbers and then pick a smaller oneof case slot size, but
+ // the complexity to implement this indirection is probably not worthwhile.
+ upb_msg_oneof_iter oit;
+ for (upb_msg_oneof_begin(&oit, msgdef);
+ !upb_msg_oneof_done(&oit);
+ upb_msg_oneof_next(&oit)) {
+ const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
+
+ // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between
+ // all fields.
+ size_t field_size = NATIVE_SLOT_MAX_SIZE;
+ // Align the offset.
+ off = align_up_to(off, field_size);
+ // Assign all fields in the oneof this same offset.
+ upb_oneof_iter fit;
+ for (upb_oneof_begin(&fit, oneof);
+ !upb_oneof_done(&fit);
+ upb_oneof_next(&fit)) {
+ const upb_fielddef* field = upb_oneof_iter_field(&fit);
+ layout->fields[upb_fielddef_index(field)].offset = off;
+ }
+ off += field_size;
+ }
+
+ // Now the case fields.
+ for (upb_msg_oneof_begin(&oit, msgdef);
+ !upb_msg_oneof_done(&oit);
+ upb_msg_oneof_next(&oit)) {
+ const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
+
+ size_t field_size = sizeof(uint32_t);
+ // Align the offset.
+ off = (off + field_size - 1) & ~(field_size - 1);
+ // Assign all fields in the oneof this same offset.
+ upb_oneof_iter fit;
+ for (upb_oneof_begin(&fit, oneof);
+ !upb_oneof_done(&fit);
+ upb_oneof_next(&fit)) {
+ const upb_fielddef* field = upb_oneof_iter_field(&fit);
+ layout->fields[upb_fielddef_index(field)].case_offset = off;
+ }
+ off += field_size;
+ }
+
+ layout->size = off;
+
+ layout->msgdef = msgdef;
+ upb_msgdef_ref(layout->msgdef, &layout->msgdef);
+
+ return layout;
+}
+
+void free_layout(MessageLayout* layout) {
+ xfree(layout->fields);
+ upb_msgdef_unref(layout->msgdef, &layout->msgdef);
+ xfree(layout);
+}
+
+VALUE field_type_class(const upb_fielddef* field) {
+ VALUE type_class = Qnil;
+ if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
+ VALUE submsgdesc =
+ get_def_obj(upb_fielddef_subdef(field));
+ type_class = Descriptor_msgclass(submsgdesc);
+ } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
+ VALUE subenumdesc =
+ get_def_obj(upb_fielddef_subdef(field));
+ type_class = EnumDescriptor_enummodule(subenumdesc);
+ }
+ return type_class;
+}
+
+static void* slot_memory(MessageLayout* layout,
+ const void* storage,
+ const upb_fielddef* field) {
+ return ((uint8_t *)storage) +
+ layout->fields[upb_fielddef_index(field)].offset;
+}
+
+static uint32_t* slot_oneof_case(MessageLayout* layout,
+ const void* storage,
+ const upb_fielddef* field) {
+ return (uint32_t *)(((uint8_t *)storage) +
+ layout->fields[upb_fielddef_index(field)].case_offset);
+}
+
+
+VALUE layout_get(MessageLayout* layout,
+ const void* storage,
+ const upb_fielddef* field) {
+ void* memory = slot_memory(layout, storage, field);
+ uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+ if (upb_fielddef_containingoneof(field)) {
+ if (*oneof_case != upb_fielddef_number(field)) {
+ return Qnil;
+ }
+ return native_slot_get(upb_fielddef_type(field),
+ field_type_class(field),
+ memory);
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+ return *((VALUE *)memory);
+ } else {
+ return native_slot_get(upb_fielddef_type(field),
+ field_type_class(field),
+ memory);
+ }
+}
+
+static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
+ assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);
+
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
+ RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
+ rb_raise(rb_eTypeError, "Expected repeated field array");
+ }
+
+ RepeatedField* self = ruby_to_RepeatedField(val);
+ if (self->field_type != upb_fielddef_type(field)) {
+ rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
+ }
+
+ if (self->field_type == UPB_TYPE_MESSAGE ||
+ self->field_type == UPB_TYPE_ENUM) {
+ if (self->field_type_class !=
+ get_def_obj(upb_fielddef_subdef(field))) {
+ rb_raise(rb_eTypeError,
+ "Repeated field array has wrong message/enum class");
+ }
+ }
+}
+
+static void check_map_field_type(VALUE val, const upb_fielddef* field) {
+ assert(is_map_field(field));
+ const upb_fielddef* key_field = map_field_key(field);
+ const upb_fielddef* value_field = map_field_value(field);
+
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
+ RTYPEDDATA_TYPE(val) != &Map_type) {
+ rb_raise(rb_eTypeError, "Expected Map instance");
+ }
+
+ Map* self = ruby_to_Map(val);
+ if (self->key_type != upb_fielddef_type(key_field)) {
+ rb_raise(rb_eTypeError, "Map key type does not match field's key type");
+ }
+ if (self->value_type != upb_fielddef_type(value_field)) {
+ rb_raise(rb_eTypeError, "Map value type does not match field's value type");
+ }
+ if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
+ upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
+ if (self->value_type_class !=
+ get_def_obj(upb_fielddef_subdef(value_field))) {
+ rb_raise(rb_eTypeError,
+ "Map value type has wrong message/enum class");
+ }
+ }
+}
+
+
+void layout_set(MessageLayout* layout,
+ void* storage,
+ const upb_fielddef* field,
+ VALUE val) {
+ void* memory = slot_memory(layout, storage, field);
+ uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+ if (upb_fielddef_containingoneof(field)) {
+ if (val == Qnil) {
+ // Assigning nil to a oneof field clears the oneof completely.
+ *oneof_case = ONEOF_CASE_NONE;
+ memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
+ } else {
+ // The transition between field types for a single oneof (union) slot is
+ // somewhat complex because we need to ensure that a GC triggered at any
+ // point by a call into the Ruby VM sees a valid state for this field and
+ // does not either go off into the weeds (following what it thinks is a
+ // VALUE but is actually a different field type) or miss an object (seeing
+ // what it thinks is a primitive field but is actually a VALUE for the new
+ // field type).
+ //
+ // In order for the transition to be safe, the oneof case slot must be in
+ // sync with the value slot whenever the Ruby VM has been called. Thus, we
+ // use native_slot_set_value_and_case(), which ensures that both the value
+ // and case number are altered atomically (w.r.t. the Ruby VM).
+ native_slot_set_value_and_case(
+ upb_fielddef_type(field), field_type_class(field),
+ memory, val,
+ oneof_case, upb_fielddef_number(field));
+ }
+ } else if (is_map_field(field)) {
+ check_map_field_type(val, field);
+ DEREF(memory, VALUE) = val;
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+ check_repeated_field_type(val, field);
+ DEREF(memory, VALUE) = val;
+ } else {
+ native_slot_set(upb_fielddef_type(field), field_type_class(field),
+ memory, val);
+ }
+}
+
+void layout_init(MessageLayout* layout,
+ void* storage) {
+ upb_msg_field_iter it;
+ for (upb_msg_field_begin(&it, layout->msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+ void* memory = slot_memory(layout, storage, field);
+ uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+ if (upb_fielddef_containingoneof(field)) {
+ memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
+ *oneof_case = ONEOF_CASE_NONE;
+ } else if (is_map_field(field)) {
+ VALUE map = Qnil;
+
+ const upb_fielddef* key_field = map_field_key(field);
+ const upb_fielddef* value_field = map_field_value(field);
+ VALUE type_class = field_type_class(value_field);
+
+ if (type_class != Qnil) {
+ VALUE args[3] = {
+ fieldtype_to_ruby(upb_fielddef_type(key_field)),
+ fieldtype_to_ruby(upb_fielddef_type(value_field)),
+ type_class,
+ };
+ map = rb_class_new_instance(3, args, cMap);
+ } else {
+ VALUE args[2] = {
+ fieldtype_to_ruby(upb_fielddef_type(key_field)),
+ fieldtype_to_ruby(upb_fielddef_type(value_field)),
+ };
+ map = rb_class_new_instance(2, args, cMap);
+ }
+
+ DEREF(memory, VALUE) = map;
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+ VALUE ary = Qnil;
+
+ VALUE type_class = field_type_class(field);
+
+ if (type_class != Qnil) {
+ VALUE args[2] = {
+ fieldtype_to_ruby(upb_fielddef_type(field)),
+ type_class,
+ };
+ ary = rb_class_new_instance(2, args, cRepeatedField);
+ } else {
+ VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) };
+ ary = rb_class_new_instance(1, args, cRepeatedField);
+ }
+
+ DEREF(memory, VALUE) = ary;
+ } else {
+ native_slot_init(upb_fielddef_type(field), memory);
+ }
+ }
+}
+
+void layout_mark(MessageLayout* layout, void* storage) {
+ upb_msg_field_iter it;
+ for (upb_msg_field_begin(&it, layout->msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+ void* memory = slot_memory(layout, storage, field);
+ uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+ if (upb_fielddef_containingoneof(field)) {
+ if (*oneof_case == upb_fielddef_number(field)) {
+ native_slot_mark(upb_fielddef_type(field), memory);
+ }
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+ rb_gc_mark(DEREF(memory, VALUE));
+ } else {
+ native_slot_mark(upb_fielddef_type(field), memory);
+ }
+ }
+}
+
+void layout_dup(MessageLayout* layout, void* to, void* from) {
+ upb_msg_field_iter it;
+ for (upb_msg_field_begin(&it, layout->msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+
+ void* to_memory = slot_memory(layout, to, field);
+ uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
+ void* from_memory = slot_memory(layout, from, field);
+ uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
+
+ if (upb_fielddef_containingoneof(field)) {
+ if (*from_oneof_case == upb_fielddef_number(field)) {
+ *to_oneof_case = *from_oneof_case;
+ native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
+ }
+ } else if (is_map_field(field)) {
+ DEREF(to_memory, VALUE) = Map_dup(DEREF(from_memory, VALUE));
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+ DEREF(to_memory, VALUE) = RepeatedField_dup(DEREF(from_memory, VALUE));
+ } else {
+ native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
+ }
+ }
+}
+
+void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
+ upb_msg_field_iter it;
+ for (upb_msg_field_begin(&it, layout->msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+
+ void* to_memory = slot_memory(layout, to, field);
+ uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
+ void* from_memory = slot_memory(layout, from, field);
+ uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
+
+ if (upb_fielddef_containingoneof(field)) {
+ if (*from_oneof_case == upb_fielddef_number(field)) {
+ *to_oneof_case = *from_oneof_case;
+ native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
+ }
+ } else if (is_map_field(field)) {
+ DEREF(to_memory, VALUE) =
+ Map_deep_copy(DEREF(from_memory, VALUE));
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+ DEREF(to_memory, VALUE) =
+ RepeatedField_deep_copy(DEREF(from_memory, VALUE));
+ } else {
+ native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
+ }
+ }
+}
+
+VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
+ upb_msg_field_iter it;
+ for (upb_msg_field_begin(&it, layout->msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+
+ void* msg1_memory = slot_memory(layout, msg1, field);
+ uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field);
+ void* msg2_memory = slot_memory(layout, msg2, field);
+ uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field);
+
+ if (upb_fielddef_containingoneof(field)) {
+ if (*msg1_oneof_case != *msg2_oneof_case ||
+ (*msg1_oneof_case == upb_fielddef_number(field) &&
+ !native_slot_eq(upb_fielddef_type(field),
+ msg1_memory,
+ msg2_memory))) {
+ return Qfalse;
+ }
+ } else if (is_map_field(field)) {
+ if (!Map_eq(DEREF(msg1_memory, VALUE),
+ DEREF(msg2_memory, VALUE))) {
+ return Qfalse;
+ }
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+ if (!RepeatedField_eq(DEREF(msg1_memory, VALUE),
+ DEREF(msg2_memory, VALUE))) {
+ return Qfalse;
+ }
+ } else {
+ if (!native_slot_eq(upb_fielddef_type(field),
+ msg1_memory, msg2_memory)) {
+ return Qfalse;
+ }
+ }
+ }
+ return Qtrue;
+}
+
+VALUE layout_hash(MessageLayout* layout, void* storage) {
+ upb_msg_field_iter it;
+ st_index_t h = rb_hash_start(0);
+ VALUE hash_sym = rb_intern("hash");
+ for (upb_msg_field_begin(&it, layout->msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+ VALUE field_val = layout_get(layout, storage, field);
+ h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0)));
+ }
+ h = rb_hash_end(h);
+
+ return INT2FIX(h);
+}
+
+VALUE layout_inspect(MessageLayout* layout, void* storage) {
+ VALUE str = rb_str_new2("");
+
+ upb_msg_field_iter it;
+ bool first = true;
+ for (upb_msg_field_begin(&it, layout->msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* field = upb_msg_iter_field(&it);
+ VALUE field_val = layout_get(layout, storage, field);
+
+ if (!first) {
+ str = rb_str_cat2(str, ", ");
+ } else {
+ first = false;
+ }
+ str = rb_str_cat2(str, upb_fielddef_name(field));
+ str = rb_str_cat2(str, ": ");
+
+ str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0));
+ }
+
+ return str;
+}
diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c
new file mode 100644
index 00000000..20bd76bc
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/upb.c
@@ -0,0 +1,11220 @@
+// Amalgamated source file
+#include "upb.h"
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2008-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ size_t len;
+ char str[1]; // Null-terminated string data follows.
+} str_t;
+
+static str_t *newstr(const char *data, size_t len) {
+ str_t *ret = malloc(sizeof(*ret) + len);
+ if (!ret) return NULL;
+ ret->len = len;
+ memcpy(ret->str, data, len);
+ ret->str[len] = '\0';
+ return ret;
+}
+
+static void freestr(str_t *s) { free(s); }
+
+// isalpha() etc. from <ctype.h> are locale-dependent, which we don't want.
+static bool upb_isbetween(char c, char low, char high) {
+ return c >= low && c <= high;
+}
+
+static bool upb_isletter(char c) {
+ return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_';
+}
+
+static bool upb_isalphanum(char c) {
+ return upb_isletter(c) || upb_isbetween(c, '0', '9');
+}
+
+static bool upb_isident(const char *str, size_t len, bool full, upb_status *s) {
+ bool start = true;
+ for (size_t i = 0; i < len; i++) {
+ char c = str[i];
+ if (c == '.') {
+ if (start || !full) {
+ upb_status_seterrf(s, "invalid name: unexpected '.' (%s)", str);
+ return false;
+ }
+ start = true;
+ } else if (start) {
+ if (!upb_isletter(c)) {
+ upb_status_seterrf(
+ s, "invalid name: path components must start with a letter (%s)",
+ str);
+ return false;
+ }
+ start = false;
+ } else {
+ if (!upb_isalphanum(c)) {
+ upb_status_seterrf(s, "invalid name: non-alphanumeric character (%s)",
+ str);
+ return false;
+ }
+ }
+ }
+ return !start;
+}
+
+
+/* upb_def ********************************************************************/
+
+upb_deftype_t upb_def_type(const upb_def *d) { return d->type; }
+
+const char *upb_def_fullname(const upb_def *d) { return d->fullname; }
+
+bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) {
+ assert(!upb_def_isfrozen(def));
+ if (!upb_isident(fullname, strlen(fullname), true, s)) return false;
+ free((void*)def->fullname);
+ def->fullname = upb_strdup(fullname);
+ return true;
+}
+
+upb_def *upb_def_dup(const upb_def *def, const void *o) {
+ switch (def->type) {
+ case UPB_DEF_MSG:
+ return UPB_UPCAST(upb_msgdef_dup(upb_downcast_msgdef(def), o));
+ case UPB_DEF_FIELD:
+ return UPB_UPCAST(upb_fielddef_dup(upb_downcast_fielddef(def), o));
+ case UPB_DEF_ENUM:
+ return UPB_UPCAST(upb_enumdef_dup(upb_downcast_enumdef(def), o));
+ default: assert(false); return NULL;
+ }
+}
+
+bool upb_def_isfrozen(const upb_def *def) {
+ return upb_refcounted_isfrozen(UPB_UPCAST(def));
+}
+
+void upb_def_ref(const upb_def *def, const void *owner) {
+ upb_refcounted_ref(UPB_UPCAST(def), owner);
+}
+
+void upb_def_unref(const upb_def *def, const void *owner) {
+ upb_refcounted_unref(UPB_UPCAST(def), owner);
+}
+
+void upb_def_donateref(const upb_def *def, const void *from, const void *to) {
+ upb_refcounted_donateref(UPB_UPCAST(def), from, to);
+}
+
+void upb_def_checkref(const upb_def *def, const void *owner) {
+ upb_refcounted_checkref(UPB_UPCAST(def), owner);
+}
+
+static bool upb_def_init(upb_def *def, upb_deftype_t type,
+ const struct upb_refcounted_vtbl *vtbl,
+ const void *owner) {
+ if (!upb_refcounted_init(UPB_UPCAST(def), vtbl, owner)) return false;
+ def->type = type;
+ def->fullname = NULL;
+ def->came_from_user = false;
+ return true;
+}
+
+static void upb_def_uninit(upb_def *def) {
+ free((void*)def->fullname);
+}
+
+static const char *msgdef_name(const upb_msgdef *m) {
+ const char *name = upb_def_fullname(UPB_UPCAST(m));
+ return name ? name : "(anonymous)";
+}
+
+static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
+ if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+ upb_status_seterrmsg(s, "fielddef must have name and number set");
+ return false;
+ }
+
+ if (!f->type_is_set_) {
+ upb_status_seterrmsg(s, "fielddef type was not initialized");
+ return false;
+ }
+
+ if (upb_fielddef_lazy(f) &&
+ upb_fielddef_descriptortype(f) != UPB_DESCRIPTOR_TYPE_MESSAGE) {
+ upb_status_seterrmsg(s,
+ "only length-delimited submessage fields may be lazy");
+ return false;
+ }
+
+ if (upb_fielddef_hassubdef(f)) {
+ if (f->subdef_is_symbolic) {
+ upb_status_seterrf(s, "field '%s.%s' has not been resolved",
+ msgdef_name(f->msg.def), upb_fielddef_name(f));
+ return false;
+ }
+
+ const upb_def *subdef = upb_fielddef_subdef(f);
+ if (subdef == NULL) {
+ upb_status_seterrf(s, "field %s.%s is missing required subdef",
+ msgdef_name(f->msg.def), upb_fielddef_name(f));
+ return false;
+ }
+
+ if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) {
+ upb_status_seterrf(s,
+ "subdef of field %s.%s is not frozen or being frozen",
+ msgdef_name(f->msg.def), upb_fielddef_name(f));
+ return false;
+ }
+ }
+
+ if (upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+ bool has_default_name = upb_fielddef_enumhasdefaultstr(f);
+ bool has_default_number = upb_fielddef_enumhasdefaultint32(f);
+
+ // Previously verified by upb_validate_enumdef().
+ assert(upb_enumdef_numvals(upb_fielddef_enumsubdef(f)) > 0);
+
+ // We've already validated that we have an associated enumdef and that it
+ // has at least one member, so at least one of these should be true.
+ // Because if the user didn't set anything, we'll pick up the enum's
+ // default, but if the user *did* set something we should at least pick up
+ // the one they set (int32 or string).
+ assert(has_default_name || has_default_number);
+
+ if (!has_default_name) {
+ upb_status_seterrf(s,
+ "enum default for field %s.%s (%d) is not in the enum",
+ msgdef_name(f->msg.def), upb_fielddef_name(f),
+ upb_fielddef_defaultint32(f));
+ return false;
+ }
+
+ if (!has_default_number) {
+ upb_status_seterrf(s,
+ "enum default for field %s.%s (%s) is not in the enum",
+ msgdef_name(f->msg.def), upb_fielddef_name(f),
+ upb_fielddef_defaultstr(f, NULL));
+ return false;
+ }
+
+ // Lift the effective numeric default into the field's default slot, in case
+ // we were only getting it "by reference" from the enumdef.
+ upb_fielddef_setdefaultint32(f, upb_fielddef_defaultint32(f));
+ }
+
+ // Ensure that MapEntry submessages only appear as repeated fields, not
+ // optional/required (singular) fields.
+ if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
+ upb_fielddef_msgsubdef(f) != NULL) {
+ const upb_msgdef *subdef = upb_fielddef_msgsubdef(f);
+ if (upb_msgdef_mapentry(subdef) && !upb_fielddef_isseq(f)) {
+ upb_status_seterrf(s,
+ "Field %s refers to mapentry message but is not "
+ "a repeated field",
+ upb_fielddef_name(f) ? upb_fielddef_name(f) :
+ "(unnamed)");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool upb_validate_enumdef(const upb_enumdef *e, upb_status *s) {
+ if (upb_enumdef_numvals(e) == 0) {
+ upb_status_seterrf(s, "enum %s has no members (must have at least one)",
+ upb_enumdef_fullname(e));
+ return false;
+ }
+
+ return true;
+}
+
+// All submessage fields are lower than all other fields.
+// Secondly, fields are increasing in order.
+uint32_t field_rank(const upb_fielddef *f) {
+ uint32_t ret = upb_fielddef_number(f);
+ const uint32_t high_bit = 1 << 30;
+ assert(ret < high_bit);
+ if (!upb_fielddef_issubmsg(f))
+ ret |= high_bit;
+ return ret;
+}
+
+int cmp_fields(const void *p1, const void *p2) {
+ const upb_fielddef *f1 = *(upb_fielddef*const*)p1;
+ const upb_fielddef *f2 = *(upb_fielddef*const*)p2;
+ return field_rank(f1) - field_rank(f2);
+}
+
+static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
+ // Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the
+ // lowest indexes, but we do not publicly guarantee this.
+ int n = upb_msgdef_numfields(m);
+ upb_fielddef **fields = malloc(n * sizeof(*fields));
+ if (!fields) return false;
+
+ upb_msg_field_iter j;
+ int i;
+ m->submsg_field_count = 0;
+ for(i = 0, upb_msg_field_begin(&j, m);
+ !upb_msg_field_done(&j);
+ upb_msg_field_next(&j), i++) {
+ upb_fielddef *f = upb_msg_iter_field(&j);
+ assert(f->msg.def == m);
+ if (!upb_validate_field(f, s)) {
+ free(fields);
+ return false;
+ }
+ if (upb_fielddef_issubmsg(f)) {
+ m->submsg_field_count++;
+ }
+ fields[i] = f;
+ }
+
+ qsort(fields, n, sizeof(*fields), cmp_fields);
+
+ uint32_t selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
+ for (i = 0; i < n; i++) {
+ upb_fielddef *f = fields[i];
+ f->index_ = i;
+ f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
+ selector += upb_handlers_selectorcount(f);
+ }
+ m->selector_count = selector;
+
+#ifndef NDEBUG
+ // Verify that all selectors for the message are distinct.
+ //
+#define TRY(type) \
+ if (upb_handlers_getselector(f, type, &sel)) upb_inttable_insert(&t, sel, v);
+
+ upb_inttable t;
+ upb_inttable_init(&t, UPB_CTYPE_BOOL);
+ upb_value v = upb_value_bool(true);
+ upb_selector_t sel;
+ upb_inttable_insert(&t, UPB_STARTMSG_SELECTOR, v);
+ upb_inttable_insert(&t, UPB_ENDMSG_SELECTOR, v);
+ for(upb_msg_field_begin(&j, m);
+ !upb_msg_field_done(&j);
+ upb_msg_field_next(&j)) {
+ upb_fielddef *f = upb_msg_iter_field(&j);
+ // These calls will assert-fail in upb_table if the value already exists.
+ TRY(UPB_HANDLER_INT32);
+ TRY(UPB_HANDLER_INT64)
+ TRY(UPB_HANDLER_UINT32)
+ TRY(UPB_HANDLER_UINT64)
+ TRY(UPB_HANDLER_FLOAT)
+ TRY(UPB_HANDLER_DOUBLE)
+ TRY(UPB_HANDLER_BOOL)
+ TRY(UPB_HANDLER_STARTSTR)
+ TRY(UPB_HANDLER_STRING)
+ TRY(UPB_HANDLER_ENDSTR)
+ TRY(UPB_HANDLER_STARTSUBMSG)
+ TRY(UPB_HANDLER_ENDSUBMSG)
+ TRY(UPB_HANDLER_STARTSEQ)
+ TRY(UPB_HANDLER_ENDSEQ)
+ }
+ upb_inttable_uninit(&t);
+#undef TRY
+#endif
+
+ free(fields);
+ return true;
+}
+
+bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) {
+ upb_status_clear(s);
+
+ // First perform validation, in two passes so we can check that we have a
+ // transitive closure without needing to search.
+ for (int i = 0; i < n; i++) {
+ upb_def *def = defs[i];
+ if (upb_def_isfrozen(def)) {
+ // Could relax this requirement if it's annoying.
+ upb_status_seterrmsg(s, "def is already frozen");
+ goto err;
+ } else if (def->type == UPB_DEF_FIELD) {
+ upb_status_seterrmsg(s, "standalone fielddefs can not be frozen");
+ goto err;
+ } else if (def->type == UPB_DEF_ENUM) {
+ if (!upb_validate_enumdef(upb_dyncast_enumdef(def), s)) {
+ goto err;
+ }
+ } else {
+ // Set now to detect transitive closure in the second pass.
+ def->came_from_user = true;
+ }
+ }
+
+ // Second pass of validation. Also assign selector bases and indexes, and
+ // compact tables.
+ for (int i = 0; i < n; i++) {
+ upb_msgdef *m = upb_dyncast_msgdef_mutable(defs[i]);
+ upb_enumdef *e = upb_dyncast_enumdef_mutable(defs[i]);
+ if (m) {
+ upb_inttable_compact(&m->itof);
+ if (!assign_msg_indices(m, s)) {
+ goto err;
+ }
+ } else if (e) {
+ upb_inttable_compact(&e->iton);
+ }
+ }
+
+ // Def graph contains FieldDefs between each MessageDef, so double the limit.
+ int maxdepth = UPB_MAX_MESSAGE_DEPTH * 2;
+
+ // Validation all passed; freeze the defs.
+ bool ret =
+ upb_refcounted_freeze((upb_refcounted * const *)defs, n, s, maxdepth);
+ assert(!(s && ret != upb_ok(s)));
+ return ret;
+
+err:
+ for (int i = 0; i < n; i++) {
+ defs[i]->came_from_user = false;
+ }
+ assert(!(s && upb_ok(s)));
+ return false;
+}
+
+
+/* upb_enumdef ****************************************************************/
+
+static void upb_enumdef_free(upb_refcounted *r) {
+ upb_enumdef *e = (upb_enumdef*)r;
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &e->iton);
+ for( ; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ // To clean up the upb_strdup() from upb_enumdef_addval().
+ free(upb_value_getcstr(upb_inttable_iter_value(&i)));
+ }
+ upb_strtable_uninit(&e->ntoi);
+ upb_inttable_uninit(&e->iton);
+ upb_def_uninit(UPB_UPCAST(e));
+ free(e);
+}
+
+upb_enumdef *upb_enumdef_new(const void *owner) {
+ static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_enumdef_free};
+ upb_enumdef *e = malloc(sizeof(*e));
+ if (!e) return NULL;
+ if (!upb_def_init(UPB_UPCAST(e), UPB_DEF_ENUM, &vtbl, owner)) goto err2;
+ if (!upb_strtable_init(&e->ntoi, UPB_CTYPE_INT32)) goto err2;
+ if (!upb_inttable_init(&e->iton, UPB_CTYPE_CSTR)) goto err1;
+ return e;
+
+err1:
+ upb_strtable_uninit(&e->ntoi);
+err2:
+ free(e);
+ return NULL;
+}
+
+upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner) {
+ upb_enumdef *new_e = upb_enumdef_new(owner);
+ if (!new_e) return NULL;
+ upb_enum_iter i;
+ for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) {
+ bool success = upb_enumdef_addval(
+ new_e, upb_enum_iter_name(&i),upb_enum_iter_number(&i), NULL);
+ if (!success) {
+ upb_enumdef_unref(new_e, owner);
+ return NULL;
+ }
+ }
+ return new_e;
+}
+
+bool upb_enumdef_isfrozen(const upb_enumdef *e) {
+ return upb_def_isfrozen(UPB_UPCAST(e));
+}
+
+void upb_enumdef_ref(const upb_enumdef *e, const void *owner) {
+ upb_def_ref(UPB_UPCAST(e), owner);
+}
+
+void upb_enumdef_unref(const upb_enumdef *e, const void *owner) {
+ upb_def_unref(UPB_UPCAST(e), owner);
+}
+
+void upb_enumdef_donateref(
+ const upb_enumdef *e, const void *from, const void *to) {
+ upb_def_donateref(UPB_UPCAST(e), from, to);
+}
+
+void upb_enumdef_checkref(const upb_enumdef *e, const void *owner) {
+ upb_def_checkref(UPB_UPCAST(e), owner);
+}
+
+bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status) {
+ upb_def *d = UPB_UPCAST(e);
+ return upb_def_freeze(&d, 1, status);
+}
+
+const char *upb_enumdef_fullname(const upb_enumdef *e) {
+ return upb_def_fullname(UPB_UPCAST(e));
+}
+
+bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname,
+ upb_status *s) {
+ return upb_def_setfullname(UPB_UPCAST(e), fullname, s);
+}
+
+bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
+ upb_status *status) {
+ if (!upb_isident(name, strlen(name), false, status)) {
+ return false;
+ }
+ if (upb_enumdef_ntoiz(e, name, NULL)) {
+ upb_status_seterrf(status, "name '%s' is already defined", name);
+ return false;
+ }
+ if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) {
+ upb_status_seterrmsg(status, "out of memory");
+ return false;
+ }
+ if (!upb_inttable_lookup(&e->iton, num, NULL) &&
+ !upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) {
+ upb_status_seterrmsg(status, "out of memory");
+ upb_strtable_remove(&e->ntoi, name, NULL);
+ return false;
+ }
+ if (upb_enumdef_numvals(e) == 1) {
+ bool ok = upb_enumdef_setdefault(e, num, NULL);
+ UPB_ASSERT_VAR(ok, ok);
+ }
+ return true;
+}
+
+int32_t upb_enumdef_default(const upb_enumdef *e) {
+ assert(upb_enumdef_iton(e, e->defaultval));
+ return e->defaultval;
+}
+
+bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s) {
+ assert(!upb_enumdef_isfrozen(e));
+ if (!upb_enumdef_iton(e, val)) {
+ upb_status_seterrf(s, "number '%d' is not in the enum.", val);
+ return false;
+ }
+ e->defaultval = val;
+ return true;
+}
+
+int upb_enumdef_numvals(const upb_enumdef *e) {
+ return upb_strtable_count(&e->ntoi);
+}
+
+void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) {
+ // We iterate over the ntoi table, to account for duplicate numbers.
+ upb_strtable_begin(i, &e->ntoi);
+}
+
+void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); }
+bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); }
+
+bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name,
+ size_t len, int32_t *num) {
+ upb_value v;
+ if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) {
+ return false;
+ }
+ if (num) *num = upb_value_getint32(v);
+ return true;
+}
+
+const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) {
+ upb_value v;
+ return upb_inttable_lookup32(&def->iton, num, &v) ?
+ upb_value_getcstr(v) : NULL;
+}
+
+const char *upb_enum_iter_name(upb_enum_iter *iter) {
+ return upb_strtable_iter_key(iter);
+}
+
+int32_t upb_enum_iter_number(upb_enum_iter *iter) {
+ return upb_value_getint32(upb_strtable_iter_value(iter));
+}
+
+
+/* upb_fielddef ***************************************************************/
+
+static void upb_fielddef_init_default(upb_fielddef *f);
+
+static void upb_fielddef_uninit_default(upb_fielddef *f) {
+ if (f->type_is_set_ && f->default_is_string && f->defaultval.bytes)
+ freestr(f->defaultval.bytes);
+}
+
+static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit,
+ void *closure) {
+ const upb_fielddef *f = (const upb_fielddef*)r;
+ if (upb_fielddef_containingtype(f)) {
+ visit(r, UPB_UPCAST2(upb_fielddef_containingtype(f)), closure);
+ }
+ if (upb_fielddef_containingoneof(f)) {
+ visit(r, UPB_UPCAST2(upb_fielddef_containingoneof(f)), closure);
+ }
+ if (upb_fielddef_subdef(f)) {
+ visit(r, UPB_UPCAST(upb_fielddef_subdef(f)), closure);
+ }
+}
+
+static void freefield(upb_refcounted *r) {
+ upb_fielddef *f = (upb_fielddef*)r;
+ upb_fielddef_uninit_default(f);
+ if (f->subdef_is_symbolic)
+ free(f->sub.name);
+ upb_def_uninit(UPB_UPCAST(f));
+ free(f);
+}
+
+static const char *enumdefaultstr(const upb_fielddef *f) {
+ assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+ const upb_enumdef *e = upb_fielddef_enumsubdef(f);
+ if (f->default_is_string && f->defaultval.bytes) {
+ // Default was explicitly set as a string.
+ str_t *s = f->defaultval.bytes;
+ return s->str;
+ } else if (e) {
+ if (!f->default_is_string) {
+ // Default was explicitly set as an integer; look it up in enumdef.
+ const char *name = upb_enumdef_iton(e, f->defaultval.sint);
+ if (name) {
+ return name;
+ }
+ } else {
+ // Default is completely unset; pull enumdef default.
+ if (upb_enumdef_numvals(e) > 0) {
+ const char *name = upb_enumdef_iton(e, upb_enumdef_default(e));
+ assert(name);
+ return name;
+ }
+ }
+ }
+ return NULL;
+}
+
+static bool enumdefaultint32(const upb_fielddef *f, int32_t *val) {
+ assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+ const upb_enumdef *e = upb_fielddef_enumsubdef(f);
+ if (!f->default_is_string) {
+ // Default was explicitly set as an integer.
+ *val = f->defaultval.sint;
+ return true;
+ } else if (e) {
+ if (f->defaultval.bytes) {
+ // Default was explicitly set as a str; try to lookup corresponding int.
+ str_t *s = f->defaultval.bytes;
+ if (upb_enumdef_ntoiz(e, s->str, val)) {
+ return true;
+ }
+ } else {
+ // Default is unset; try to pull in enumdef default.
+ if (upb_enumdef_numvals(e) > 0) {
+ *val = upb_enumdef_default(e);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+upb_fielddef *upb_fielddef_new(const void *owner) {
+ static const struct upb_refcounted_vtbl vtbl = {visitfield, freefield};
+ upb_fielddef *f = malloc(sizeof(*f));
+ if (!f) return NULL;
+ if (!upb_def_init(UPB_UPCAST(f), UPB_DEF_FIELD, &vtbl, owner)) {
+ free(f);
+ return NULL;
+ }
+ f->msg.def = NULL;
+ f->sub.def = NULL;
+ f->oneof = NULL;
+ f->subdef_is_symbolic = false;
+ f->msg_is_symbolic = false;
+ f->label_ = UPB_LABEL_OPTIONAL;
+ f->type_ = UPB_TYPE_INT32;
+ f->number_ = 0;
+ f->type_is_set_ = false;
+ f->tagdelim = false;
+ f->is_extension_ = false;
+ f->lazy_ = false;
+ f->packed_ = true;
+
+ // For the moment we default this to UPB_INTFMT_VARIABLE, since it will work
+ // with all integer types and is in some since more "default" since the most
+ // normal-looking proto2 types int32/int64/uint32/uint64 use variable.
+ //
+ // Other options to consider:
+ // - there is no default; users must set this manually (like type).
+ // - default signed integers to UPB_INTFMT_ZIGZAG, since it's more likely to
+ // be an optimal default for signed integers.
+ f->intfmt = UPB_INTFMT_VARIABLE;
+ return f;
+}
+
+upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) {
+ upb_fielddef *newf = upb_fielddef_new(owner);
+ if (!newf) return NULL;
+ upb_fielddef_settype(newf, upb_fielddef_type(f));
+ upb_fielddef_setlabel(newf, upb_fielddef_label(f));
+ upb_fielddef_setnumber(newf, upb_fielddef_number(f), NULL);
+ upb_fielddef_setname(newf, upb_fielddef_name(f), NULL);
+ if (f->default_is_string && f->defaultval.bytes) {
+ str_t *s = f->defaultval.bytes;
+ upb_fielddef_setdefaultstr(newf, s->str, s->len, NULL);
+ } else {
+ newf->default_is_string = f->default_is_string;
+ newf->defaultval = f->defaultval;
+ }
+
+ const char *srcname;
+ if (f->subdef_is_symbolic) {
+ srcname = f->sub.name; // Might be NULL.
+ } else {
+ srcname = f->sub.def ? upb_def_fullname(f->sub.def) : NULL;
+ }
+ if (srcname) {
+ char *newname = malloc(strlen(f->sub.def->fullname) + 2);
+ if (!newname) {
+ upb_fielddef_unref(newf, owner);
+ return NULL;
+ }
+ strcpy(newname, ".");
+ strcat(newname, f->sub.def->fullname);
+ upb_fielddef_setsubdefname(newf, newname, NULL);
+ free(newname);
+ }
+
+ return newf;
+}
+
+bool upb_fielddef_isfrozen(const upb_fielddef *f) {
+ return upb_def_isfrozen(UPB_UPCAST(f));
+}
+
+void upb_fielddef_ref(const upb_fielddef *f, const void *owner) {
+ upb_def_ref(UPB_UPCAST(f), owner);
+}
+
+void upb_fielddef_unref(const upb_fielddef *f, const void *owner) {
+ upb_def_unref(UPB_UPCAST(f), owner);
+}
+
+void upb_fielddef_donateref(
+ const upb_fielddef *f, const void *from, const void *to) {
+ upb_def_donateref(UPB_UPCAST(f), from, to);
+}
+
+void upb_fielddef_checkref(const upb_fielddef *f, const void *owner) {
+ upb_def_checkref(UPB_UPCAST(f), owner);
+}
+
+bool upb_fielddef_typeisset(const upb_fielddef *f) {
+ return f->type_is_set_;
+}
+
+upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) {
+ assert(f->type_is_set_);
+ return f->type_;
+}
+
+uint32_t upb_fielddef_index(const upb_fielddef *f) {
+ return f->index_;
+}
+
+upb_label_t upb_fielddef_label(const upb_fielddef *f) {
+ return f->label_;
+}
+
+upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f) {
+ return f->intfmt;
+}
+
+bool upb_fielddef_istagdelim(const upb_fielddef *f) {
+ return f->tagdelim;
+}
+
+uint32_t upb_fielddef_number(const upb_fielddef *f) {
+ return f->number_;
+}
+
+bool upb_fielddef_isextension(const upb_fielddef *f) {
+ return f->is_extension_;
+}
+
+bool upb_fielddef_lazy(const upb_fielddef *f) {
+ return f->lazy_;
+}
+
+bool upb_fielddef_packed(const upb_fielddef *f) {
+ return f->packed_;
+}
+
+const char *upb_fielddef_name(const upb_fielddef *f) {
+ return upb_def_fullname(UPB_UPCAST(f));
+}
+
+const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) {
+ return f->msg_is_symbolic ? NULL : f->msg.def;
+}
+
+const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) {
+ return f->oneof;
+}
+
+upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) {
+ return (upb_msgdef*)upb_fielddef_containingtype(f);
+}
+
+const char *upb_fielddef_containingtypename(upb_fielddef *f) {
+ return f->msg_is_symbolic ? f->msg.name : NULL;
+}
+
+static void release_containingtype(upb_fielddef *f) {
+ if (f->msg_is_symbolic) free(f->msg.name);
+}
+
+bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name,
+ upb_status *s) {
+ assert(!upb_fielddef_isfrozen(f));
+ if (upb_fielddef_containingtype(f)) {
+ upb_status_seterrmsg(s, "field has already been added to a message.");
+ return false;
+ }
+ // TODO: validate name (upb_isident() doesn't quite work atm because this name
+ // may have a leading ".").
+ release_containingtype(f);
+ f->msg.name = upb_strdup(name);
+ f->msg_is_symbolic = true;
+ return true;
+}
+
+bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) {
+ if (upb_fielddef_containingtype(f) || upb_fielddef_containingoneof(f)) {
+ upb_status_seterrmsg(s, "Already added to message or oneof");
+ return false;
+ }
+ return upb_def_setfullname(UPB_UPCAST(f), name, s);
+}
+
+static void chkdefaulttype(const upb_fielddef *f, upb_fieldtype_t type) {
+ UPB_UNUSED(f);
+ UPB_UNUSED(type);
+ assert(f->type_is_set_ && upb_fielddef_type(f) == type);
+}
+
+int64_t upb_fielddef_defaultint64(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_INT64);
+ return f->defaultval.sint;
+}
+
+int32_t upb_fielddef_defaultint32(const upb_fielddef *f) {
+ if (f->type_is_set_ && upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+ int32_t val;
+ bool ok = enumdefaultint32(f, &val);
+ UPB_ASSERT_VAR(ok, ok);
+ return val;
+ } else {
+ chkdefaulttype(f, UPB_TYPE_INT32);
+ return f->defaultval.sint;
+ }
+}
+
+uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_UINT64);
+ return f->defaultval.uint;
+}
+
+uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_UINT32);
+ return f->defaultval.uint;
+}
+
+bool upb_fielddef_defaultbool(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_BOOL);
+ return f->defaultval.uint;
+}
+
+float upb_fielddef_defaultfloat(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_FLOAT);
+ return f->defaultval.flt;
+}
+
+double upb_fielddef_defaultdouble(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_DOUBLE);
+ return f->defaultval.dbl;
+}
+
+const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) {
+ assert(f->type_is_set_);
+ assert(upb_fielddef_type(f) == UPB_TYPE_STRING ||
+ upb_fielddef_type(f) == UPB_TYPE_BYTES ||
+ upb_fielddef_type(f) == UPB_TYPE_ENUM);
+
+ if (upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+ const char *ret = enumdefaultstr(f);
+ assert(ret);
+ // Enum defaults can't have embedded NULLs.
+ if (len) *len = strlen(ret);
+ return ret;
+ }
+
+ if (f->default_is_string) {
+ str_t *str = f->defaultval.bytes;
+ if (len) *len = str->len;
+ return str->str;
+ }
+
+ return NULL;
+}
+
+static void upb_fielddef_init_default(upb_fielddef *f) {
+ f->default_is_string = false;
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_DOUBLE: f->defaultval.dbl = 0; break;
+ case UPB_TYPE_FLOAT: f->defaultval.flt = 0; break;
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64: f->defaultval.sint = 0; break;
+ case UPB_TYPE_UINT64:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_BOOL: f->defaultval.uint = 0; break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ f->defaultval.bytes = newstr("", 0);
+ f->default_is_string = true;
+ break;
+ case UPB_TYPE_MESSAGE: break;
+ case UPB_TYPE_ENUM:
+ // This is our special sentinel that indicates "not set" for an enum.
+ f->default_is_string = true;
+ f->defaultval.bytes = NULL;
+ break;
+ }
+}
+
+const upb_def *upb_fielddef_subdef(const upb_fielddef *f) {
+ return f->subdef_is_symbolic ? NULL : f->sub.def;
+}
+
+const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) {
+ const upb_def *def = upb_fielddef_subdef(f);
+ return def ? upb_dyncast_msgdef(def) : NULL;
+}
+
+const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) {
+ const upb_def *def = upb_fielddef_subdef(f);
+ return def ? upb_dyncast_enumdef(def) : NULL;
+}
+
+upb_def *upb_fielddef_subdef_mutable(upb_fielddef *f) {
+ return (upb_def*)upb_fielddef_subdef(f);
+}
+
+const char *upb_fielddef_subdefname(const upb_fielddef *f) {
+ if (f->subdef_is_symbolic) {
+ return f->sub.name;
+ } else if (f->sub.def) {
+ return upb_def_fullname(f->sub.def);
+ } else {
+ return NULL;
+ }
+}
+
+bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) {
+ if (upb_fielddef_containingtype(f)) {
+ upb_status_seterrmsg(
+ s, "cannot change field number after adding to a message");
+ return false;
+ }
+ if (number == 0 || number > UPB_MAX_FIELDNUMBER) {
+ upb_status_seterrf(s, "invalid field number (%u)", number);
+ return false;
+ }
+ f->number_ = number;
+ return true;
+}
+
+void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type) {
+ assert(!upb_fielddef_isfrozen(f));
+ assert(upb_fielddef_checktype(type));
+ upb_fielddef_uninit_default(f);
+ f->type_ = type;
+ f->type_is_set_ = true;
+ upb_fielddef_init_default(f);
+}
+
+void upb_fielddef_setdescriptortype(upb_fielddef *f, int type) {
+ assert(!upb_fielddef_isfrozen(f));
+ switch (type) {
+ case UPB_DESCRIPTOR_TYPE_DOUBLE:
+ upb_fielddef_settype(f, UPB_TYPE_DOUBLE);
+ break;
+ case UPB_DESCRIPTOR_TYPE_FLOAT:
+ upb_fielddef_settype(f, UPB_TYPE_FLOAT);
+ break;
+ case UPB_DESCRIPTOR_TYPE_INT64:
+ case UPB_DESCRIPTOR_TYPE_SFIXED64:
+ case UPB_DESCRIPTOR_TYPE_SINT64:
+ upb_fielddef_settype(f, UPB_TYPE_INT64);
+ break;
+ case UPB_DESCRIPTOR_TYPE_UINT64:
+ case UPB_DESCRIPTOR_TYPE_FIXED64:
+ upb_fielddef_settype(f, UPB_TYPE_UINT64);
+ break;
+ case UPB_DESCRIPTOR_TYPE_INT32:
+ case UPB_DESCRIPTOR_TYPE_SFIXED32:
+ case UPB_DESCRIPTOR_TYPE_SINT32:
+ upb_fielddef_settype(f, UPB_TYPE_INT32);
+ break;
+ case UPB_DESCRIPTOR_TYPE_UINT32:
+ case UPB_DESCRIPTOR_TYPE_FIXED32:
+ upb_fielddef_settype(f, UPB_TYPE_UINT32);
+ break;
+ case UPB_DESCRIPTOR_TYPE_BOOL:
+ upb_fielddef_settype(f, UPB_TYPE_BOOL);
+ break;
+ case UPB_DESCRIPTOR_TYPE_STRING:
+ upb_fielddef_settype(f, UPB_TYPE_STRING);
+ break;
+ case UPB_DESCRIPTOR_TYPE_BYTES:
+ upb_fielddef_settype(f, UPB_TYPE_BYTES);
+ break;
+ case UPB_DESCRIPTOR_TYPE_GROUP:
+ case UPB_DESCRIPTOR_TYPE_MESSAGE:
+ upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
+ break;
+ case UPB_DESCRIPTOR_TYPE_ENUM:
+ upb_fielddef_settype(f, UPB_TYPE_ENUM);
+ break;
+ default: assert(false);
+ }
+
+ if (type == UPB_DESCRIPTOR_TYPE_FIXED64 ||
+ type == UPB_DESCRIPTOR_TYPE_FIXED32 ||
+ type == UPB_DESCRIPTOR_TYPE_SFIXED64 ||
+ type == UPB_DESCRIPTOR_TYPE_SFIXED32) {
+ upb_fielddef_setintfmt(f, UPB_INTFMT_FIXED);
+ } else if (type == UPB_DESCRIPTOR_TYPE_SINT64 ||
+ type == UPB_DESCRIPTOR_TYPE_SINT32) {
+ upb_fielddef_setintfmt(f, UPB_INTFMT_ZIGZAG);
+ } else {
+ upb_fielddef_setintfmt(f, UPB_INTFMT_VARIABLE);
+ }
+
+ upb_fielddef_settagdelim(f, type == UPB_DESCRIPTOR_TYPE_GROUP);
+}
+
+upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) {
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_FLOAT: return UPB_DESCRIPTOR_TYPE_FLOAT;
+ case UPB_TYPE_DOUBLE: return UPB_DESCRIPTOR_TYPE_DOUBLE;
+ case UPB_TYPE_BOOL: return UPB_DESCRIPTOR_TYPE_BOOL;
+ case UPB_TYPE_STRING: return UPB_DESCRIPTOR_TYPE_STRING;
+ case UPB_TYPE_BYTES: return UPB_DESCRIPTOR_TYPE_BYTES;
+ case UPB_TYPE_ENUM: return UPB_DESCRIPTOR_TYPE_ENUM;
+ case UPB_TYPE_INT32:
+ switch (upb_fielddef_intfmt(f)) {
+ case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT32;
+ case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_SFIXED32;
+ case UPB_INTFMT_ZIGZAG: return UPB_DESCRIPTOR_TYPE_SINT32;
+ }
+ case UPB_TYPE_INT64:
+ switch (upb_fielddef_intfmt(f)) {
+ case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT64;
+ case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_SFIXED64;
+ case UPB_INTFMT_ZIGZAG: return UPB_DESCRIPTOR_TYPE_SINT64;
+ }
+ case UPB_TYPE_UINT32:
+ switch (upb_fielddef_intfmt(f)) {
+ case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT32;
+ case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_FIXED32;
+ case UPB_INTFMT_ZIGZAG: return -1;
+ }
+ case UPB_TYPE_UINT64:
+ switch (upb_fielddef_intfmt(f)) {
+ case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT64;
+ case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_FIXED64;
+ case UPB_INTFMT_ZIGZAG: return -1;
+ }
+ case UPB_TYPE_MESSAGE:
+ return upb_fielddef_istagdelim(f) ?
+ UPB_DESCRIPTOR_TYPE_GROUP : UPB_DESCRIPTOR_TYPE_MESSAGE;
+ }
+ return 0;
+}
+
+void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension) {
+ assert(!upb_fielddef_isfrozen(f));
+ f->is_extension_ = is_extension;
+}
+
+void upb_fielddef_setlazy(upb_fielddef *f, bool lazy) {
+ assert(!upb_fielddef_isfrozen(f));
+ f->lazy_ = lazy;
+}
+
+void upb_fielddef_setpacked(upb_fielddef *f, bool packed) {
+ assert(!upb_fielddef_isfrozen(f));
+ f->packed_ = packed;
+}
+
+void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) {
+ assert(!upb_fielddef_isfrozen(f));
+ assert(upb_fielddef_checklabel(label));
+ f->label_ = label;
+}
+
+void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt) {
+ assert(!upb_fielddef_isfrozen(f));
+ assert(upb_fielddef_checkintfmt(fmt));
+ f->intfmt = fmt;
+}
+
+void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim) {
+ assert(!upb_fielddef_isfrozen(f));
+ f->tagdelim = tag_delim;
+ f->tagdelim = tag_delim;
+}
+
+static bool checksetdefault(upb_fielddef *f, upb_fieldtype_t type) {
+ if (!f->type_is_set_ || upb_fielddef_isfrozen(f) ||
+ upb_fielddef_type(f) != type) {
+ assert(false);
+ return false;
+ }
+ if (f->default_is_string) {
+ str_t *s = f->defaultval.bytes;
+ assert(s || type == UPB_TYPE_ENUM);
+ if (s) freestr(s);
+ }
+ f->default_is_string = false;
+ return true;
+}
+
+void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t value) {
+ if (checksetdefault(f, UPB_TYPE_INT64))
+ f->defaultval.sint = value;
+}
+
+void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t value) {
+ if ((upb_fielddef_type(f) == UPB_TYPE_ENUM &&
+ checksetdefault(f, UPB_TYPE_ENUM)) ||
+ checksetdefault(f, UPB_TYPE_INT32)) {
+ f->defaultval.sint = value;
+ }
+}
+
+void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t value) {
+ if (checksetdefault(f, UPB_TYPE_UINT64))
+ f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t value) {
+ if (checksetdefault(f, UPB_TYPE_UINT32))
+ f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultbool(upb_fielddef *f, bool value) {
+ if (checksetdefault(f, UPB_TYPE_BOOL))
+ f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultfloat(upb_fielddef *f, float value) {
+ if (checksetdefault(f, UPB_TYPE_FLOAT))
+ f->defaultval.flt = value;
+}
+
+void upb_fielddef_setdefaultdouble(upb_fielddef *f, double value) {
+ if (checksetdefault(f, UPB_TYPE_DOUBLE))
+ f->defaultval.dbl = value;
+}
+
+bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len,
+ upb_status *s) {
+ assert(upb_fielddef_isstring(f) || f->type_ == UPB_TYPE_ENUM);
+ if (f->type_ == UPB_TYPE_ENUM && !upb_isident(str, len, false, s))
+ return false;
+
+ if (f->default_is_string) {
+ str_t *s = f->defaultval.bytes;
+ assert(s || f->type_ == UPB_TYPE_ENUM);
+ if (s) freestr(s);
+ } else {
+ assert(f->type_ == UPB_TYPE_ENUM);
+ }
+
+ str_t *str2 = newstr(str, len);
+ f->defaultval.bytes = str2;
+ f->default_is_string = true;
+ return true;
+}
+
+void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str,
+ upb_status *s) {
+ assert(f->type_is_set_);
+ upb_fielddef_setdefaultstr(f, str, str ? strlen(str) : 0, s);
+}
+
+bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f) {
+ assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+ int32_t val;
+ return enumdefaultint32(f, &val);
+}
+
+bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f) {
+ assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+ return enumdefaultstr(f) != NULL;
+}
+
+static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef,
+ upb_status *s) {
+ if (f->type_ == UPB_TYPE_MESSAGE) {
+ if (upb_dyncast_msgdef(subdef)) return true;
+ upb_status_seterrmsg(s, "invalid subdef type for this submessage field");
+ return false;
+ } else if (f->type_ == UPB_TYPE_ENUM) {
+ if (upb_dyncast_enumdef(subdef)) return true;
+ upb_status_seterrmsg(s, "invalid subdef type for this enum field");
+ return false;
+ } else {
+ upb_status_seterrmsg(s, "only message and enum fields can have a subdef");
+ return false;
+ }
+}
+
+static void release_subdef(upb_fielddef *f) {
+ if (f->subdef_is_symbolic) {
+ free(f->sub.name);
+ } else if (f->sub.def) {
+ upb_unref2(f->sub.def, f);
+ }
+}
+
+bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef,
+ upb_status *s) {
+ assert(!upb_fielddef_isfrozen(f));
+ assert(upb_fielddef_hassubdef(f));
+ if (subdef && !upb_subdef_typecheck(f, subdef, s)) return false;
+ release_subdef(f);
+ f->sub.def = subdef;
+ f->subdef_is_symbolic = false;
+ if (f->sub.def) upb_ref2(f->sub.def, f);
+ return true;
+}
+
+bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef,
+ upb_status *s) {
+ return upb_fielddef_setsubdef(f, UPB_UPCAST(subdef), s);
+}
+
+bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef,
+ upb_status *s) {
+ return upb_fielddef_setsubdef(f, UPB_UPCAST(subdef), s);
+}
+
+bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
+ upb_status *s) {
+ assert(!upb_fielddef_isfrozen(f));
+ if (!upb_fielddef_hassubdef(f)) {
+ upb_status_seterrmsg(s, "field type does not accept a subdef");
+ return false;
+ }
+ // TODO: validate name (upb_isident() doesn't quite work atm because this name
+ // may have a leading ".").
+ release_subdef(f);
+ f->sub.name = upb_strdup(name);
+ f->subdef_is_symbolic = true;
+ return true;
+}
+
+bool upb_fielddef_issubmsg(const upb_fielddef *f) {
+ return upb_fielddef_type(f) == UPB_TYPE_MESSAGE;
+}
+
+bool upb_fielddef_isstring(const upb_fielddef *f) {
+ return upb_fielddef_type(f) == UPB_TYPE_STRING ||
+ upb_fielddef_type(f) == UPB_TYPE_BYTES;
+}
+
+bool upb_fielddef_isseq(const upb_fielddef *f) {
+ return upb_fielddef_label(f) == UPB_LABEL_REPEATED;
+}
+
+bool upb_fielddef_isprimitive(const upb_fielddef *f) {
+ return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f);
+}
+
+bool upb_fielddef_ismap(const upb_fielddef *f) {
+ return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) &&
+ upb_msgdef_mapentry(upb_fielddef_msgsubdef(f));
+}
+
+bool upb_fielddef_hassubdef(const upb_fielddef *f) {
+ return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM;
+}
+
+static bool between(int32_t x, int32_t low, int32_t high) {
+ return x >= low && x <= high;
+}
+
+bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); }
+bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); }
+bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); }
+
+bool upb_fielddef_checkdescriptortype(int32_t type) {
+ return between(type, 1, 18);
+}
+
+/* upb_msgdef *****************************************************************/
+
+static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit,
+ void *closure) {
+ const upb_msgdef *m = (const upb_msgdef*)r;
+ upb_msg_field_iter i;
+ for(upb_msg_field_begin(&i, m);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ upb_fielddef *f = upb_msg_iter_field(&i);
+ visit(r, UPB_UPCAST2(f), closure);
+ }
+ upb_msg_oneof_iter o;
+ for(upb_msg_oneof_begin(&o, m);
+ !upb_msg_oneof_done(&o);
+ upb_msg_oneof_next(&o)) {
+ upb_oneofdef *f = upb_msg_iter_oneof(&o);
+ visit(r, UPB_UPCAST2(f), closure);
+ }
+}
+
+static void freemsg(upb_refcounted *r) {
+ upb_msgdef *m = (upb_msgdef*)r;
+ upb_strtable_uninit(&m->ntoo);
+ upb_strtable_uninit(&m->ntof);
+ upb_inttable_uninit(&m->itof);
+ upb_def_uninit(UPB_UPCAST(m));
+ free(m);
+}
+
+upb_msgdef *upb_msgdef_new(const void *owner) {
+ static const struct upb_refcounted_vtbl vtbl = {visitmsg, freemsg};
+ upb_msgdef *m = malloc(sizeof(*m));
+ if (!m) return NULL;
+ if (!upb_def_init(UPB_UPCAST(m), UPB_DEF_MSG, &vtbl, owner)) goto err2;
+ if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err3;
+ if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err2;
+ if (!upb_strtable_init(&m->ntoo, UPB_CTYPE_PTR)) goto err1;
+ m->map_entry = false;
+ return m;
+
+err1:
+ upb_strtable_uninit(&m->ntof);
+err2:
+ upb_inttable_uninit(&m->itof);
+err3:
+ free(m);
+ return NULL;
+}
+
+upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) {
+ upb_msgdef *newm = upb_msgdef_new(owner);
+ if (!newm) return NULL;
+ bool ok = upb_def_setfullname(UPB_UPCAST(newm),
+ upb_def_fullname(UPB_UPCAST(m)), NULL);
+ newm->map_entry = m->map_entry;
+ UPB_ASSERT_VAR(ok, ok);
+ upb_msg_field_iter i;
+ for(upb_msg_field_begin(&i, m);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f);
+ // Fields in oneofs are dup'd below.
+ if (upb_fielddef_containingoneof(f)) continue;
+ if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) {
+ upb_msgdef_unref(newm, owner);
+ return NULL;
+ }
+ }
+ upb_msg_oneof_iter o;
+ for(upb_msg_oneof_begin(&o, m);
+ !upb_msg_oneof_done(&o);
+ upb_msg_oneof_next(&o)) {
+ upb_oneofdef *f = upb_oneofdef_dup(upb_msg_iter_oneof(&o), &f);
+ if (!f || !upb_msgdef_addoneof(newm, f, &f, NULL)) {
+ upb_msgdef_unref(newm, owner);
+ return NULL;
+ }
+ }
+ return newm;
+}
+
+bool upb_msgdef_isfrozen(const upb_msgdef *m) {
+ return upb_def_isfrozen(UPB_UPCAST(m));
+}
+
+void upb_msgdef_ref(const upb_msgdef *m, const void *owner) {
+ upb_def_ref(UPB_UPCAST(m), owner);
+}
+
+void upb_msgdef_unref(const upb_msgdef *m, const void *owner) {
+ upb_def_unref(UPB_UPCAST(m), owner);
+}
+
+void upb_msgdef_donateref(
+ const upb_msgdef *m, const void *from, const void *to) {
+ upb_def_donateref(UPB_UPCAST(m), from, to);
+}
+
+void upb_msgdef_checkref(const upb_msgdef *m, const void *owner) {
+ upb_def_checkref(UPB_UPCAST(m), owner);
+}
+
+bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status) {
+ upb_def *d = UPB_UPCAST(m);
+ return upb_def_freeze(&d, 1, status);
+}
+
+const char *upb_msgdef_fullname(const upb_msgdef *m) {
+ return upb_def_fullname(UPB_UPCAST(m));
+}
+
+bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname,
+ upb_status *s) {
+ return upb_def_setfullname(UPB_UPCAST(m), fullname, s);
+}
+
+// Helper: check that the field |f| is safe to add to msgdef |m|. Set an error
+// on status |s| and return false if not.
+static bool check_field_add(const upb_msgdef *m, const upb_fielddef *f,
+ upb_status *s) {
+ if (upb_fielddef_containingtype(f) != NULL) {
+ upb_status_seterrmsg(s, "fielddef already belongs to a message");
+ return false;
+ } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+ upb_status_seterrmsg(s, "field name or number were not set");
+ return false;
+ } else if (upb_msgdef_ntofz(m, upb_fielddef_name(f)) ||
+ upb_msgdef_itof(m, upb_fielddef_number(f))) {
+ upb_status_seterrmsg(s, "duplicate field name or number for field");
+ return false;
+ }
+ return true;
+}
+
+static void add_field(upb_msgdef *m, upb_fielddef *f, const void *ref_donor) {
+ release_containingtype(f);
+ f->msg.def = m;
+ f->msg_is_symbolic = false;
+ upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f));
+ upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f));
+ upb_ref2(f, m);
+ upb_ref2(m, f);
+ if (ref_donor) upb_fielddef_unref(f, ref_donor);
+}
+
+bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
+ upb_status *s) {
+ // TODO: extensions need to have a separate namespace, because proto2 allows a
+ // top-level extension (ie. one not in any package) to have the same name as a
+ // field from the message.
+ //
+ // This also implies that there needs to be a separate lookup-by-name method
+ // for extensions. It seems desirable for iteration to return both extensions
+ // and non-extensions though.
+ //
+ // We also need to validate that the field number is in an extension range iff
+ // it is an extension.
+
+ // This method is idempotent. Check if |f| is already part of this msgdef and
+ // return immediately if so.
+ if (upb_fielddef_containingtype(f) == m) {
+ return true;
+ }
+
+ // Check constraints for all fields before performing any action.
+ if (!check_field_add(m, f, s)) {
+ return false;
+ } else if (upb_fielddef_containingoneof(f) != NULL) {
+ // Fields in a oneof can only be added by adding the oneof to the msgdef.
+ upb_status_seterrmsg(s, "fielddef is part of a oneof");
+ return false;
+ }
+
+ // Constraint checks ok, perform the action.
+ add_field(m, f, ref_donor);
+ return true;
+}
+
+bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
+ upb_status *s) {
+ // Check various conditions that would prevent this oneof from being added.
+ if (upb_oneofdef_containingtype(o)) {
+ upb_status_seterrmsg(s, "oneofdef already belongs to a message");
+ return false;
+ } else if (upb_oneofdef_name(o) == NULL) {
+ upb_status_seterrmsg(s, "oneofdef name was not set");
+ return false;
+ } else if (upb_msgdef_ntooz(m, upb_oneofdef_name(o))) {
+ upb_status_seterrmsg(s, "duplicate oneof name");
+ return false;
+ }
+
+ // Check that all of the oneof's fields do not conflict with names or numbers
+ // of fields already in the message.
+ upb_oneof_iter it;
+ for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
+ const upb_fielddef *f = upb_oneof_iter_field(&it);
+ if (!check_field_add(m, f, s)) {
+ return false;
+ }
+ }
+
+ // Everything checks out -- commit now.
+
+ // Add oneof itself first.
+ o->parent = m;
+ upb_strtable_insert(&m->ntoo, upb_oneofdef_name(o), upb_value_ptr(o));
+ upb_ref2(o, m);
+ upb_ref2(m, o);
+
+ // Add each field of the oneof directly to the msgdef.
+ for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
+ upb_fielddef *f = upb_oneof_iter_field(&it);
+ add_field(m, f, NULL);
+ }
+
+ if (ref_donor) upb_oneofdef_unref(o, ref_donor);
+
+ return true;
+}
+
+const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) {
+ upb_value val;
+ return upb_inttable_lookup32(&m->itof, i, &val) ?
+ upb_value_getptr(val) : NULL;
+}
+
+const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
+ size_t len) {
+ upb_value val;
+ return upb_strtable_lookup2(&m->ntof, name, len, &val) ?
+ upb_value_getptr(val) : NULL;
+}
+
+const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
+ size_t len) {
+ upb_value val;
+ return upb_strtable_lookup2(&m->ntoo, name, len, &val) ?
+ upb_value_getptr(val) : NULL;
+}
+
+int upb_msgdef_numfields(const upb_msgdef *m) {
+ return upb_strtable_count(&m->ntof);
+}
+
+int upb_msgdef_numoneofs(const upb_msgdef *m) {
+ return upb_strtable_count(&m->ntoo);
+}
+
+void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry) {
+ assert(!upb_msgdef_isfrozen(m));
+ m->map_entry = map_entry;
+}
+
+bool upb_msgdef_mapentry(const upb_msgdef *m) {
+ return m->map_entry;
+}
+
+void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) {
+ upb_inttable_begin(iter, &m->itof);
+}
+
+void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); }
+
+bool upb_msg_field_done(const upb_msg_field_iter *iter) {
+ return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) {
+ return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
+}
+
+void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) {
+ upb_inttable_iter_setdone(iter);
+}
+
+void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) {
+ upb_strtable_begin(iter, &m->ntoo);
+}
+
+void upb_msg_oneof_next(upb_msg_oneof_iter *iter) { upb_strtable_next(iter); }
+
+bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) {
+ return upb_strtable_done(iter);
+}
+
+upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) {
+ return (upb_oneofdef*)upb_value_getptr(upb_strtable_iter_value(iter));
+}
+
+void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) {
+ upb_strtable_iter_setdone(iter);
+}
+
+/* upb_oneofdef ***************************************************************/
+
+static void visitoneof(const upb_refcounted *r, upb_refcounted_visit *visit,
+ void *closure) {
+ const upb_oneofdef *o = (const upb_oneofdef*)r;
+ upb_oneof_iter i;
+ for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+ const upb_fielddef *f = upb_oneof_iter_field(&i);
+ visit(r, UPB_UPCAST2(f), closure);
+ }
+ if (o->parent) {
+ visit(r, UPB_UPCAST2(o->parent), closure);
+ }
+}
+
+static void freeoneof(upb_refcounted *r) {
+ upb_oneofdef *o = (upb_oneofdef*)r;
+ upb_strtable_uninit(&o->ntof);
+ upb_inttable_uninit(&o->itof);
+ upb_def_uninit(UPB_UPCAST(o));
+ free(o);
+}
+
+upb_oneofdef *upb_oneofdef_new(const void *owner) {
+ static const struct upb_refcounted_vtbl vtbl = {visitoneof, freeoneof};
+ upb_oneofdef *o = malloc(sizeof(*o));
+ o->parent = NULL;
+ if (!o) return NULL;
+ if (!upb_def_init(UPB_UPCAST(o), UPB_DEF_ONEOF, &vtbl, owner)) goto err2;
+ if (!upb_inttable_init(&o->itof, UPB_CTYPE_PTR)) goto err2;
+ if (!upb_strtable_init(&o->ntof, UPB_CTYPE_PTR)) goto err1;
+ return o;
+
+err1:
+ upb_inttable_uninit(&o->itof);
+err2:
+ free(o);
+ return NULL;
+}
+
+upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner) {
+ upb_oneofdef *newo = upb_oneofdef_new(owner);
+ if (!newo) return NULL;
+ bool ok = upb_def_setfullname(UPB_UPCAST(newo),
+ upb_def_fullname(UPB_UPCAST(o)), NULL);
+ UPB_ASSERT_VAR(ok, ok);
+ upb_oneof_iter i;
+ for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+ upb_fielddef *f = upb_fielddef_dup(upb_oneof_iter_field(&i), &f);
+ if (!f || !upb_oneofdef_addfield(newo, f, &f, NULL)) {
+ upb_oneofdef_unref(newo, owner);
+ return NULL;
+ }
+ }
+ return newo;
+}
+
+bool upb_oneofdef_isfrozen(const upb_oneofdef *o) {
+ return upb_def_isfrozen(UPB_UPCAST(o));
+}
+
+void upb_oneofdef_ref(const upb_oneofdef *o, const void *owner) {
+ upb_def_ref(UPB_UPCAST(o), owner);
+}
+
+void upb_oneofdef_unref(const upb_oneofdef *o, const void *owner) {
+ upb_def_unref(UPB_UPCAST(o), owner);
+}
+
+void upb_oneofdef_donateref(const upb_oneofdef *o, const void *from,
+ const void *to) {
+ upb_def_donateref(UPB_UPCAST(o), from, to);
+}
+
+void upb_oneofdef_checkref(const upb_oneofdef *o, const void *owner) {
+ upb_def_checkref(UPB_UPCAST(o), owner);
+}
+
+const char *upb_oneofdef_name(const upb_oneofdef *o) {
+ return upb_def_fullname(UPB_UPCAST(o));
+}
+
+bool upb_oneofdef_setname(upb_oneofdef *o, const char *fullname,
+ upb_status *s) {
+ if (upb_oneofdef_containingtype(o)) {
+ upb_status_seterrmsg(s, "oneof already added to a message");
+ return false;
+ }
+ return upb_def_setfullname(UPB_UPCAST(o), fullname, s);
+}
+
+const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) {
+ return o->parent;
+}
+
+int upb_oneofdef_numfields(const upb_oneofdef *o) {
+ return upb_strtable_count(&o->ntof);
+}
+
+bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
+ const void *ref_donor,
+ upb_status *s) {
+ assert(!upb_oneofdef_isfrozen(o));
+ assert(!o->parent || !upb_msgdef_isfrozen(o->parent));
+
+ // This method is idempotent. Check if |f| is already part of this oneofdef
+ // and return immediately if so.
+ if (upb_fielddef_containingoneof(f) == o) {
+ return true;
+ }
+
+ // The field must have an OPTIONAL label.
+ if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) {
+ upb_status_seterrmsg(s, "fields in oneof must have OPTIONAL label");
+ return false;
+ }
+
+ // Check that no field with this name or number exists already in the oneof.
+ // Also check that the field is not already part of a oneof.
+ if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+ upb_status_seterrmsg(s, "field name or number were not set");
+ return false;
+ } else if (upb_oneofdef_itof(o, upb_fielddef_number(f)) ||
+ upb_oneofdef_ntofz(o, upb_fielddef_name(f))) {
+ upb_status_seterrmsg(s, "duplicate field name or number");
+ return false;
+ } else if (upb_fielddef_containingoneof(f) != NULL) {
+ upb_status_seterrmsg(s, "fielddef already belongs to a oneof");
+ return false;
+ }
+
+ // We allow adding a field to the oneof either if the field is not part of a
+ // msgdef, or if it is and we are also part of the same msgdef.
+ if (o->parent == NULL) {
+ // If we're not in a msgdef, the field cannot be either. Otherwise we would
+ // need to magically add this oneof to a msgdef to remain consistent, which
+ // is surprising behavior.
+ if (upb_fielddef_containingtype(f) != NULL) {
+ upb_status_seterrmsg(s, "fielddef already belongs to a message, but "
+ "oneof does not");
+ return false;
+ }
+ } else {
+ // If we're in a msgdef, the user can add fields that either aren't in any
+ // msgdef (in which case they're added to our msgdef) or already a part of
+ // our msgdef.
+ if (upb_fielddef_containingtype(f) != NULL &&
+ upb_fielddef_containingtype(f) != o->parent) {
+ upb_status_seterrmsg(s, "fielddef belongs to a different message "
+ "than oneof");
+ return false;
+ }
+ }
+
+ // Commit phase. First add the field to our parent msgdef, if any, because
+ // that may fail; then add the field to our own tables.
+
+ if (o->parent != NULL && upb_fielddef_containingtype(f) == NULL) {
+ if (!upb_msgdef_addfield((upb_msgdef*)o->parent, f, NULL, s)) {
+ return false;
+ }
+ }
+
+ release_containingtype(f);
+ f->oneof = o;
+ upb_inttable_insert(&o->itof, upb_fielddef_number(f), upb_value_ptr(f));
+ upb_strtable_insert(&o->ntof, upb_fielddef_name(f), upb_value_ptr(f));
+ upb_ref2(f, o);
+ upb_ref2(o, f);
+ if (ref_donor) upb_fielddef_unref(f, ref_donor);
+
+ return true;
+}
+
+const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
+ const char *name, size_t length) {
+ upb_value val;
+ return upb_strtable_lookup2(&o->ntof, name, length, &val) ?
+ upb_value_getptr(val) : NULL;
+}
+
+const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) {
+ upb_value val;
+ return upb_inttable_lookup32(&o->itof, num, &val) ?
+ upb_value_getptr(val) : NULL;
+}
+
+void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) {
+ upb_inttable_begin(iter, &o->itof);
+}
+
+void upb_oneof_next(upb_oneof_iter *iter) {
+ upb_inttable_next(iter);
+}
+
+bool upb_oneof_done(upb_oneof_iter *iter) {
+ return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) {
+ return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
+}
+
+void upb_oneof_iter_setdone(upb_oneof_iter *iter) {
+ upb_inttable_iter_setdone(iter);
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * TODO(haberman): it's unclear whether a lot of the consistency checks should
+ * assert() or return false.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+// Defined for the sole purpose of having a unique pointer value for
+// UPB_NO_CLOSURE.
+char _upb_noclosure;
+
+static void freehandlers(upb_refcounted *r) {
+ upb_handlers *h = (upb_handlers*)r;
+
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &h->cleanup_);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ void *val = (void*)upb_inttable_iter_key(&i);
+ upb_value func_val = upb_inttable_iter_value(&i);
+ upb_handlerfree *func = upb_value_getfptr(func_val);
+ func(val);
+ }
+
+ upb_inttable_uninit(&h->cleanup_);
+ upb_msgdef_unref(h->msg, h);
+ free(h->sub);
+ free(h);
+}
+
+static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit,
+ void *closure) {
+ const upb_handlers *h = (const upb_handlers*)r;
+ upb_msg_field_iter i;
+ for(upb_msg_field_begin(&i, h->msg);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ upb_fielddef *f = upb_msg_iter_field(&i);
+ if (!upb_fielddef_issubmsg(f)) continue;
+ const upb_handlers *sub = upb_handlers_getsubhandlers(h, f);
+ if (sub) visit(r, UPB_UPCAST(sub), closure);
+ }
+}
+
+static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers};
+
+typedef struct {
+ upb_inttable tab; // maps upb_msgdef* -> upb_handlers*.
+ upb_handlers_callback *callback;
+ const void *closure;
+} dfs_state;
+
+// TODO(haberman): discard upb_handlers* objects that do not actually have any
+// handlers set and cannot reach any upb_handlers* object that does. This is
+// slightly tricky to do correctly.
+static upb_handlers *newformsg(const upb_msgdef *m, const void *owner,
+ dfs_state *s) {
+ upb_handlers *h = upb_handlers_new(m, owner);
+ if (!h) return NULL;
+ if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
+
+ s->callback(s->closure, h);
+
+ // For each submessage field, get or create a handlers object and set it as
+ // the subhandlers.
+ upb_msg_field_iter i;
+ for(upb_msg_field_begin(&i, m);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ upb_fielddef *f = upb_msg_iter_field(&i);
+ if (!upb_fielddef_issubmsg(f)) continue;
+
+ const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f));
+ upb_value subm_ent;
+ if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) {
+ upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent));
+ } else {
+ upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s);
+ if (!sub_mh) goto oom;
+ upb_handlers_setsubhandlers(h, f, sub_mh);
+ upb_handlers_unref(sub_mh, &sub_mh);
+ }
+ }
+ return h;
+
+oom:
+ upb_handlers_unref(h, owner);
+ return NULL;
+}
+
+// Given a selector for a STARTSUBMSG handler, resolves to a pointer to the
+// subhandlers for this submessage field.
+#define SUBH(h, selector) (h->sub[selector])
+
+// The selector for a submessage field is the field index.
+#define SUBH_F(h, f) SUBH(h, f->index_)
+
+static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f,
+ upb_handlertype_t type) {
+ upb_selector_t sel;
+ assert(!upb_handlers_isfrozen(h));
+ if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) {
+ upb_status_seterrf(
+ &h->status_, "type mismatch: field %s does not belong to message %s",
+ upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h)));
+ return -1;
+ }
+ if (!upb_handlers_getselector(f, type, &sel)) {
+ upb_status_seterrf(
+ &h->status_,
+ "type mismatch: cannot register handler type %d for field %s",
+ type, upb_fielddef_name(f));
+ return -1;
+ }
+ return sel;
+}
+
+static upb_selector_t handlers_getsel(upb_handlers *h, const upb_fielddef *f,
+ upb_handlertype_t type) {
+ int32_t sel = trygetsel(h, f, type);
+ assert(sel >= 0);
+ return sel;
+}
+
+static const void **returntype(upb_handlers *h, const upb_fielddef *f,
+ upb_handlertype_t type) {
+ return &h->table[handlers_getsel(h, f, type)].attr.return_closure_type_;
+}
+
+static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f,
+ upb_handlertype_t type, upb_func *func,
+ upb_handlerattr *attr) {
+ assert(!upb_handlers_isfrozen(h));
+
+ if (sel < 0) {
+ upb_status_seterrmsg(&h->status_,
+ "incorrect handler type for this field.");
+ return false;
+ }
+
+ if (h->table[sel].func) {
+ upb_status_seterrmsg(&h->status_,
+ "cannot change handler once it has been set.");
+ return false;
+ }
+
+ upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER;
+ if (attr) {
+ set_attr = *attr;
+ }
+
+ // Check that the given closure type matches the closure type that has been
+ // established for this context (if any).
+ const void *closure_type = upb_handlerattr_closuretype(&set_attr);
+ const void **context_closure_type;
+
+ if (type == UPB_HANDLER_STRING) {
+ context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR);
+ } else if (f && upb_fielddef_isseq(f) &&
+ type != UPB_HANDLER_STARTSEQ &&
+ type != UPB_HANDLER_ENDSEQ) {
+ context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ);
+ } else {
+ context_closure_type = &h->top_closure_type;
+ }
+
+ if (closure_type && *context_closure_type &&
+ closure_type != *context_closure_type) {
+ // TODO(haberman): better message for debugging.
+ upb_status_seterrmsg(&h->status_, "closure type does not match");
+ return false;
+ }
+
+ if (closure_type)
+ *context_closure_type = closure_type;
+
+ // If this is a STARTSEQ or STARTSTR handler, check that the returned pointer
+ // matches any pre-existing expectations about what type is expected.
+ if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) {
+ const void *return_type = upb_handlerattr_returnclosuretype(&set_attr);
+ const void *table_return_type =
+ upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+ if (return_type && table_return_type && return_type != table_return_type) {
+ upb_status_seterrmsg(&h->status_, "closure return type does not match");
+ return false;
+ }
+
+ if (table_return_type && !return_type)
+ upb_handlerattr_setreturnclosuretype(&set_attr, table_return_type);
+ }
+
+ h->table[sel].func = (upb_func*)func;
+ h->table[sel].attr = set_attr;
+ return true;
+}
+
+// Returns the effective closure type for this handler (which will propagate
+// from outer frames if this frame has no START* handler). Not implemented for
+// UPB_HANDLER_STRING at the moment since this is not needed. Returns NULL is
+// the effective closure type is unspecified (either no handler was registered
+// to specify it or the handler that was registered did not specify the closure
+// type).
+const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f,
+ upb_handlertype_t type) {
+ assert(type != UPB_HANDLER_STRING);
+ const void *ret = h->top_closure_type;
+ upb_selector_t sel;
+ if (upb_fielddef_isseq(f) &&
+ type != UPB_HANDLER_STARTSEQ &&
+ type != UPB_HANDLER_ENDSEQ &&
+ h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)].func) {
+ ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+ }
+
+ if (type == UPB_HANDLER_STRING &&
+ h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSTR)].func) {
+ ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+ }
+
+ // The effective type of the submessage; not used yet.
+ // if (type == SUBMESSAGE &&
+ // h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) {
+ // ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+ // }
+
+ return ret;
+}
+
+// Checks whether the START* handler specified by f & type is missing even
+// though it is required to convert the established type of an outer frame
+// ("closure_type") into the established type of an inner frame (represented in
+// the return closure type of this handler's attr.
+bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type,
+ upb_status *status) {
+ upb_selector_t sel = handlers_getsel(h, f, type);
+ if (h->table[sel].func) return true;
+ const void *closure_type = effective_closure_type(h, f, type);
+ const upb_handlerattr *attr = &h->table[sel].attr;
+ const void *return_closure_type = upb_handlerattr_returnclosuretype(attr);
+ if (closure_type && return_closure_type &&
+ closure_type != return_closure_type) {
+ upb_status_seterrf(status,
+ "expected start handler to return sub type for field %f",
+ upb_fielddef_name(f));
+ return false;
+ }
+ return true;
+}
+
+/* Public interface ***********************************************************/
+
+bool upb_handlers_isfrozen(const upb_handlers *h) {
+ return upb_refcounted_isfrozen(UPB_UPCAST(h));
+}
+
+void upb_handlers_ref(const upb_handlers *h, const void *owner) {
+ upb_refcounted_ref(UPB_UPCAST(h), owner);
+}
+
+void upb_handlers_unref(const upb_handlers *h, const void *owner) {
+ upb_refcounted_unref(UPB_UPCAST(h), owner);
+}
+
+void upb_handlers_donateref(
+ const upb_handlers *h, const void *from, const void *to) {
+ upb_refcounted_donateref(UPB_UPCAST(h), from, to);
+}
+
+void upb_handlers_checkref(const upb_handlers *h, const void *owner) {
+ upb_refcounted_checkref(UPB_UPCAST(h), owner);
+}
+
+upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) {
+ assert(upb_msgdef_isfrozen(md));
+
+ int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1);
+ upb_handlers *h = calloc(sizeof(*h) + extra, 1);
+ if (!h) return NULL;
+
+ h->msg = md;
+ upb_msgdef_ref(h->msg, h);
+ upb_status_clear(&h->status_);
+ h->sub = calloc(md->submsg_field_count, sizeof(*h->sub));
+ if (!h->sub) goto oom;
+ if (!upb_refcounted_init(UPB_UPCAST(h), &vtbl, owner)) goto oom;
+ if (!upb_inttable_init(&h->cleanup_, UPB_CTYPE_FPTR)) goto oom;
+
+ // calloc() above initialized all handlers to NULL.
+ return h;
+
+oom:
+ freehandlers(UPB_UPCAST(h));
+ return NULL;
+}
+
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+ const void *owner,
+ upb_handlers_callback *callback,
+ const void *closure) {
+ dfs_state state;
+ state.callback = callback;
+ state.closure = closure;
+ if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL;
+
+ upb_handlers *ret = newformsg(m, owner, &state);
+
+ upb_inttable_uninit(&state.tab);
+ if (!ret) return NULL;
+
+ upb_refcounted *r = UPB_UPCAST(ret);
+ bool ok = upb_refcounted_freeze(&r, 1, NULL, UPB_MAX_HANDLER_DEPTH);
+ UPB_ASSERT_VAR(ok, ok);
+
+ return ret;
+}
+
+const upb_status *upb_handlers_status(upb_handlers *h) {
+ assert(!upb_handlers_isfrozen(h));
+ return &h->status_;
+}
+
+void upb_handlers_clearerr(upb_handlers *h) {
+ assert(!upb_handlers_isfrozen(h));
+ upb_status_clear(&h->status_);
+}
+
+#define SETTER(name, handlerctype, handlertype) \
+ bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
+ handlerctype func, upb_handlerattr *attr) { \
+ int32_t sel = trygetsel(h, f, handlertype); \
+ return doset(h, sel, f, handlertype, (upb_func*)func, attr); \
+ }
+
+SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32);
+SETTER(int64, upb_int64_handlerfunc*, UPB_HANDLER_INT64);
+SETTER(uint32, upb_uint32_handlerfunc*, UPB_HANDLER_UINT32);
+SETTER(uint64, upb_uint64_handlerfunc*, UPB_HANDLER_UINT64);
+SETTER(float, upb_float_handlerfunc*, UPB_HANDLER_FLOAT);
+SETTER(double, upb_double_handlerfunc*, UPB_HANDLER_DOUBLE);
+SETTER(bool, upb_bool_handlerfunc*, UPB_HANDLER_BOOL);
+SETTER(startstr, upb_startstr_handlerfunc*, UPB_HANDLER_STARTSTR);
+SETTER(string, upb_string_handlerfunc*, UPB_HANDLER_STRING);
+SETTER(endstr, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSTR);
+SETTER(startseq, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSEQ);
+SETTER(startsubmsg, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSUBMSG);
+SETTER(endsubmsg, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSUBMSG);
+SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ);
+
+#undef SETTER
+
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+ upb_handlerattr *attr) {
+ return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
+ (upb_func *)func, attr);
+}
+
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+ upb_handlerattr *attr) {
+ assert(!upb_handlers_isfrozen(h));
+ return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
+ (upb_func *)func, attr);
+}
+
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+ const upb_handlers *sub) {
+ assert(sub);
+ assert(!upb_handlers_isfrozen(h));
+ assert(upb_fielddef_issubmsg(f));
+ if (SUBH_F(h, f)) return false; // Can't reset.
+ if (UPB_UPCAST(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) {
+ return false;
+ }
+ SUBH_F(h, f) = sub;
+ upb_ref2(sub, h);
+ return true;
+}
+
+const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
+ const upb_fielddef *f) {
+ assert(upb_fielddef_issubmsg(f));
+ return SUBH_F(h, f);
+}
+
+bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel,
+ upb_handlerattr *attr) {
+ if (!upb_handlers_gethandler(h, sel))
+ return false;
+ *attr = h->table[sel].attr;
+ return true;
+}
+
+const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
+ upb_selector_t sel) {
+ // STARTSUBMSG selector in sel is the field's selector base.
+ return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT);
+}
+
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; }
+
+bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *func) {
+ if (upb_inttable_lookupptr(&h->cleanup_, p, NULL)) {
+ return false;
+ }
+ bool ok = upb_inttable_insertptr(&h->cleanup_, p, upb_value_fptr(func));
+ UPB_ASSERT_VAR(ok, ok);
+ return true;
+}
+
+
+/* "Static" methods ***********************************************************/
+
+bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
+ // TODO: verify we have a transitive closure.
+ for (int i = 0; i < n; i++) {
+ upb_handlers *h = handlers[i];
+
+ if (!upb_ok(&h->status_)) {
+ upb_status_seterrf(s, "handlers for message %s had error status: %s",
+ upb_msgdef_fullname(upb_handlers_msgdef(h)),
+ upb_status_errmsg(&h->status_));
+ return false;
+ }
+
+ // Check that there are no closure mismatches due to missing Start* handlers
+ // or subhandlers with different type-level types.
+ upb_msg_field_iter j;
+ for(upb_msg_field_begin(&j, h->msg);
+ !upb_msg_field_done(&j);
+ upb_msg_field_next(&j)) {
+
+ const upb_fielddef *f = upb_msg_iter_field(&j);
+ if (upb_fielddef_isseq(f)) {
+ if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s))
+ return false;
+ }
+
+ if (upb_fielddef_isstring(f)) {
+ if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s))
+ return false;
+ }
+
+ if (upb_fielddef_issubmsg(f)) {
+ bool hashandler = false;
+ if (upb_handlers_gethandler(
+ h, handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)) ||
+ upb_handlers_gethandler(
+ h, handlers_getsel(h, f, UPB_HANDLER_ENDSUBMSG))) {
+ hashandler = true;
+ }
+
+ if (upb_fielddef_isseq(f) &&
+ (upb_handlers_gethandler(
+ h, handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)) ||
+ upb_handlers_gethandler(
+ h, handlers_getsel(h, f, UPB_HANDLER_ENDSEQ)))) {
+ hashandler = true;
+ }
+
+ if (hashandler && !upb_handlers_getsubhandlers(h, f)) {
+ // For now we add an empty subhandlers in this case. It makes the
+ // decoder code generator simpler, because it only has to handle two
+ // cases (submessage has handlers or not) as opposed to three
+ // (submessage has handlers in enclosing message but no subhandlers).
+ //
+ // This makes parsing less efficient in the case that we want to
+ // notice a submessage but skip its contents (like if we're testing
+ // for submessage presence or counting the number of repeated
+ // submessages). In this case we will end up parsing the submessage
+ // field by field and throwing away the results for each, instead of
+ // skipping the whole delimited thing at once. If this is an issue we
+ // can revisit it, but do remember that this only arises when you have
+ // handlers (startseq/startsubmsg/endsubmsg/endseq) set for the
+ // submessage but no subhandlers. The uses cases for this are
+ // limited.
+ upb_handlers *sub = upb_handlers_new(upb_fielddef_msgsubdef(f), &sub);
+ upb_handlers_setsubhandlers(h, f, sub);
+ upb_handlers_unref(sub, &sub);
+ }
+
+ // TODO(haberman): check type of submessage.
+ // This is slightly tricky; also consider whether we should check that
+ // they match at setsubhandlers time.
+ }
+ }
+ }
+
+ if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s,
+ UPB_MAX_HANDLER_DEPTH)) {
+ return false;
+ }
+
+ return true;
+}
+
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) {
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_ENUM: return UPB_HANDLER_INT32;
+ case UPB_TYPE_INT64: return UPB_HANDLER_INT64;
+ case UPB_TYPE_UINT32: return UPB_HANDLER_UINT32;
+ case UPB_TYPE_UINT64: return UPB_HANDLER_UINT64;
+ case UPB_TYPE_FLOAT: return UPB_HANDLER_FLOAT;
+ case UPB_TYPE_DOUBLE: return UPB_HANDLER_DOUBLE;
+ case UPB_TYPE_BOOL: return UPB_HANDLER_BOOL;
+ default: assert(false); return -1; // Invalid input.
+ }
+}
+
+bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
+ upb_selector_t *s) {
+ switch (type) {
+ case UPB_HANDLER_INT32:
+ case UPB_HANDLER_INT64:
+ case UPB_HANDLER_UINT32:
+ case UPB_HANDLER_UINT64:
+ case UPB_HANDLER_FLOAT:
+ case UPB_HANDLER_DOUBLE:
+ case UPB_HANDLER_BOOL:
+ if (!upb_fielddef_isprimitive(f) ||
+ upb_handlers_getprimitivehandlertype(f) != type)
+ return false;
+ *s = f->selector_base;
+ break;
+ case UPB_HANDLER_STRING:
+ if (upb_fielddef_isstring(f)) {
+ *s = f->selector_base;
+ } else if (upb_fielddef_lazy(f)) {
+ *s = f->selector_base + 3;
+ } else {
+ return false;
+ }
+ break;
+ case UPB_HANDLER_STARTSTR:
+ if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
+ *s = f->selector_base + 1;
+ } else {
+ return false;
+ }
+ break;
+ case UPB_HANDLER_ENDSTR:
+ if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
+ *s = f->selector_base + 2;
+ } else {
+ return false;
+ }
+ break;
+ case UPB_HANDLER_STARTSEQ:
+ if (!upb_fielddef_isseq(f)) return false;
+ *s = f->selector_base - 2;
+ break;
+ case UPB_HANDLER_ENDSEQ:
+ if (!upb_fielddef_isseq(f)) return false;
+ *s = f->selector_base - 1;
+ break;
+ case UPB_HANDLER_STARTSUBMSG:
+ if (!upb_fielddef_issubmsg(f)) return false;
+ // Selectors for STARTSUBMSG are at the beginning of the table so that the
+ // selector can also be used as an index into the "sub" array of
+ // subhandlers. The indexes for the two into these two tables are the
+ // same, except that in the handler table the static selectors come first.
+ *s = f->index_ + UPB_STATIC_SELECTOR_COUNT;
+ break;
+ case UPB_HANDLER_ENDSUBMSG:
+ if (!upb_fielddef_issubmsg(f)) return false;
+ *s = f->selector_base;
+ break;
+ }
+ assert(*s < upb_fielddef_containingtype(f)->selector_count);
+ return true;
+}
+
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
+ return upb_fielddef_isseq(f) ? 2 : 0;
+}
+
+uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
+ uint32_t ret = 1;
+ if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ
+ if (upb_fielddef_isstring(f)) ret += 2; // [STRING]/STARTSTR/ENDSTR
+ if (upb_fielddef_issubmsg(f)) {
+ // ENDSUBMSG (STARTSUBMSG is at table beginning)
+ ret += 0;
+ if (upb_fielddef_lazy(f)) {
+ // STARTSTR/ENDSTR/STRING (for lazy)
+ ret += 3;
+ }
+ }
+ return ret;
+}
+
+
+/* upb_handlerattr ************************************************************/
+
+void upb_handlerattr_init(upb_handlerattr *attr) {
+ upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER;
+ memcpy(attr, &from, sizeof(*attr));
+}
+
+void upb_handlerattr_uninit(upb_handlerattr *attr) {
+ UPB_UNUSED(attr);
+}
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd) {
+ attr->handler_data_ = hd;
+ return true;
+}
+
+bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type) {
+ attr->closure_type_ = type;
+ return true;
+}
+
+const void *upb_handlerattr_closuretype(const upb_handlerattr *attr) {
+ return attr->closure_type_;
+}
+
+bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr,
+ const void *type) {
+ attr->return_closure_type_ = type;
+ return true;
+}
+
+const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr) {
+ return attr->return_closure_type_;
+}
+
+bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok) {
+ attr->alwaysok_ = alwaysok;
+ return true;
+}
+
+bool upb_handlerattr_alwaysok(const upb_handlerattr *attr) {
+ return attr->alwaysok_;
+}
+
+/* upb_bufhandle **************************************************************/
+
+size_t upb_bufhandle_objofs(const upb_bufhandle *h) {
+ return h->objofs_;
+}
+
+/* upb_byteshandler ***********************************************************/
+
+void upb_byteshandler_init(upb_byteshandler* h) {
+ memset(h, 0, sizeof(*h));
+}
+
+// For when we support handlerfree callbacks.
+void upb_byteshandler_uninit(upb_byteshandler* h) {
+ UPB_UNUSED(h);
+}
+
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+ upb_startstr_handlerfunc *func, void *d) {
+ h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func;
+ h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d;
+ return true;
+}
+
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+ upb_string_handlerfunc *func, void *d) {
+ h->table[UPB_STRING_SELECTOR].func = (upb_func*)func;
+ h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d;
+ return true;
+}
+
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+ upb_endfield_handlerfunc *func, void *d) {
+ h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func;
+ h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d;
+ return true;
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * Our key invariants are:
+ * 1. reference cycles never span groups
+ * 2. for ref2(to, from), we increment to's count iff group(from) != group(to)
+ *
+ * The previous two are how we avoid leaking cycles. Other important
+ * invariants are:
+ * 3. for mutable objects "from" and "to", if there exists a ref2(to, from)
+ * this implies group(from) == group(to). (In practice, what we implement
+ * is even stronger; "from" and "to" will share a group if there has *ever*
+ * been a ref2(to, from), but all that is necessary for correctness is the
+ * weaker one).
+ * 4. mutable and immutable objects are never in the same group.
+ */
+
+
+#include <setjmp.h>
+#include <stdlib.h>
+
+static void freeobj(upb_refcounted *o);
+
+const char untracked_val;
+const void *UPB_UNTRACKED_REF = &untracked_val;
+
+/* arch-specific atomic primitives *******************************************/
+
+#ifdef UPB_THREAD_UNSAFE //////////////////////////////////////////////////////
+
+static void atomic_inc(uint32_t *a) { (*a)++; }
+static bool atomic_dec(uint32_t *a) { return --(*a) == 0; }
+
+#elif defined(__GNUC__) || defined(__clang__) //////////////////////////////////
+
+static void atomic_inc(uint32_t *a) { __sync_fetch_and_add(a, 1); }
+static bool atomic_dec(uint32_t *a) { return __sync_sub_and_fetch(a, 1) == 0; }
+
+#elif defined(WIN32) ///////////////////////////////////////////////////////////
+
+#include <Windows.h>
+
+static void atomic_inc(upb_atomic_t *a) { InterlockedIncrement(&a->val); }
+static bool atomic_dec(upb_atomic_t *a) {
+ return InterlockedDecrement(&a->val) == 0;
+}
+
+#else
+#error Atomic primitives not defined for your platform/CPU. \
+ Implement them or compile with UPB_THREAD_UNSAFE.
+#endif
+
+// All static objects point to this refcount.
+// It is special-cased in ref/unref below.
+uint32_t static_refcount = -1;
+
+// We can avoid atomic ops for statically-declared objects.
+// This is a minor optimization but nice since we can avoid degrading under
+// contention in this case.
+
+static void refgroup(uint32_t *group) {
+ if (group != &static_refcount)
+ atomic_inc(group);
+}
+
+static bool unrefgroup(uint32_t *group) {
+ if (group == &static_refcount) {
+ return false;
+ } else {
+ return atomic_dec(group);
+ }
+}
+
+
+/* Reference tracking (debug only) ********************************************/
+
+#ifdef UPB_DEBUG_REFS
+
+#ifdef UPB_THREAD_UNSAFE
+
+static void upb_lock() {}
+static void upb_unlock() {}
+
+#else
+
+// User must define functions that lock/unlock a global mutex and link this
+// file against them.
+void upb_lock();
+void upb_unlock();
+
+#endif
+
+// UPB_DEBUG_REFS mode counts on being able to malloc() memory in some
+// code-paths that can normally never fail, like upb_refcounted_ref(). Since
+// we have no way to propagage out-of-memory errors back to the user, and since
+// these errors can only occur in UPB_DEBUG_REFS mode, we immediately fail.
+#define CHECK_OOM(predicate) if (!(predicate)) { assert(predicate); exit(1); }
+
+typedef struct {
+ int count; // How many refs there are (duplicates only allowed for ref2).
+ bool is_ref2;
+} trackedref;
+
+static trackedref *trackedref_new(bool is_ref2) {
+ trackedref *ret = malloc(sizeof(*ret));
+ CHECK_OOM(ret);
+ ret->count = 1;
+ ret->is_ref2 = is_ref2;
+ return ret;
+}
+
+static void track(const upb_refcounted *r, const void *owner, bool ref2) {
+ assert(owner);
+ if (owner == UPB_UNTRACKED_REF) return;
+
+ upb_lock();
+ upb_value v;
+ if (upb_inttable_lookupptr(r->refs, owner, &v)) {
+ trackedref *ref = upb_value_getptr(v);
+ // Since we allow multiple ref2's for the same to/from pair without
+ // allocating separate memory for each one, we lose the fine-grained
+ // tracking behavior we get with regular refs. Since ref2s only happen
+ // inside upb, we'll accept this limitation until/unless there is a really
+ // difficult upb-internal bug that can't be figured out without it.
+ assert(ref2);
+ assert(ref->is_ref2);
+ ref->count++;
+ } else {
+ trackedref *ref = trackedref_new(ref2);
+ bool ok = upb_inttable_insertptr(r->refs, owner, upb_value_ptr(ref));
+ CHECK_OOM(ok);
+ if (ref2) {
+ // We know this cast is safe when it is a ref2, because it's coming from
+ // another refcounted object.
+ const upb_refcounted *from = owner;
+ assert(!upb_inttable_lookupptr(from->ref2s, r, NULL));
+ ok = upb_inttable_insertptr(from->ref2s, r, upb_value_ptr(NULL));
+ CHECK_OOM(ok);
+ }
+ }
+ upb_unlock();
+}
+
+static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
+ assert(owner);
+ if (owner == UPB_UNTRACKED_REF) return;
+
+ upb_lock();
+ upb_value v;
+ bool found = upb_inttable_lookupptr(r->refs, owner, &v);
+ // This assert will fail if an owner attempts to release a ref it didn't have.
+ UPB_ASSERT_VAR(found, found);
+ trackedref *ref = upb_value_getptr(v);
+ assert(ref->is_ref2 == ref2);
+ if (--ref->count == 0) {
+ free(ref);
+ upb_inttable_removeptr(r->refs, owner, NULL);
+ if (ref2) {
+ // We know this cast is safe when it is a ref2, because it's coming from
+ // another refcounted object.
+ const upb_refcounted *from = owner;
+ bool removed = upb_inttable_removeptr(from->ref2s, r, NULL);
+ assert(removed);
+ }
+ }
+ upb_unlock();
+}
+
+static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
+ upb_lock();
+ upb_value v;
+ bool found = upb_inttable_lookupptr(r->refs, owner, &v);
+ UPB_ASSERT_VAR(found, found);
+ trackedref *ref = upb_value_getptr(v);
+ assert(ref->is_ref2 == ref2);
+ upb_unlock();
+}
+
+// Populates the given UPB_CTYPE_INT32 inttable with counts of ref2's that
+// originate from the given owner.
+static void getref2s(const upb_refcounted *owner, upb_inttable *tab) {
+ upb_lock();
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, owner->ref2s);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ upb_refcounted *to = (upb_refcounted*)upb_inttable_iter_key(&i);
+
+ // To get the count we need to look in the target's table.
+ upb_value v;
+ bool found = upb_inttable_lookupptr(to->refs, owner, &v);
+ assert(found);
+ trackedref *ref = upb_value_getptr(v);
+ upb_value count = upb_value_int32(ref->count);
+
+ bool ok = upb_inttable_insertptr(tab, to, count);
+ CHECK_OOM(ok);
+ }
+ upb_unlock();
+}
+
+typedef struct {
+ upb_inttable ref2;
+ const upb_refcounted *obj;
+} check_state;
+
+static void visit_check(const upb_refcounted *obj, const upb_refcounted *subobj,
+ void *closure) {
+ check_state *s = closure;
+ assert(obj == s->obj);
+ assert(subobj);
+ upb_inttable *ref2 = &s->ref2;
+ upb_value v;
+ bool removed = upb_inttable_removeptr(ref2, subobj, &v);
+ // The following assertion will fail if the visit() function visits a subobj
+ // that it did not have a ref2 on, or visits the same subobj too many times.
+ assert(removed);
+ int32_t newcount = upb_value_getint32(v) - 1;
+ if (newcount > 0) {
+ upb_inttable_insert(ref2, (uintptr_t)subobj, upb_value_int32(newcount));
+ }
+}
+
+static void visit(const upb_refcounted *r, upb_refcounted_visit *v,
+ void *closure) {
+ // In DEBUG_REFS mode we know what existing ref2 refs there are, so we know
+ // exactly the set of nodes that visit() should visit. So we verify visit()'s
+ // correctness here.
+ check_state state;
+ state.obj = r;
+ bool ok = upb_inttable_init(&state.ref2, UPB_CTYPE_INT32);
+ CHECK_OOM(ok);
+ getref2s(r, &state.ref2);
+
+ // This should visit any children in the ref2 table.
+ if (r->vtbl->visit) r->vtbl->visit(r, visit_check, &state);
+
+ // This assertion will fail if the visit() function missed any children.
+ assert(upb_inttable_count(&state.ref2) == 0);
+ upb_inttable_uninit(&state.ref2);
+ if (r->vtbl->visit) r->vtbl->visit(r, v, closure);
+}
+
+static bool trackinit(upb_refcounted *r) {
+ r->refs = malloc(sizeof(*r->refs));
+ r->ref2s = malloc(sizeof(*r->ref2s));
+ if (!r->refs || !r->ref2s) goto err1;
+
+ if (!upb_inttable_init(r->refs, UPB_CTYPE_PTR)) goto err1;
+ if (!upb_inttable_init(r->ref2s, UPB_CTYPE_PTR)) goto err2;
+ return true;
+
+err2:
+ upb_inttable_uninit(r->refs);
+err1:
+ free(r->refs);
+ free(r->ref2s);
+ return false;
+}
+
+static void trackfree(const upb_refcounted *r) {
+ upb_inttable_uninit(r->refs);
+ upb_inttable_uninit(r->ref2s);
+ free(r->refs);
+ free(r->ref2s);
+}
+
+#else
+
+static void track(const upb_refcounted *r, const void *owner, bool ref2) {
+ UPB_UNUSED(r);
+ UPB_UNUSED(owner);
+ UPB_UNUSED(ref2);
+}
+
+static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
+ UPB_UNUSED(r);
+ UPB_UNUSED(owner);
+ UPB_UNUSED(ref2);
+}
+
+static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
+ UPB_UNUSED(r);
+ UPB_UNUSED(owner);
+ UPB_UNUSED(ref2);
+}
+
+static bool trackinit(upb_refcounted *r) {
+ UPB_UNUSED(r);
+ return true;
+}
+
+static void trackfree(const upb_refcounted *r) {
+ UPB_UNUSED(r);
+}
+
+static void visit(const upb_refcounted *r, upb_refcounted_visit *v,
+ void *closure) {
+ if (r->vtbl->visit) r->vtbl->visit(r, v, closure);
+}
+
+#endif // UPB_DEBUG_REFS
+
+
+/* freeze() *******************************************************************/
+
+// The freeze() operation is by far the most complicated part of this scheme.
+// We compute strongly-connected components and then mutate the graph such that
+// we preserve the invariants documented at the top of this file. And we must
+// handle out-of-memory errors gracefully (without leaving the graph
+// inconsistent), which adds to the fun.
+
+// The state used by the freeze operation (shared across many functions).
+typedef struct {
+ int depth;
+ int maxdepth;
+ uint64_t index;
+ // Maps upb_refcounted* -> attributes (color, etc). attr layout varies by
+ // color.
+ upb_inttable objattr;
+ upb_inttable stack; // stack of upb_refcounted* for Tarjan's algorithm.
+ upb_inttable groups; // array of uint32_t*, malloc'd refcounts for new groups
+ upb_status *status;
+ jmp_buf err;
+} tarjan;
+
+static void release_ref2(const upb_refcounted *obj,
+ const upb_refcounted *subobj,
+ void *closure);
+
+// Node attributes /////////////////////////////////////////////////////////////
+
+// After our analysis phase all nodes will be either GRAY or WHITE.
+
+typedef enum {
+ BLACK = 0, // Object has not been seen.
+ GRAY, // Object has been found via a refgroup but may not be reachable.
+ GREEN, // Object is reachable and is currently on the Tarjan stack.
+ WHITE, // Object is reachable and has been assigned a group (SCC).
+} color_t;
+
+UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); }
+UPB_NORETURN static void oom(tarjan *t) {
+ upb_status_seterrmsg(t->status, "out of memory");
+ err(t);
+}
+
+static uint64_t trygetattr(const tarjan *t, const upb_refcounted *r) {
+ upb_value v;
+ return upb_inttable_lookupptr(&t->objattr, r, &v) ?
+ upb_value_getuint64(v) : 0;
+}
+
+static uint64_t getattr(const tarjan *t, const upb_refcounted *r) {
+ upb_value v;
+ bool found = upb_inttable_lookupptr(&t->objattr, r, &v);
+ UPB_ASSERT_VAR(found, found);
+ return upb_value_getuint64(v);
+}
+
+static void setattr(tarjan *t, const upb_refcounted *r, uint64_t attr) {
+ upb_inttable_removeptr(&t->objattr, r, NULL);
+ upb_inttable_insertptr(&t->objattr, r, upb_value_uint64(attr));
+}
+
+static color_t color(tarjan *t, const upb_refcounted *r) {
+ return trygetattr(t, r) & 0x3; // Color is always stored in the low 2 bits.
+}
+
+static void set_gray(tarjan *t, const upb_refcounted *r) {
+ assert(color(t, r) == BLACK);
+ setattr(t, r, GRAY);
+}
+
+// Pushes an obj onto the Tarjan stack and sets it to GREEN.
+static void push(tarjan *t, const upb_refcounted *r) {
+ assert(color(t, r) == BLACK || color(t, r) == GRAY);
+ // This defines the attr layout for the GREEN state. "index" and "lowlink"
+ // get 31 bits, which is plenty (limit of 2B objects frozen at a time).
+ setattr(t, r, GREEN | (t->index << 2) | (t->index << 33));
+ if (++t->index == 0x80000000) {
+ upb_status_seterrmsg(t->status, "too many objects to freeze");
+ err(t);
+ }
+ upb_inttable_push(&t->stack, upb_value_ptr((void*)r));
+}
+
+// Pops an obj from the Tarjan stack and sets it to WHITE, with a ptr to its
+// SCC group.
+static upb_refcounted *pop(tarjan *t) {
+ upb_refcounted *r = upb_value_getptr(upb_inttable_pop(&t->stack));
+ assert(color(t, r) == GREEN);
+ // This defines the attr layout for nodes in the WHITE state.
+ // Top of group stack is [group, NULL]; we point at group.
+ setattr(t, r, WHITE | (upb_inttable_count(&t->groups) - 2) << 8);
+ return r;
+}
+
+static void tarjan_newgroup(tarjan *t) {
+ uint32_t *group = malloc(sizeof(*group));
+ if (!group) oom(t);
+ // Push group and empty group leader (we'll fill in leader later).
+ if (!upb_inttable_push(&t->groups, upb_value_ptr(group)) ||
+ !upb_inttable_push(&t->groups, upb_value_ptr(NULL))) {
+ free(group);
+ oom(t);
+ }
+ *group = 0;
+}
+
+static uint32_t idx(tarjan *t, const upb_refcounted *r) {
+ assert(color(t, r) == GREEN);
+ return (getattr(t, r) >> 2) & 0x7FFFFFFF;
+}
+
+static uint32_t lowlink(tarjan *t, const upb_refcounted *r) {
+ if (color(t, r) == GREEN) {
+ return getattr(t, r) >> 33;
+ } else {
+ return UINT32_MAX;
+ }
+}
+
+static void set_lowlink(tarjan *t, const upb_refcounted *r, uint32_t lowlink) {
+ assert(color(t, r) == GREEN);
+ setattr(t, r, ((uint64_t)lowlink << 33) | (getattr(t, r) & 0x1FFFFFFFF));
+}
+
+static uint32_t *group(tarjan *t, upb_refcounted *r) {
+ assert(color(t, r) == WHITE);
+ uint64_t groupnum = getattr(t, r) >> 8;
+ upb_value v;
+ bool found = upb_inttable_lookup(&t->groups, groupnum, &v);
+ UPB_ASSERT_VAR(found, found);
+ return upb_value_getptr(v);
+}
+
+// If the group leader for this object's group has not previously been set,
+// the given object is assigned to be its leader.
+static upb_refcounted *groupleader(tarjan *t, upb_refcounted *r) {
+ assert(color(t, r) == WHITE);
+ uint64_t leader_slot = (getattr(t, r) >> 8) + 1;
+ upb_value v;
+ bool found = upb_inttable_lookup(&t->groups, leader_slot, &v);
+ UPB_ASSERT_VAR(found, found);
+ if (upb_value_getptr(v)) {
+ return upb_value_getptr(v);
+ } else {
+ upb_inttable_remove(&t->groups, leader_slot, NULL);
+ upb_inttable_insert(&t->groups, leader_slot, upb_value_ptr(r));
+ return r;
+ }
+}
+
+
+// Tarjan's algorithm //////////////////////////////////////////////////////////
+
+// See:
+// http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
+static void do_tarjan(const upb_refcounted *obj, tarjan *t);
+
+static void tarjan_visit(const upb_refcounted *obj,
+ const upb_refcounted *subobj,
+ void *closure) {
+ tarjan *t = closure;
+ if (++t->depth > t->maxdepth) {
+ upb_status_seterrf(t->status, "graph too deep to freeze (%d)", t->maxdepth);
+ err(t);
+ } else if (subobj->is_frozen || color(t, subobj) == WHITE) {
+ // Do nothing: we don't want to visit or color already-frozen nodes,
+ // and WHITE nodes have already been assigned a SCC.
+ } else if (color(t, subobj) < GREEN) {
+ // Subdef has not yet been visited; recurse on it.
+ do_tarjan(subobj, t);
+ set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), lowlink(t, subobj)));
+ } else if (color(t, subobj) == GREEN) {
+ // Subdef is in the stack and hence in the current SCC.
+ set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), idx(t, subobj)));
+ }
+ --t->depth;
+}
+
+static void do_tarjan(const upb_refcounted *obj, tarjan *t) {
+ if (color(t, obj) == BLACK) {
+ // We haven't seen this object's group; mark the whole group GRAY.
+ const upb_refcounted *o = obj;
+ do { set_gray(t, o); } while ((o = o->next) != obj);
+ }
+
+ push(t, obj);
+ visit(obj, tarjan_visit, t);
+ if (lowlink(t, obj) == idx(t, obj)) {
+ tarjan_newgroup(t);
+ while (pop(t) != obj)
+ ;
+ }
+}
+
+
+// freeze() ////////////////////////////////////////////////////////////////////
+
+static void crossref(const upb_refcounted *r, const upb_refcounted *subobj,
+ void *_t) {
+ tarjan *t = _t;
+ assert(color(t, r) > BLACK);
+ if (color(t, subobj) > BLACK && r->group != subobj->group) {
+ // Previously this ref was not reflected in subobj->group because they
+ // were in the same group; now that they are split a ref must be taken.
+ refgroup(subobj->group);
+ }
+}
+
+static bool freeze(upb_refcounted *const*roots, int n, upb_status *s,
+ int maxdepth) {
+ volatile bool ret = false;
+
+ // We run in two passes so that we can allocate all memory before performing
+ // any mutation of the input -- this allows us to leave the input unchanged
+ // in the case of memory allocation failure.
+ tarjan t;
+ t.index = 0;
+ t.depth = 0;
+ t.maxdepth = maxdepth;
+ t.status = s;
+ if (!upb_inttable_init(&t.objattr, UPB_CTYPE_UINT64)) goto err1;
+ if (!upb_inttable_init(&t.stack, UPB_CTYPE_PTR)) goto err2;
+ if (!upb_inttable_init(&t.groups, UPB_CTYPE_PTR)) goto err3;
+ if (setjmp(t.err) != 0) goto err4;
+
+
+ for (int i = 0; i < n; i++) {
+ if (color(&t, roots[i]) < GREEN) {
+ do_tarjan(roots[i], &t);
+ }
+ }
+
+ // If we've made it this far, no further errors are possible so it's safe to
+ // mutate the objects without risk of leaving them in an inconsistent state.
+ ret = true;
+
+ // The transformation that follows requires care. The preconditions are:
+ // - all objects in attr map are WHITE or GRAY, and are in mutable groups
+ // (groups of all mutable objs)
+ // - no ref2(to, from) refs have incremented count(to) if both "to" and
+ // "from" are in our attr map (this follows from invariants (2) and (3))
+
+ // Pass 1: we remove WHITE objects from their mutable groups, and add them to
+ // new groups according to the SCC's we computed. These new groups will
+ // consist of only frozen objects. None will be immediately collectible,
+ // because WHITE objects are by definition reachable from one of "roots",
+ // which the caller must own refs on.
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &t.objattr);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&i);
+ // Since removal from a singly-linked list requires access to the object's
+ // predecessor, we consider obj->next instead of obj for moving. With the
+ // while() loop we guarantee that we will visit every node's predecessor.
+ // Proof:
+ // 1. every node's predecessor is in our attr map.
+ // 2. though the loop body may change a node's predecessor, it will only
+ // change it to be the node we are currently operating on, so with a
+ // while() loop we guarantee ourselves the chance to remove each node.
+ while (color(&t, obj->next) == WHITE &&
+ group(&t, obj->next) != obj->next->group) {
+ // Remove from old group.
+ upb_refcounted *move = obj->next;
+ if (obj == move) {
+ // Removing the last object from a group.
+ assert(*obj->group == obj->individual_count);
+ free(obj->group);
+ } else {
+ obj->next = move->next;
+ // This may decrease to zero; we'll collect GRAY objects (if any) that
+ // remain in the group in the third pass.
+ assert(*move->group >= move->individual_count);
+ *move->group -= move->individual_count;
+ }
+
+ // Add to new group.
+ upb_refcounted *leader = groupleader(&t, move);
+ if (move == leader) {
+ // First object added to new group is its leader.
+ move->group = group(&t, move);
+ move->next = move;
+ *move->group = move->individual_count;
+ } else {
+ // Group already has at least one object in it.
+ assert(leader->group == group(&t, move));
+ move->group = group(&t, move);
+ move->next = leader->next;
+ leader->next = move;
+ *move->group += move->individual_count;
+ }
+
+ move->is_frozen = true;
+ }
+ }
+
+ // Pass 2: GRAY and WHITE objects "obj" with ref2(to, obj) references must
+ // increment count(to) if group(obj) != group(to) (which could now be the
+ // case if "to" was just frozen).
+ upb_inttable_begin(&i, &t.objattr);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&i);
+ visit(obj, crossref, &t);
+ }
+
+ // Pass 3: GRAY objects are collected if their group's refcount dropped to
+ // zero when we removed its white nodes. This can happen if they had only
+ // been kept alive by virtue of sharing a group with an object that was just
+ // frozen.
+ //
+ // It is important that we do this last, since the GRAY object's free()
+ // function could call unref2() on just-frozen objects, which will decrement
+ // refs that were added in pass 2.
+ upb_inttable_begin(&i, &t.objattr);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&i);
+ if (obj->group == NULL || *obj->group == 0) {
+ if (obj->group) {
+ // We eagerly free() the group's count (since we can't easily determine
+ // the group's remaining size it's the easiest way to ensure it gets
+ // done).
+ free(obj->group);
+
+ // Visit to release ref2's (done in a separate pass since release_ref2
+ // depends on o->group being unmodified so it can test merged()).
+ upb_refcounted *o = obj;
+ do { visit(o, release_ref2, NULL); } while ((o = o->next) != obj);
+
+ // Mark "group" fields as NULL so we know to free the objects later in
+ // this loop, but also don't try to delete the group twice.
+ o = obj;
+ do { o->group = NULL; } while ((o = o->next) != obj);
+ }
+ freeobj(obj);
+ }
+ }
+
+err4:
+ if (!ret) {
+ upb_inttable_begin(&i, &t.groups);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i))
+ free(upb_value_getptr(upb_inttable_iter_value(&i)));
+ }
+ upb_inttable_uninit(&t.groups);
+err3:
+ upb_inttable_uninit(&t.stack);
+err2:
+ upb_inttable_uninit(&t.objattr);
+err1:
+ return ret;
+}
+
+
+/* Misc internal functions ***************************************************/
+
+static bool merged(const upb_refcounted *r, const upb_refcounted *r2) {
+ return r->group == r2->group;
+}
+
+static void merge(upb_refcounted *r, upb_refcounted *from) {
+ if (merged(r, from)) return;
+ *r->group += *from->group;
+ free(from->group);
+ upb_refcounted *base = from;
+
+ // Set all refcount pointers in the "from" chain to the merged refcount.
+ //
+ // TODO(haberman): this linear algorithm can result in an overall O(n^2) bound
+ // if the user continuously extends a group by one object. Prevent this by
+ // using one of the techniques in this paper:
+ // ftp://www.ncedc.org/outgoing/geomorph/dino/orals/p245-tarjan.pdf
+ do { from->group = r->group; } while ((from = from->next) != base);
+
+ // Merge the two circularly linked lists by swapping their next pointers.
+ upb_refcounted *tmp = r->next;
+ r->next = base->next;
+ base->next = tmp;
+}
+
+static void unref(const upb_refcounted *r);
+
+static void release_ref2(const upb_refcounted *obj,
+ const upb_refcounted *subobj,
+ void *closure) {
+ UPB_UNUSED(closure);
+ untrack(subobj, obj, true);
+ if (!merged(obj, subobj)) {
+ assert(subobj->is_frozen);
+ unref(subobj);
+ }
+}
+
+static void unref(const upb_refcounted *r) {
+ if (unrefgroup(r->group)) {
+ free(r->group);
+
+ // In two passes, since release_ref2 needs a guarantee that any subobjs
+ // are alive.
+ const upb_refcounted *o = r;
+ do { visit(o, release_ref2, NULL); } while((o = o->next) != r);
+
+ o = r;
+ do {
+ const upb_refcounted *next = o->next;
+ assert(o->is_frozen || o->individual_count == 0);
+ freeobj((upb_refcounted*)o);
+ o = next;
+ } while(o != r);
+ }
+}
+
+static void freeobj(upb_refcounted *o) {
+ trackfree(o);
+ o->vtbl->free((upb_refcounted*)o);
+}
+
+
+/* Public interface ***********************************************************/
+
+bool upb_refcounted_init(upb_refcounted *r,
+ const struct upb_refcounted_vtbl *vtbl,
+ const void *owner) {
+ r->next = r;
+ r->vtbl = vtbl;
+ r->individual_count = 0;
+ r->is_frozen = false;
+ r->group = malloc(sizeof(*r->group));
+ if (!r->group) return false;
+ *r->group = 0;
+ if (!trackinit(r)) {
+ free(r->group);
+ return false;
+ }
+ upb_refcounted_ref(r, owner);
+ return true;
+}
+
+bool upb_refcounted_isfrozen(const upb_refcounted *r) {
+ return r->is_frozen;
+}
+
+void upb_refcounted_ref(const upb_refcounted *r, const void *owner) {
+ track(r, owner, false);
+ if (!r->is_frozen)
+ ((upb_refcounted*)r)->individual_count++;
+ refgroup(r->group);
+}
+
+void upb_refcounted_unref(const upb_refcounted *r, const void *owner) {
+ untrack(r, owner, false);
+ if (!r->is_frozen)
+ ((upb_refcounted*)r)->individual_count--;
+ unref(r);
+}
+
+void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from) {
+ assert(!from->is_frozen); // Non-const pointer implies this.
+ track(r, from, true);
+ if (r->is_frozen) {
+ refgroup(r->group);
+ } else {
+ merge((upb_refcounted*)r, from);
+ }
+}
+
+void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from) {
+ assert(!from->is_frozen); // Non-const pointer implies this.
+ untrack(r, from, true);
+ if (r->is_frozen) {
+ unref(r);
+ } else {
+ assert(merged(r, from));
+ }
+}
+
+void upb_refcounted_donateref(
+ const upb_refcounted *r, const void *from, const void *to) {
+ assert(from != to);
+ if (to != NULL)
+ upb_refcounted_ref(r, to);
+ if (from != NULL)
+ upb_refcounted_unref(r, from);
+}
+
+void upb_refcounted_checkref(const upb_refcounted *r, const void *owner) {
+ checkref(r, owner, false);
+}
+
+bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
+ int maxdepth) {
+ for (int i = 0; i < n; i++) {
+ assert(!roots[i]->is_frozen);
+ }
+ return freeze(roots, n, s, maxdepth);
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2013 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+
+#include <stdlib.h>
+
+// Fallback implementation if the shim is not specialized by the JIT.
+#define SHIM_WRITER(type, ctype) \
+ bool upb_shim_set ## type (void *c, const void *hd, ctype val) { \
+ uint8_t *m = c; \
+ const upb_shim_data *d = hd; \
+ if (d->hasbit > 0) \
+ *(uint8_t*)&m[d->hasbit / 8] |= 1 << (d->hasbit % 8); \
+ *(ctype*)&m[d->offset] = val; \
+ return true; \
+ } \
+
+SHIM_WRITER(double, double)
+SHIM_WRITER(float, float)
+SHIM_WRITER(int32, int32_t)
+SHIM_WRITER(int64, int64_t)
+SHIM_WRITER(uint32, uint32_t)
+SHIM_WRITER(uint64, uint64_t)
+SHIM_WRITER(bool, bool)
+#undef SHIM_WRITER
+
+bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
+ int32_t hasbit) {
+ upb_shim_data *d = malloc(sizeof(*d));
+ if (!d) return false;
+ d->offset = offset;
+ d->hasbit = hasbit;
+
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, d);
+ upb_handlerattr_setalwaysok(&attr, true);
+ upb_handlers_addcleanup(h, d, free);
+
+#define TYPE(u, l) \
+ case UPB_TYPE_##u: \
+ ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break;
+
+ bool ok = false;
+
+ switch (upb_fielddef_type(f)) {
+ TYPE(INT64, int64);
+ TYPE(INT32, int32);
+ TYPE(ENUM, int32);
+ TYPE(UINT64, uint64);
+ TYPE(UINT32, uint32);
+ TYPE(DOUBLE, double);
+ TYPE(FLOAT, float);
+ TYPE(BOOL, bool);
+ default: assert(false); break;
+ }
+#undef TYPE
+
+ upb_handlerattr_uninit(&attr);
+ return ok;
+}
+
+const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
+ upb_fieldtype_t *type) {
+ upb_func *f = upb_handlers_gethandler(h, s);
+
+ if ((upb_int64_handlerfunc*)f == upb_shim_setint64) {
+ *type = UPB_TYPE_INT64;
+ } else if ((upb_int32_handlerfunc*)f == upb_shim_setint32) {
+ *type = UPB_TYPE_INT32;
+ } else if ((upb_uint64_handlerfunc*)f == upb_shim_setuint64) {
+ *type = UPB_TYPE_UINT64;
+ } else if ((upb_uint32_handlerfunc*)f == upb_shim_setuint32) {
+ *type = UPB_TYPE_UINT32;
+ } else if ((upb_double_handlerfunc*)f == upb_shim_setdouble) {
+ *type = UPB_TYPE_DOUBLE;
+ } else if ((upb_float_handlerfunc*)f == upb_shim_setfloat) {
+ *type = UPB_TYPE_FLOAT;
+ } else if ((upb_bool_handlerfunc*)f == upb_shim_setbool) {
+ *type = UPB_TYPE_BOOL;
+ } else {
+ return NULL;
+ }
+
+ return (const upb_shim_data*)upb_handlers_gethandlerdata(h, s);
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2008-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+bool upb_symtab_isfrozen(const upb_symtab *s) {
+ return upb_refcounted_isfrozen(UPB_UPCAST(s));
+}
+
+void upb_symtab_ref(const upb_symtab *s, const void *owner) {
+ upb_refcounted_ref(UPB_UPCAST(s), owner);
+}
+
+void upb_symtab_unref(const upb_symtab *s, const void *owner) {
+ upb_refcounted_unref(UPB_UPCAST(s), owner);
+}
+
+void upb_symtab_donateref(
+ const upb_symtab *s, const void *from, const void *to) {
+ upb_refcounted_donateref(UPB_UPCAST(s), from, to);
+}
+
+void upb_symtab_checkref(const upb_symtab *s, const void *owner) {
+ upb_refcounted_checkref(UPB_UPCAST(s), owner);
+}
+
+static void upb_symtab_free(upb_refcounted *r) {
+ upb_symtab *s = (upb_symtab*)r;
+ upb_strtable_iter i;
+ upb_strtable_begin(&i, &s->symtab);
+ for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ const upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+ upb_def_unref(def, s);
+ }
+ upb_strtable_uninit(&s->symtab);
+ free(s);
+}
+
+
+upb_symtab *upb_symtab_new(const void *owner) {
+ static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_symtab_free};
+ upb_symtab *s = malloc(sizeof(*s));
+ upb_refcounted_init(UPB_UPCAST(s), &vtbl, owner);
+ upb_strtable_init(&s->symtab, UPB_CTYPE_PTR);
+ return s;
+}
+
+void upb_symtab_freeze(upb_symtab *s) {
+ assert(!upb_symtab_isfrozen(s));
+ upb_refcounted *r = UPB_UPCAST(s);
+ // The symtab does not take ref2's (see refcounted.h) on the defs, because
+ // defs cannot refer back to the table and therefore cannot create cycles. So
+ // 0 will suffice for maxdepth here.
+ bool ok = upb_refcounted_freeze(&r, 1, NULL, 0);
+ UPB_ASSERT_VAR(ok, ok);
+}
+
+const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym) {
+ upb_value v;
+ upb_def *ret = upb_strtable_lookup(&s->symtab, sym, &v) ?
+ upb_value_getptr(v) : NULL;
+ return ret;
+}
+
+const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) {
+ upb_value v;
+ upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ?
+ upb_value_getptr(v) : NULL;
+ return def ? upb_dyncast_msgdef(def) : NULL;
+}
+
+const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) {
+ upb_value v;
+ upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ?
+ upb_value_getptr(v) : NULL;
+ return def ? upb_dyncast_enumdef(def) : NULL;
+}
+
+// Given a symbol and the base symbol inside which it is defined, find the
+// symbol's definition in t.
+static upb_def *upb_resolvename(const upb_strtable *t,
+ const char *base, const char *sym) {
+ if(strlen(sym) == 0) return NULL;
+ if(sym[0] == '.') {
+ // Symbols starting with '.' are absolute, so we do a single lookup.
+ // Slice to omit the leading '.'
+ upb_value v;
+ return upb_strtable_lookup(t, sym + 1, &v) ? upb_value_getptr(v) : NULL;
+ } else {
+ // Remove components from base until we find an entry or run out.
+ // TODO: This branch is totally broken, but currently not used.
+ (void)base;
+ assert(false);
+ return NULL;
+ }
+}
+
+const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base,
+ const char *sym) {
+ upb_def *ret = upb_resolvename(&s->symtab, base, sym);
+ return ret;
+}
+
+// Searches def and its children to find defs that have the same name as any
+// def in "addtab." Returns true if any where found, and as a side-effect adds
+// duplicates of these defs into addtab.
+//
+// We use a modified depth-first traversal that traverses each SCC (which we
+// already computed) as if it were a single node. This allows us to traverse
+// the possibly-cyclic graph as if it were a DAG and to dup the correct set of
+// nodes with O(n) time.
+static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
+ const void *new_owner, upb_inttable *seen,
+ upb_status *s) {
+ // Memoize results of this function for efficiency (since we're traversing a
+ // DAG this is not needed to limit the depth of the search).
+ upb_value v;
+ if (upb_inttable_lookup(seen, (uintptr_t)def, &v))
+ return upb_value_getbool(v);
+
+ // Visit submessages for all messages in the SCC.
+ bool need_dup = false;
+ const upb_def *base = def;
+ do {
+ assert(upb_def_isfrozen(def));
+ if (def->type == UPB_DEF_FIELD) continue;
+ upb_value v;
+ if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) {
+ need_dup = true;
+ }
+
+ // For messages, continue the recursion by visiting all subdefs.
+ const upb_msgdef *m = upb_dyncast_msgdef(def);
+ if (m) {
+ upb_msg_field_iter i;
+ for(upb_msg_field_begin(&i, m);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ upb_fielddef *f = upb_msg_iter_field(&i);
+ if (!upb_fielddef_hassubdef(f)) continue;
+ // |= to avoid short-circuit; we need its side-effects.
+ need_dup |= upb_resolve_dfs(
+ upb_fielddef_subdef(f), addtab, new_owner, seen, s);
+ if (!upb_ok(s)) return false;
+ }
+ }
+ } while ((def = (upb_def*)def->base.next) != base);
+
+ if (need_dup) {
+ // Dup any defs that don't already have entries in addtab.
+ def = base;
+ do {
+ if (def->type == UPB_DEF_FIELD) continue;
+ const char *name = upb_def_fullname(def);
+ if (!upb_strtable_lookup(addtab, name, NULL)) {
+ upb_def *newdef = upb_def_dup(def, new_owner);
+ if (!newdef) goto oom;
+ newdef->came_from_user = false;
+ if (!upb_strtable_insert(addtab, name, upb_value_ptr(newdef)))
+ goto oom;
+ }
+ } while ((def = (upb_def*)def->base.next) != base);
+ }
+
+ upb_inttable_insert(seen, (uintptr_t)def, upb_value_bool(need_dup));
+ return need_dup;
+
+oom:
+ upb_status_seterrmsg(s, "out of memory");
+ return false;
+}
+
+// TODO(haberman): we need a lot more testing of error conditions.
+// The came_from_user stuff in particular is not tested.
+bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
+ upb_status *status) {
+ assert(!upb_symtab_isfrozen(s));
+ upb_def **add_defs = NULL;
+ upb_strtable addtab;
+ if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) {
+ upb_status_seterrmsg(status, "out of memory");
+ return false;
+ }
+
+ // Add new defs to our "add" set.
+ for (int i = 0; i < n; i++) {
+ upb_def *def = defs[i];
+ if (upb_def_isfrozen(def)) {
+ upb_status_seterrmsg(status, "added defs must be mutable");
+ goto err;
+ }
+ assert(!upb_def_isfrozen(def));
+ const char *fullname = upb_def_fullname(def);
+ if (!fullname) {
+ upb_status_seterrmsg(
+ status, "Anonymous defs cannot be added to a symtab");
+ goto err;
+ }
+
+ upb_fielddef *f = upb_dyncast_fielddef_mutable(def);
+
+ if (f) {
+ if (!upb_fielddef_containingtypename(f)) {
+ upb_status_seterrmsg(status,
+ "Standalone fielddefs must have a containing type "
+ "(extendee) name set");
+ goto err;
+ }
+ } else {
+ if (upb_strtable_lookup(&addtab, fullname, NULL)) {
+ upb_status_seterrf(status, "Conflicting defs named '%s'", fullname);
+ goto err;
+ }
+ // We need this to back out properly, because if there is a failure we
+ // need to donate the ref back to the caller.
+ def->came_from_user = true;
+ upb_def_donateref(def, ref_donor, s);
+ if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def)))
+ goto oom_err;
+ }
+ }
+
+ // Add standalone fielddefs (ie. extensions) to the appropriate messages.
+ // If the appropriate message only exists in the existing symtab, duplicate
+ // it so we have a mutable copy we can add the fields to.
+ for (int i = 0; i < n; i++) {
+ upb_def *def = defs[i];
+ upb_fielddef *f = upb_dyncast_fielddef_mutable(def);
+ if (!f) continue;
+ const char *msgname = upb_fielddef_containingtypename(f);
+ // We validated this earlier in this function.
+ assert(msgname);
+
+ // If the extendee name is absolutely qualified, move past the initial ".".
+ // TODO(haberman): it is not obvious what it would mean if this was not
+ // absolutely qualified.
+ if (msgname[0] == '.') {
+ msgname++;
+ }
+
+ upb_value v;
+ upb_msgdef *m;
+ if (upb_strtable_lookup(&addtab, msgname, &v)) {
+ // Extendee is in the set of defs the user asked us to add.
+ m = upb_value_getptr(v);
+ } else {
+ // Need to find and dup the extendee from the existing symtab.
+ const upb_msgdef *frozen_m = upb_symtab_lookupmsg(s, msgname);
+ if (!frozen_m) {
+ upb_status_seterrf(status,
+ "Tried to extend message %s that does not exist "
+ "in this SymbolTable.",
+ msgname);
+ goto err;
+ }
+ m = upb_msgdef_dup(frozen_m, s);
+ if (!m) goto oom_err;
+ if (!upb_strtable_insert(&addtab, msgname, upb_value_ptr(m))) {
+ upb_msgdef_unref(m, s);
+ goto oom_err;
+ }
+ }
+
+ if (!upb_msgdef_addfield(m, f, ref_donor, status)) {
+ goto err;
+ }
+ }
+
+ // Add dups of any existing def that can reach a def with the same name as
+ // anything in our "add" set.
+ upb_inttable seen;
+ if (!upb_inttable_init(&seen, UPB_CTYPE_BOOL)) goto oom_err;
+ upb_strtable_iter i;
+ upb_strtable_begin(&i, &s->symtab);
+ for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+ upb_resolve_dfs(def, &addtab, s, &seen, status);
+ if (!upb_ok(status)) goto err;
+ }
+ upb_inttable_uninit(&seen);
+
+ // Now using the table, resolve symbolic references for subdefs.
+ upb_strtable_begin(&i, &addtab);
+ for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+ upb_msgdef *m = upb_dyncast_msgdef_mutable(def);
+ if (!m) continue;
+ // Type names are resolved relative to the message in which they appear.
+ const char *base = upb_msgdef_fullname(m);
+
+ upb_msg_field_iter j;
+ for(upb_msg_field_begin(&j, m);
+ !upb_msg_field_done(&j);
+ upb_msg_field_next(&j)) {
+ upb_fielddef *f = upb_msg_iter_field(&j);
+ const char *name = upb_fielddef_subdefname(f);
+ if (name && !upb_fielddef_subdef(f)) {
+ // Try the lookup in the current set of to-be-added defs first. If not
+ // there, try existing defs.
+ upb_def *subdef = upb_resolvename(&addtab, base, name);
+ if (subdef == NULL) {
+ subdef = upb_resolvename(&s->symtab, base, name);
+ }
+ if (subdef == NULL) {
+ upb_status_seterrf(
+ status, "couldn't resolve name '%s' in message '%s'", name, base);
+ goto err;
+ } else if (!upb_fielddef_setsubdef(f, subdef, status)) {
+ goto err;
+ }
+ }
+ }
+ }
+
+ // We need an array of the defs in addtab, for passing to upb_def_freeze.
+ add_defs = malloc(sizeof(void*) * upb_strtable_count(&addtab));
+ if (add_defs == NULL) goto oom_err;
+ upb_strtable_begin(&i, &addtab);
+ for (n = 0; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ add_defs[n++] = upb_value_getptr(upb_strtable_iter_value(&i));
+ }
+
+ if (!upb_def_freeze(add_defs, n, status)) goto err;
+
+ // This must be delayed until all errors have been detected, since error
+ // recovery code uses this table to cleanup defs.
+ upb_strtable_uninit(&addtab);
+
+ // TODO(haberman) we don't properly handle errors after this point (like
+ // OOM in upb_strtable_insert() below).
+ for (int i = 0; i < n; i++) {
+ upb_def *def = add_defs[i];
+ const char *name = upb_def_fullname(def);
+ upb_value v;
+ if (upb_strtable_remove(&s->symtab, name, &v)) {
+ const upb_def *def = upb_value_getptr(v);
+ upb_def_unref(def, s);
+ }
+ bool success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def));
+ UPB_ASSERT_VAR(success, success == true);
+ }
+ free(add_defs);
+ return true;
+
+oom_err:
+ upb_status_seterrmsg(status, "out of memory");
+err: {
+ // For defs the user passed in, we need to donate the refs back. For defs
+ // we dup'd, we need to just unref them.
+ upb_strtable_iter i;
+ upb_strtable_begin(&i, &addtab);
+ for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+ bool came_from_user = def->came_from_user;
+ def->came_from_user = false;
+ if (came_from_user) {
+ upb_def_donateref(def, s, ref_donor);
+ } else {
+ upb_def_unref(def, s);
+ }
+ }
+ }
+ upb_strtable_uninit(&addtab);
+ free(add_defs);
+ assert(!upb_ok(status));
+ return false;
+}
+
+// Iteration.
+
+static void advance_to_matching(upb_symtab_iter *iter) {
+ if (iter->type == UPB_DEF_ANY)
+ return;
+
+ while (!upb_strtable_done(&iter->iter) &&
+ iter->type != upb_symtab_iter_def(iter)->type) {
+ upb_strtable_next(&iter->iter);
+ }
+}
+
+void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s,
+ upb_deftype_t type) {
+ upb_strtable_begin(&iter->iter, &s->symtab);
+ iter->type = type;
+ advance_to_matching(iter);
+}
+
+void upb_symtab_next(upb_symtab_iter *iter) {
+ upb_strtable_next(&iter->iter);
+ advance_to_matching(iter);
+}
+
+bool upb_symtab_done(const upb_symtab_iter *iter) {
+ return upb_strtable_done(&iter->iter);
+}
+
+const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter) {
+ return upb_value_getptr(upb_strtable_iter_value(&iter->iter));
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * Implementation is heavily inspired by Lua's ltable.c.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#define UPB_MAXARRSIZE 16 // 64k.
+
+// From Chromium.
+#define ARRAY_SIZE(x) \
+ ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
+
+static const double MAX_LOAD = 0.85;
+
+// The minimum utilization of the array part of a mixed hash/array table. This
+// is a speed/memory-usage tradeoff (though it's not straightforward because of
+// cache effects). The lower this is, the more memory we'll use.
+static const double MIN_DENSITY = 0.1;
+
+bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; }
+
+int log2ceil(uint64_t v) {
+ int ret = 0;
+ bool pow2 = is_pow2(v);
+ while (v >>= 1) ret++;
+ ret = pow2 ? ret : ret + 1; // Ceiling.
+ return UPB_MIN(UPB_MAXARRSIZE, ret);
+}
+
+char *upb_strdup(const char *s) {
+ return upb_strdup2(s, strlen(s));
+}
+
+char *upb_strdup2(const char *s, size_t len) {
+ // Prevent overflow errors.
+ if (len == SIZE_MAX) return NULL;
+ // Always null-terminate, even if binary data; but don't rely on the input to
+ // have a null-terminating byte since it may be a raw binary buffer.
+ size_t n = len + 1;
+ char *p = malloc(n);
+ if (p) {
+ memcpy(p, s, len);
+ p[len] = 0;
+ }
+ return p;
+}
+
+// A type to represent the lookup key of either a strtable or an inttable.
+typedef struct {
+ upb_tabkey key;
+} lookupkey_t;
+
+static lookupkey_t strkey2(const char *str, size_t len) {
+ lookupkey_t k;
+ k.key.s.str = (char*)str;
+ k.key.s.length = len;
+ return k;
+}
+
+static lookupkey_t intkey(uintptr_t key) {
+ lookupkey_t k;
+ k.key = upb_intkey(key);
+ return k;
+}
+
+typedef uint32_t hashfunc_t(upb_tabkey key);
+typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2);
+
+/* Base table (shared code) ***************************************************/
+
+// For when we need to cast away const.
+static upb_tabent *mutable_entries(upb_table *t) {
+ return (upb_tabent*)t->entries;
+}
+
+static bool isfull(upb_table *t) {
+ return (double)(t->count + 1) / upb_table_size(t) > MAX_LOAD;
+}
+
+static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2) {
+ t->count = 0;
+ t->ctype = ctype;
+ t->size_lg2 = size_lg2;
+ t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0;
+ size_t bytes = upb_table_size(t) * sizeof(upb_tabent);
+ if (bytes > 0) {
+ t->entries = malloc(bytes);
+ if (!t->entries) return false;
+ memset(mutable_entries(t), 0, bytes);
+ } else {
+ t->entries = NULL;
+ }
+ return true;
+}
+
+static void uninit(upb_table *t) { free(mutable_entries(t)); }
+
+static upb_tabent *emptyent(upb_table *t) {
+ upb_tabent *e = mutable_entries(t) + upb_table_size(t);
+ while (1) { if (upb_tabent_isempty(--e)) return e; assert(e > t->entries); }
+}
+
+static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) {
+ return (upb_tabent*)upb_getentry(t, hash);
+}
+
+static const upb_tabent *findentry(const upb_table *t, lookupkey_t key,
+ uint32_t hash, eqlfunc_t *eql) {
+ if (t->size_lg2 == 0) return NULL;
+ const upb_tabent *e = upb_getentry(t, hash);
+ if (upb_tabent_isempty(e)) return NULL;
+ while (1) {
+ if (eql(e->key, key)) return e;
+ if ((e = e->next) == NULL) return NULL;
+ }
+}
+
+static upb_tabent *findentry_mutable(upb_table *t, lookupkey_t key,
+ uint32_t hash, eqlfunc_t *eql) {
+ return (upb_tabent*)findentry(t, key, hash, eql);
+}
+
+static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v,
+ uint32_t hash, eqlfunc_t *eql) {
+ const upb_tabent *e = findentry(t, key, hash, eql);
+ if (e) {
+ if (v) {
+ _upb_value_setval(v, e->val, t->ctype);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// The given key must not already exist in the table.
+static void insert(upb_table *t, lookupkey_t key, upb_value val,
+ uint32_t hash, hashfunc_t *hashfunc, eqlfunc_t *eql) {
+ UPB_UNUSED(eql);
+ assert(findentry(t, key, hash, eql) == NULL);
+ assert(val.ctype == t->ctype);
+ t->count++;
+ upb_tabent *mainpos_e = getentry_mutable(t, hash);
+ upb_tabent *our_e = mainpos_e;
+ if (upb_tabent_isempty(mainpos_e)) {
+ // Our main position is empty; use it.
+ our_e->next = NULL;
+ } else {
+ // Collision.
+ upb_tabent *new_e = emptyent(t);
+ // Head of collider's chain.
+ upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key));
+ if (chain == mainpos_e) {
+ // Existing ent is in its main posisiton (it has the same hash as us, and
+ // is the head of our chain). Insert to new ent and append to this chain.
+ new_e->next = mainpos_e->next;
+ mainpos_e->next = new_e;
+ our_e = new_e;
+ } else {
+ // Existing ent is not in its main position (it is a node in some other
+ // chain). This implies that no existing ent in the table has our hash.
+ // Evict it (updating its chain) and use its ent for head of our chain.
+ *new_e = *mainpos_e; // copies next.
+ while (chain->next != mainpos_e) {
+ chain = (upb_tabent*)chain->next;
+ assert(chain);
+ }
+ chain->next = new_e;
+ our_e = mainpos_e;
+ our_e->next = NULL;
+ }
+ }
+ our_e->key = key.key;
+ our_e->val = val.val;
+ assert(findentry(t, key, hash, eql) == our_e);
+}
+
+static bool rm(upb_table *t, lookupkey_t key, upb_value *val,
+ upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql) {
+ upb_tabent *chain = getentry_mutable(t, hash);
+ if (upb_tabent_isempty(chain)) return false;
+ if (eql(chain->key, key)) {
+ // Element to remove is at the head of its chain.
+ t->count--;
+ if (val) {
+ _upb_value_setval(val, chain->val, t->ctype);
+ }
+ if (chain->next) {
+ upb_tabent *move = (upb_tabent*)chain->next;
+ *chain = *move;
+ if (removed) *removed = move->key;
+ move->key.num = 0; // Make the slot empty.
+ } else {
+ if (removed) *removed = chain->key;
+ chain->key.num = 0; // Make the slot empty.
+ }
+ return true;
+ } else {
+ // Element to remove is either in a non-head position or not in the table.
+ while (chain->next && !eql(chain->next->key, key))
+ chain = (upb_tabent*)chain->next;
+ if (chain->next) {
+ // Found element to remove.
+ if (val) {
+ _upb_value_setval(val, chain->next->val, t->ctype);
+ }
+ upb_tabent *rm = (upb_tabent*)chain->next;
+ if (removed) *removed = rm->key;
+ rm->key.num = 0;
+ chain->next = rm->next;
+ t->count--;
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
+static size_t next(const upb_table *t, size_t i) {
+ do {
+ if (++i >= upb_table_size(t))
+ return SIZE_MAX;
+ } while(upb_tabent_isempty(&t->entries[i]));
+
+ return i;
+}
+
+static size_t begin(const upb_table *t) {
+ return next(t, -1);
+}
+
+
+/* upb_strtable ***************************************************************/
+
+// A simple "subclass" of upb_table that only adds a hash function for strings.
+
+static uint32_t strhash(upb_tabkey key) {
+ return MurmurHash2(key.s.str, key.s.length, 0);
+}
+
+static bool streql(upb_tabkey k1, lookupkey_t k2) {
+ return k1.s.length == k2.key.s.length &&
+ memcmp(k1.s.str, k2.key.s.str, k1.s.length) == 0;
+}
+
+bool upb_strtable_init(upb_strtable *t, upb_ctype_t ctype) {
+ return init(&t->t, ctype, 2);
+}
+
+void upb_strtable_uninit(upb_strtable *t) {
+ for (size_t i = 0; i < upb_table_size(&t->t); i++)
+ free((void*)t->t.entries[i].key.s.str);
+ uninit(&t->t);
+}
+
+bool upb_strtable_resize(upb_strtable *t, size_t size_lg2) {
+ upb_strtable new_table;
+ if (!init(&new_table.t, t->t.ctype, size_lg2))
+ return false;
+ upb_strtable_iter i;
+ upb_strtable_begin(&i, t);
+ for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ upb_strtable_insert2(
+ &new_table,
+ upb_strtable_iter_key(&i),
+ upb_strtable_iter_keylength(&i),
+ upb_strtable_iter_value(&i));
+ }
+ upb_strtable_uninit(t);
+ *t = new_table;
+ return true;
+}
+
+bool upb_strtable_insert2(upb_strtable *t, const char *k, size_t len,
+ upb_value v) {
+ if (isfull(&t->t)) {
+ // Need to resize. New table of double the size, add old elements to it.
+ if (!upb_strtable_resize(t, t->t.size_lg2 + 1)) {
+ return false;
+ }
+ }
+ if ((k = upb_strdup2(k, len)) == NULL) return false;
+
+ lookupkey_t key = strkey2(k, len);
+ uint32_t hash = MurmurHash2(key.key.s.str, key.key.s.length, 0);
+ insert(&t->t, key, v, hash, &strhash, &streql);
+ return true;
+}
+
+bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
+ upb_value *v) {
+ uint32_t hash = MurmurHash2(key, len, 0);
+ return lookup(&t->t, strkey2(key, len), v, hash, &streql);
+}
+
+bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len,
+ upb_value *val) {
+ uint32_t hash = MurmurHash2(key, strlen(key), 0);
+ upb_tabkey tabkey;
+ if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) {
+ free((void*)tabkey.s.str);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// Iteration
+
+static const upb_tabent *str_tabent(const upb_strtable_iter *i) {
+ return &i->t->t.entries[i->index];
+}
+
+void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) {
+ i->t = t;
+ i->index = begin(&t->t);
+}
+
+void upb_strtable_next(upb_strtable_iter *i) {
+ i->index = next(&i->t->t, i->index);
+}
+
+bool upb_strtable_done(const upb_strtable_iter *i) {
+ return i->index >= upb_table_size(&i->t->t) ||
+ upb_tabent_isempty(str_tabent(i));
+}
+
+const char *upb_strtable_iter_key(upb_strtable_iter *i) {
+ assert(!upb_strtable_done(i));
+ return str_tabent(i)->key.s.str;
+}
+
+size_t upb_strtable_iter_keylength(upb_strtable_iter *i) {
+ assert(!upb_strtable_done(i));
+ return str_tabent(i)->key.s.length;
+}
+
+upb_value upb_strtable_iter_value(const upb_strtable_iter *i) {
+ assert(!upb_strtable_done(i));
+ return _upb_value_val(str_tabent(i)->val, i->t->t.ctype);
+}
+
+void upb_strtable_iter_setdone(upb_strtable_iter *i) {
+ i->index = SIZE_MAX;
+}
+
+bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
+ const upb_strtable_iter *i2) {
+ if (upb_strtable_done(i1) && upb_strtable_done(i2))
+ return true;
+ return i1->t == i2->t && i1->index == i2->index;
+}
+
+
+/* upb_inttable ***************************************************************/
+
+// For inttables we use a hybrid structure where small keys are kept in an
+// array and large keys are put in the hash table.
+
+static uint32_t inthash(upb_tabkey key) { return upb_inthash(key.num); }
+
+static bool inteql(upb_tabkey k1, lookupkey_t k2) {
+ return k1.num == k2.key.num;
+}
+
+static _upb_value *mutable_array(upb_inttable *t) {
+ return (_upb_value*)t->array;
+}
+
+static _upb_value *inttable_val(upb_inttable *t, uintptr_t key) {
+ if (key < t->array_size) {
+ return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL;
+ } else {
+ upb_tabent *e =
+ findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql);
+ return e ? &e->val : NULL;
+ }
+}
+
+static const _upb_value *inttable_val_const(const upb_inttable *t,
+ uintptr_t key) {
+ return inttable_val((upb_inttable*)t, key);
+}
+
+size_t upb_inttable_count(const upb_inttable *t) {
+ return t->t.count + t->array_count;
+}
+
+static void check(upb_inttable *t) {
+ UPB_UNUSED(t);
+#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
+ // This check is very expensive (makes inserts/deletes O(N)).
+ size_t count = 0;
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, t);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
+ assert(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL));
+ }
+ assert(count == upb_inttable_count(t));
+#endif
+}
+
+bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype,
+ size_t asize, int hsize_lg2) {
+ if (!init(&t->t, ctype, hsize_lg2)) return false;
+ // Always make the array part at least 1 long, so that we know key 0
+ // won't be in the hash part, which simplifies things.
+ t->array_size = UPB_MAX(1, asize);
+ t->array_count = 0;
+ size_t array_bytes = t->array_size * sizeof(upb_value);
+ t->array = malloc(array_bytes);
+ if (!t->array) {
+ uninit(&t->t);
+ return false;
+ }
+ memset(mutable_array(t), 0xff, array_bytes);
+ check(t);
+ return true;
+}
+
+bool upb_inttable_init(upb_inttable *t, upb_ctype_t ctype) {
+ return upb_inttable_sizedinit(t, ctype, 0, 4);
+}
+
+void upb_inttable_uninit(upb_inttable *t) {
+ uninit(&t->t);
+ free(mutable_array(t));
+}
+
+bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) {
+ assert(upb_arrhas(val.val));
+ if (key < t->array_size) {
+ assert(!upb_arrhas(t->array[key]));
+ t->array_count++;
+ mutable_array(t)[key] = val.val;
+ } else {
+ if (isfull(&t->t)) {
+ // Need to resize the hash part, but we re-use the array part.
+ upb_table new_table;
+ if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1))
+ return false;
+ size_t i;
+ for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
+ const upb_tabent *e = &t->t.entries[i];
+ upb_value v;
+ _upb_value_setval(&v, e->val, t->t.ctype);
+ uint32_t hash = upb_inthash(e->key.num);
+ insert(&new_table, intkey(e->key.num), v, hash, &inthash, &inteql);
+ }
+
+ assert(t->t.count == new_table.count);
+
+ uninit(&t->t);
+ t->t = new_table;
+ }
+ insert(&t->t, intkey(key), val, upb_inthash(key), &inthash, &inteql);
+ }
+ check(t);
+ return true;
+}
+
+bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) {
+ const _upb_value *table_v = inttable_val_const(t, key);
+ if (!table_v) return false;
+ if (v) _upb_value_setval(v, *table_v, t->t.ctype);
+ return true;
+}
+
+bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) {
+ _upb_value *table_v = inttable_val(t, key);
+ if (!table_v) return false;
+ *table_v = val.val;
+ return true;
+}
+
+bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
+ bool success;
+ if (key < t->array_size) {
+ if (upb_arrhas(t->array[key])) {
+ t->array_count--;
+ if (val) {
+ _upb_value_setval(val, t->array[key], t->t.ctype);
+ }
+ _upb_value empty = UPB_ARRAY_EMPTYENT;
+ mutable_array(t)[key] = empty;
+ success = true;
+ } else {
+ success = false;
+ }
+ } else {
+ upb_tabkey removed;
+ uint32_t hash = upb_inthash(key);
+ success = rm(&t->t, intkey(key), val, &removed, hash, &inteql);
+ }
+ check(t);
+ return success;
+}
+
+bool upb_inttable_push(upb_inttable *t, upb_value val) {
+ return upb_inttable_insert(t, upb_inttable_count(t), val);
+}
+
+upb_value upb_inttable_pop(upb_inttable *t) {
+ upb_value val;
+ bool ok = upb_inttable_remove(t, upb_inttable_count(t) - 1, &val);
+ UPB_ASSERT_VAR(ok, ok);
+ return val;
+}
+
+bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val) {
+ return upb_inttable_insert(t, (uintptr_t)key, val);
+}
+
+bool upb_inttable_lookupptr(const upb_inttable *t, const void *key,
+ upb_value *v) {
+ return upb_inttable_lookup(t, (uintptr_t)key, v);
+}
+
+bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) {
+ return upb_inttable_remove(t, (uintptr_t)key, val);
+}
+
+void upb_inttable_compact(upb_inttable *t) {
+ // Create a power-of-two histogram of the table keys.
+ int counts[UPB_MAXARRSIZE + 1] = {0};
+ uintptr_t max_key = 0;
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, t);
+ for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ uintptr_t key = upb_inttable_iter_key(&i);
+ if (key > max_key) {
+ max_key = key;
+ }
+ counts[log2ceil(key)]++;
+ }
+
+ int arr_size;
+ int arr_count = upb_inttable_count(t);
+
+ if (upb_inttable_count(t) >= max_key * MIN_DENSITY) {
+ // We can put 100% of the entries in the array part.
+ arr_size = max_key + 1;
+ } else {
+ // Find the largest power of two that satisfies the MIN_DENSITY definition.
+ for (int size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 1; size_lg2--) {
+ arr_size = 1 << size_lg2;
+ arr_count -= counts[size_lg2];
+ if (arr_count >= arr_size * MIN_DENSITY) {
+ break;
+ }
+ }
+ }
+
+ // Array part must always be at least 1 entry large to catch lookups of key
+ // 0. Key 0 must always be in the array part because "0" in the hash part
+ // denotes an empty entry.
+ arr_size = UPB_MAX(arr_size, 1);
+
+ // Insert all elements into new, perfectly-sized table.
+ int hash_count = upb_inttable_count(t) - arr_count;
+ int hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0;
+ int hashsize_lg2 = log2ceil(hash_size);
+ assert(hash_count >= 0);
+
+ upb_inttable new_t;
+ upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2);
+ upb_inttable_begin(&i, t);
+ for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ uintptr_t k = upb_inttable_iter_key(&i);
+ upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i));
+ }
+ assert(new_t.array_size == arr_size);
+ assert(new_t.t.size_lg2 == hashsize_lg2);
+ upb_inttable_uninit(t);
+ *t = new_t;
+}
+
+// Iteration.
+
+static const upb_tabent *int_tabent(const upb_inttable_iter *i) {
+ assert(!i->array_part);
+ return &i->t->t.entries[i->index];
+}
+
+static _upb_value int_arrent(const upb_inttable_iter *i) {
+ assert(i->array_part);
+ return i->t->array[i->index];
+}
+
+void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) {
+ i->t = t;
+ i->index = -1;
+ i->array_part = true;
+ upb_inttable_next(i);
+}
+
+void upb_inttable_next(upb_inttable_iter *iter) {
+ const upb_inttable *t = iter->t;
+ if (iter->array_part) {
+ while (++iter->index < t->array_size) {
+ if (upb_arrhas(int_arrent(iter))) {
+ return;
+ }
+ }
+ iter->array_part = false;
+ iter->index = begin(&t->t);
+ } else {
+ iter->index = next(&t->t, iter->index);
+ }
+}
+
+bool upb_inttable_done(const upb_inttable_iter *i) {
+ if (i->array_part) {
+ return i->index >= i->t->array_size ||
+ !upb_arrhas(int_arrent(i));
+ } else {
+ return i->index >= upb_table_size(&i->t->t) ||
+ upb_tabent_isempty(int_tabent(i));
+ }
+}
+
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) {
+ assert(!upb_inttable_done(i));
+ return i->array_part ? i->index : int_tabent(i)->key.num;
+}
+
+upb_value upb_inttable_iter_value(const upb_inttable_iter *i) {
+ assert(!upb_inttable_done(i));
+ return _upb_value_val(
+ i->array_part ? i->t->array[i->index] : int_tabent(i)->val,
+ i->t->t.ctype);
+}
+
+void upb_inttable_iter_setdone(upb_inttable_iter *i) {
+ i->index = SIZE_MAX;
+ i->array_part = false;
+}
+
+bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
+ const upb_inttable_iter *i2) {
+ if (upb_inttable_done(i1) && upb_inttable_done(i2))
+ return true;
+ return i1->t == i2->t && i1->index == i2->index &&
+ i1->array_part == i2->array_part;
+}
+
+#ifdef UPB_UNALIGNED_READS_OK
+//-----------------------------------------------------------------------------
+// MurmurHash2, by Austin Appleby (released as public domain).
+// Reformatted and C99-ified by Joshua Haberman.
+// Note - This code makes a few assumptions about how your machine behaves -
+// 1. We can read a 4-byte value from any address without crashing
+// 2. sizeof(int) == 4 (in upb this limitation is removed by using uint32_t
+// And it has a few limitations -
+// 1. It will not work incrementally.
+// 2. It will not produce the same results on little-endian and big-endian
+// machines.
+uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed) {
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ const uint32_t m = 0x5bd1e995;
+ const int32_t r = 24;
+
+ // Initialize the hash to a 'random' value
+ uint32_t h = seed ^ len;
+
+ // Mix 4 bytes at a time into the hash
+ const uint8_t * data = (const uint8_t *)key;
+ while(len >= 4) {
+ uint32_t k = *(uint32_t *)data;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+ switch(len) {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0]; h *= m;
+ };
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+#else // !UPB_UNALIGNED_READS_OK
+
+//-----------------------------------------------------------------------------
+// MurmurHashAligned2, by Austin Appleby
+// Same algorithm as MurmurHash2, but only does aligned reads - should be safer
+// on certain platforms.
+// Performance will be lower than MurmurHash2
+
+#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
+
+uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed) {
+ const uint32_t m = 0x5bd1e995;
+ const int32_t r = 24;
+ const uint8_t * data = (const uint8_t *)key;
+ uint32_t h = seed ^ len;
+ uint8_t align = (uintptr_t)data & 3;
+
+ if(align && (len >= 4)) {
+ // Pre-load the temp registers
+ uint32_t t = 0, d = 0;
+
+ switch(align) {
+ case 1: t |= data[2] << 16;
+ case 2: t |= data[1] << 8;
+ case 3: t |= data[0];
+ }
+
+ t <<= (8 * align);
+
+ data += 4-align;
+ len -= 4-align;
+
+ int32_t sl = 8 * (4-align);
+ int32_t sr = 8 * align;
+
+ // Mix
+
+ while(len >= 4) {
+ d = *(uint32_t *)data;
+ t = (t >> sr) | (d << sl);
+
+ uint32_t k = t;
+
+ MIX(h,k,m);
+
+ t = d;
+
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle leftover data in temp registers
+
+ d = 0;
+
+ if(len >= align) {
+ switch(align) {
+ case 3: d |= data[2] << 16;
+ case 2: d |= data[1] << 8;
+ case 1: d |= data[0];
+ }
+
+ uint32_t k = (t >> sr) | (d << sl);
+ MIX(h,k,m);
+
+ data += align;
+ len -= align;
+
+ //----------
+ // Handle tail bytes
+
+ switch(len) {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0]; h *= m;
+ };
+ } else {
+ switch(len) {
+ case 3: d |= data[2] << 16;
+ case 2: d |= data[1] << 8;
+ case 1: d |= data[0];
+ case 0: h ^= (t >> sr) | (d << sl); h *= m;
+ }
+ }
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+ } else {
+ while(len >= 4) {
+ uint32_t k = *(uint32_t *)data;
+
+ MIX(h,k,m);
+
+ data += 4;
+ len -= 4;
+ }
+
+ //----------
+ // Handle tail bytes
+
+ switch(len) {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0]; h *= m;
+ };
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+ }
+}
+#undef MIX
+
+#endif // UPB_UNALIGNED_READS_OK
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool upb_dumptostderr(void *closure, const upb_status* status) {
+ UPB_UNUSED(closure);
+ fprintf(stderr, "%s\n", upb_status_errmsg(status));
+ return false;
+}
+
+// Guarantee null-termination and provide ellipsis truncation.
+// It may be tempting to "optimize" this by initializing these final
+// four bytes up-front and then being careful never to overwrite them,
+// this is safer and simpler.
+static void nullz(upb_status *status) {
+ const char *ellipsis = "...";
+ size_t len = strlen(ellipsis);
+ assert(sizeof(status->msg) > len);
+ memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len);
+}
+
+void upb_status_clear(upb_status *status) {
+ if (!status) return;
+ status->ok_ = true;
+ status->code_ = 0;
+ status->msg[0] = '\0';
+}
+
+bool upb_ok(const upb_status *status) { return status->ok_; }
+
+upb_errorspace *upb_status_errspace(const upb_status *status) {
+ return status->error_space_;
+}
+
+int upb_status_errcode(const upb_status *status) { return status->code_; }
+
+const char *upb_status_errmsg(const upb_status *status) { return status->msg; }
+
+void upb_status_seterrmsg(upb_status *status, const char *msg) {
+ if (!status) return;
+ status->ok_ = false;
+ strncpy(status->msg, msg, sizeof(status->msg));
+ nullz(status);
+}
+
+void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ upb_status_vseterrf(status, fmt, args);
+ va_end(args);
+}
+
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
+ if (!status) return;
+ status->ok_ = false;
+ vsnprintf(status->msg, sizeof(status->msg), fmt, args);
+ nullz(status);
+}
+
+void upb_status_seterrcode(upb_status *status, upb_errorspace *space,
+ int code) {
+ if (!status) return;
+ status->ok_ = false;
+ status->error_space_ = space;
+ status->code_ = code;
+ space->set_message(status, code);
+}
+
+void upb_status_copy(upb_status *to, const upb_status *from) {
+ if (!to) return;
+ *to = *from;
+}
+// This file was generated by upbc (the upb compiler).
+// Do not edit -- your changes will be discarded when the file is
+// regenerated.
+
+
+static const upb_msgdef msgs[20];
+static const upb_fielddef fields[81];
+static const upb_enumdef enums[4];
+static const upb_tabent strentries[236];
+static const upb_tabent intentries[14];
+static const _upb_value arrays[232];
+
+#ifdef UPB_DEBUG_REFS
+static upb_inttable reftables[212];
+#endif
+
+static const upb_msgdef msgs[20] = {
+ UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 27, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[0]),&reftables[0], &reftables[1]),
+ UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[16]),&reftables[2], &reftables[3]),
+ UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[20]),&reftables[4], &reftables[5]),
+ UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 7, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[0], &arrays[15], 8, 1), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[24]),&reftables[6], &reftables[7]),
+ UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[23], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[28]),&reftables[8], &reftables[9]),
+ UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[2], &arrays[27], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[32]),&reftables[10], &reftables[11]),
+ UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 19, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[31], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &strentries[36]),&reftables[12], &reftables[13]),
+ UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 14, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[4], &arrays[40], 32, 6), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[52]),&reftables[14], &reftables[15]),
+ UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 39, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[72], 12, 11), UPB_STRTABLE_INIT(11, 15, UPB_CTYPE_PTR, 4, &strentries[68]),&reftables[16], &reftables[17]),
+ UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[84], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[84]),&reftables[18], &reftables[19]),
+ UPB_MSGDEF_INIT("google.protobuf.FileOptions", 21, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[6], &arrays[86], 64, 9), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[88]),&reftables[20], &reftables[21]),
+ UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[8], &arrays[150], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[104]),&reftables[22], &reftables[23]),
+ UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 13, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[166], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &strentries[108]),&reftables[24], &reftables[25]),
+ UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[10], &arrays[171], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[116]),&reftables[26], &reftables[27]),
+ UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[175], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[120]),&reftables[28], &reftables[29]),
+ UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[12], &arrays[179], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[124]),&reftables[30], &reftables[31]),
+ UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[183], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[128]),&reftables[32], &reftables[33]),
+ UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 14, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[185], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &strentries[132]),&reftables[34], &reftables[35]),
+ UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[190], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[140]),&reftables[36], &reftables[37]),
+ UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[199], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[156]),&reftables[38], &reftables[39]),
+};
+
+static const upb_fielddef fields[81] = {
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "aggregate_value", 8, &msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "allow_alias", 2, &msgs[3], NULL, 6, 1, {0},&reftables[42], &reftables[43]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "cc_generic_services", 16, &msgs[10], NULL, 17, 6, {0},&reftables[44], &reftables[45]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "ctype", 1, &msgs[7], UPB_UPCAST(&enums[2]), 6, 1, {0},&reftables[46], &reftables[47]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "default_value", 7, &msgs[6], NULL, 16, 7, {0},&reftables[48], &reftables[49]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "dependency", 3, &msgs[8], NULL, 30, 8, {0},&reftables[50], &reftables[51]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[7], NULL, 8, 3, {0},&reftables[52], &reftables[53]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, false, false, false, "double_value", 6, &msgs[18], NULL, 11, 4, {0},&reftables[54], &reftables[55]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[1], NULL, 3, 1, {0},&reftables[56], &reftables[57]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 4, &msgs[0], UPB_UPCAST(&msgs[2]), 16, 2, {0},&reftables[58], &reftables[59]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 5, &msgs[8], UPB_UPCAST(&msgs[2]), 13, 1, {0},&reftables[60], &reftables[61]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "experimental_map_key", 9, &msgs[7], NULL, 10, 5, {0},&reftables[62], &reftables[63]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "extendee", 2, &msgs[6], NULL, 7, 2, {0},&reftables[64], &reftables[65]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 7, &msgs[8], UPB_UPCAST(&msgs[6]), 19, 3, {0},&reftables[66], &reftables[67]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 6, &msgs[0], UPB_UPCAST(&msgs[6]), 22, 4, {0},&reftables[68], &reftables[69]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension_range", 5, &msgs[0], UPB_UPCAST(&msgs[1]), 19, 3, {0},&reftables[70], &reftables[71]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "field", 2, &msgs[0], UPB_UPCAST(&msgs[6]), 10, 0, {0},&reftables[72], &reftables[73]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "file", 1, &msgs[9], UPB_UPCAST(&msgs[8]), 5, 0, {0},&reftables[74], &reftables[75]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "go_package", 11, &msgs[10], NULL, 14, 5, {0},&reftables[76], &reftables[77]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "identifier_value", 3, &msgs[18], NULL, 6, 1, {0},&reftables[78], &reftables[79]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "input_type", 2, &msgs[12], NULL, 7, 2, {0},&reftables[80], &reftables[81]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, false, false, false, "is_extension", 2, &msgs[19], NULL, 5, 1, {0},&reftables[82], &reftables[83]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generate_equals_and_hash", 20, &msgs[10], NULL, 20, 9, {0},&reftables[84], &reftables[85]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generic_services", 17, &msgs[10], NULL, 18, 7, {0},&reftables[86], &reftables[87]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_multiple_files", 10, &msgs[10], NULL, 13, 4, {0},&reftables[88], &reftables[89]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_outer_classname", 8, &msgs[10], NULL, 9, 2, {0},&reftables[90], &reftables[91]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_package", 1, &msgs[10], NULL, 6, 1, {0},&reftables[92], &reftables[93]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "label", 4, &msgs[6], UPB_UPCAST(&enums[0]), 11, 4, {0},&reftables[94], &reftables[95]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "lazy", 5, &msgs[7], NULL, 9, 4, {0},&reftables[96], &reftables[97]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "leading_comments", 3, &msgs[17], NULL, 8, 2, {0},&reftables[98], &reftables[99]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "location", 1, &msgs[16], UPB_UPCAST(&msgs[17]), 5, 0, {0},&reftables[100], &reftables[101]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "message_set_wire_format", 1, &msgs[11], NULL, 6, 1, {0},&reftables[102], &reftables[103]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "message_type", 4, &msgs[8], UPB_UPCAST(&msgs[0]), 10, 0, {0},&reftables[104], &reftables[105]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "method", 2, &msgs[14], UPB_UPCAST(&msgs[12]), 6, 0, {0},&reftables[106], &reftables[107]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[8], NULL, 22, 6, {0},&reftables[108], &reftables[109]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[14], NULL, 8, 2, {0},&reftables[110], &reftables[111]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "name", 2, &msgs[18], UPB_UPCAST(&msgs[19]), 5, 0, {0},&reftables[112], &reftables[113]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[4], NULL, 4, 1, {0},&reftables[114], &reftables[115]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[0], NULL, 24, 6, {0},&reftables[116], &reftables[117]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[12], NULL, 4, 1, {0},&reftables[118], &reftables[119]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[2], NULL, 8, 2, {0},&reftables[120], &reftables[121]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[6], NULL, 4, 1, {0},&reftables[122], &reftables[123]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, false, false, false, "name_part", 1, &msgs[19], NULL, 2, 0, {0},&reftables[124], &reftables[125]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, false, false, false, "negative_int_value", 5, &msgs[18], NULL, 10, 3, {0},&reftables[126], &reftables[127]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "nested_type", 3, &msgs[0], UPB_UPCAST(&msgs[0]), 13, 1, {0},&reftables[128], &reftables[129]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "no_standard_descriptor_accessor", 2, &msgs[11], NULL, 7, 2, {0},&reftables[130], &reftables[131]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 3, &msgs[6], NULL, 10, 3, {0},&reftables[132], &reftables[133]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 2, &msgs[4], NULL, 7, 2, {0},&reftables[134], &reftables[135]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "optimize_for", 9, &msgs[10], UPB_UPCAST(&enums[3]), 12, 3, {0},&reftables[136], &reftables[137]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 7, &msgs[0], UPB_UPCAST(&msgs[11]), 23, 5, {0},&reftables[138], &reftables[139]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[2], UPB_UPCAST(&msgs[3]), 7, 1, {0},&reftables[140], &reftables[141]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[6], UPB_UPCAST(&msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[4], UPB_UPCAST(&msgs[5]), 3, 0, {0},&reftables[144], &reftables[145]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[8], UPB_UPCAST(&msgs[10]), 20, 4, {0},&reftables[146], &reftables[147]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[14], UPB_UPCAST(&msgs[15]), 7, 1, {0},&reftables[148], &reftables[149]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 4, &msgs[12], UPB_UPCAST(&msgs[13]), 3, 0, {0},&reftables[150], &reftables[151]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "output_type", 3, &msgs[12], NULL, 10, 3, {0},&reftables[152], &reftables[153]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "package", 2, &msgs[8], NULL, 25, 7, {0},&reftables[154], &reftables[155]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "packed", 2, &msgs[7], NULL, 7, 2, {0},&reftables[156], &reftables[157]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "path", 1, &msgs[17], NULL, 4, 0, {0},&reftables[158], &reftables[159]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, false, false, false, "positive_int_value", 4, &msgs[18], NULL, 9, 2, {0},&reftables[160], &reftables[161]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "public_dependency", 10, &msgs[8], NULL, 35, 9, {0},&reftables[162], &reftables[163]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "py_generic_services", 18, &msgs[10], NULL, 19, 8, {0},&reftables[164], &reftables[165]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "service", 6, &msgs[8], UPB_UPCAST(&msgs[14]), 16, 2, {0},&reftables[166], &reftables[167]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "source_code_info", 9, &msgs[8], UPB_UPCAST(&msgs[16]), 21, 5, {0},&reftables[168], &reftables[169]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "span", 2, &msgs[17], NULL, 7, 1, {0},&reftables[170], &reftables[171]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[1], NULL, 2, 0, {0},&reftables[172], &reftables[173]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, false, false, false, "string_value", 7, &msgs[18], NULL, 12, 5, {0},&reftables[174], &reftables[175]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "trailing_comments", 4, &msgs[17], NULL, 11, 3, {0},&reftables[176], &reftables[177]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "type", 5, &msgs[6], UPB_UPCAST(&enums[1]), 12, 5, {0},&reftables[178], &reftables[179]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "type_name", 6, &msgs[6], NULL, 13, 6, {0},&reftables[180], &reftables[181]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[5], UPB_UPCAST(&msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[15], UPB_UPCAST(&msgs[18]), 5, 0, {0},&reftables[184], &reftables[185]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[3], UPB_UPCAST(&msgs[18]), 5, 0, {0},&reftables[186], &reftables[187]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[13], UPB_UPCAST(&msgs[18]), 5, 0, {0},&reftables[188], &reftables[189]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[10], UPB_UPCAST(&msgs[18]), 5, 0, {0},&reftables[190], &reftables[191]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[11], UPB_UPCAST(&msgs[18]), 5, 0, {0},&reftables[192], &reftables[193]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[7], UPB_UPCAST(&msgs[18]), 5, 0, {0},&reftables[194], &reftables[195]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "value", 2, &msgs[2], UPB_UPCAST(&msgs[4]), 6, 0, {0},&reftables[196], &reftables[197]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "weak", 10, &msgs[7], NULL, 13, 6, {0},&reftables[198], &reftables[199]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "weak_dependency", 11, &msgs[8], NULL, 38, 10, {0},&reftables[200], &reftables[201]),
+};
+
+static const upb_enumdef enums[4] = {
+ UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Label", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[160]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[202], 4, 3), 0, &reftables[202], &reftables[203]),
+ UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Type", UPB_STRTABLE_INIT(18, 31, UPB_CTYPE_INT32, 5, &strentries[164]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[206], 19, 18), 0, &reftables[204], &reftables[205]),
+ UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.CType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[196]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[225], 3, 3), 0, &reftables[206], &reftables[207]),
+ UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[200]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[228], 4, 3), 0, &reftables[208], &reftables[209]),
+};
+
+static const upb_tabent strentries[236] = {
+ {UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&fields[14]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[38]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("field"), UPB_VALUE_INIT_CONSTPTR(&fields[16]), NULL},
+ {UPB_TABKEY_STR("extension_range"), UPB_VALUE_INIT_CONSTPTR(&fields[15]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("nested_type"), UPB_VALUE_INIT_CONSTPTR(&fields[44]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[49]), NULL},
+ {UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&fields[9]), &strentries[14]},
+ {UPB_TABKEY_STR("start"), UPB_VALUE_INIT_CONSTPTR(&fields[66]), NULL},
+ {UPB_TABKEY_STR("end"), UPB_VALUE_INIT_CONSTPTR(&fields[8]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("value"), UPB_VALUE_INIT_CONSTPTR(&fields[78]), NULL},
+ {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[50]), NULL},
+ {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[40]), &strentries[22]},
+ {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[73]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("allow_alias"), UPB_VALUE_INIT_CONSTPTR(&fields[1]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&fields[47]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[52]), NULL},
+ {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[37]), &strentries[30]},
+ {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[71]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("label"), UPB_VALUE_INIT_CONSTPTR(&fields[27]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[41]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&fields[46]), &strentries[49]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("type_name"), UPB_VALUE_INIT_CONSTPTR(&fields[70]), NULL},
+ {UPB_TABKEY_STR("extendee"), UPB_VALUE_INIT_CONSTPTR(&fields[12]), NULL},
+ {UPB_TABKEY_STR("type"), UPB_VALUE_INIT_CONSTPTR(&fields[69]), &strentries[48]},
+ {UPB_TABKEY_STR("default_value"), UPB_VALUE_INIT_CONSTPTR(&fields[4]), NULL},
+ {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[51]), NULL},
+ {UPB_TABKEY_STR("experimental_map_key"), UPB_VALUE_INIT_CONSTPTR(&fields[11]), &strentries[67]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("weak"), UPB_VALUE_INIT_CONSTPTR(&fields[79]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("packed"), UPB_VALUE_INIT_CONSTPTR(&fields[58]), NULL},
+ {UPB_TABKEY_STR("lazy"), UPB_VALUE_INIT_CONSTPTR(&fields[28]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("ctype"), UPB_VALUE_INIT_CONSTPTR(&fields[3]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("deprecated"), UPB_VALUE_INIT_CONSTPTR(&fields[6]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[77]), NULL},
+ {UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&fields[13]), NULL},
+ {UPB_TABKEY_STR("weak_dependency"), UPB_VALUE_INIT_CONSTPTR(&fields[80]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[34]), NULL},
+ {UPB_TABKEY_STR("service"), UPB_VALUE_INIT_CONSTPTR(&fields[63]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("source_code_info"), UPB_VALUE_INIT_CONSTPTR(&fields[64]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("dependency"), UPB_VALUE_INIT_CONSTPTR(&fields[5]), NULL},
+ {UPB_TABKEY_STR("message_type"), UPB_VALUE_INIT_CONSTPTR(&fields[32]), NULL},
+ {UPB_TABKEY_STR("package"), UPB_VALUE_INIT_CONSTPTR(&fields[57]), NULL},
+ {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[53]), &strentries[82]},
+ {UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&fields[10]), NULL},
+ {UPB_TABKEY_STR("public_dependency"), UPB_VALUE_INIT_CONSTPTR(&fields[61]), &strentries[81]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("file"), UPB_VALUE_INIT_CONSTPTR(&fields[17]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[75]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("cc_generic_services"), UPB_VALUE_INIT_CONSTPTR(&fields[2]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("java_multiple_files"), UPB_VALUE_INIT_CONSTPTR(&fields[24]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("java_generic_services"), UPB_VALUE_INIT_CONSTPTR(&fields[23]), &strentries[102]},
+ {UPB_TABKEY_STR("java_generate_equals_and_hash"), UPB_VALUE_INIT_CONSTPTR(&fields[22]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("go_package"), UPB_VALUE_INIT_CONSTPTR(&fields[18]), NULL},
+ {UPB_TABKEY_STR("java_package"), UPB_VALUE_INIT_CONSTPTR(&fields[26]), NULL},
+ {UPB_TABKEY_STR("optimize_for"), UPB_VALUE_INIT_CONSTPTR(&fields[48]), NULL},
+ {UPB_TABKEY_STR("py_generic_services"), UPB_VALUE_INIT_CONSTPTR(&fields[62]), NULL},
+ {UPB_TABKEY_STR("java_outer_classname"), UPB_VALUE_INIT_CONSTPTR(&fields[25]), NULL},
+ {UPB_TABKEY_STR("message_set_wire_format"), UPB_VALUE_INIT_CONSTPTR(&fields[31]), &strentries[106]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[76]), NULL},
+ {UPB_TABKEY_STR("no_standard_descriptor_accessor"), UPB_VALUE_INIT_CONSTPTR(&fields[45]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[39]), NULL},
+ {UPB_TABKEY_STR("input_type"), UPB_VALUE_INIT_CONSTPTR(&fields[20]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("output_type"), UPB_VALUE_INIT_CONSTPTR(&fields[56]), NULL},
+ {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[55]), NULL},
+ {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[74]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[54]), &strentries[122]},
+ {UPB_TABKEY_STR("method"), UPB_VALUE_INIT_CONSTPTR(&fields[33]), NULL},
+ {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[35]), &strentries[121]},
+ {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[72]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("location"), UPB_VALUE_INIT_CONSTPTR(&fields[30]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("span"), UPB_VALUE_INIT_CONSTPTR(&fields[65]), &strentries[139]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("trailing_comments"), UPB_VALUE_INIT_CONSTPTR(&fields[68]), NULL},
+ {UPB_TABKEY_STR("leading_comments"), UPB_VALUE_INIT_CONSTPTR(&fields[29]), &strentries[137]},
+ {UPB_TABKEY_STR("path"), UPB_VALUE_INIT_CONSTPTR(&fields[59]), NULL},
+ {UPB_TABKEY_STR("double_value"), UPB_VALUE_INIT_CONSTPTR(&fields[7]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[36]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("negative_int_value"), UPB_VALUE_INIT_CONSTPTR(&fields[43]), NULL},
+ {UPB_TABKEY_STR("aggregate_value"), UPB_VALUE_INIT_CONSTPTR(&fields[0]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("positive_int_value"), UPB_VALUE_INIT_CONSTPTR(&fields[60]), NULL},
+ {UPB_TABKEY_STR("identifier_value"), UPB_VALUE_INIT_CONSTPTR(&fields[19]), NULL},
+ {UPB_TABKEY_STR("string_value"), UPB_VALUE_INIT_CONSTPTR(&fields[67]), &strentries[154]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("is_extension"), UPB_VALUE_INIT_CONSTPTR(&fields[21]), NULL},
+ {UPB_TABKEY_STR("name_part"), UPB_VALUE_INIT_CONSTPTR(&fields[42]), NULL},
+ {UPB_TABKEY_STR("LABEL_REQUIRED"), UPB_VALUE_INIT_INT32(2), &strentries[162]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("LABEL_REPEATED"), UPB_VALUE_INIT_INT32(3), NULL},
+ {UPB_TABKEY_STR("LABEL_OPTIONAL"), UPB_VALUE_INIT_INT32(1), NULL},
+ {UPB_TABKEY_STR("TYPE_FIXED64"), UPB_VALUE_INIT_INT32(6), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("TYPE_STRING"), UPB_VALUE_INIT_INT32(9), NULL},
+ {UPB_TABKEY_STR("TYPE_FLOAT"), UPB_VALUE_INIT_INT32(2), &strentries[193]},
+ {UPB_TABKEY_STR("TYPE_DOUBLE"), UPB_VALUE_INIT_INT32(1), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("TYPE_INT32"), UPB_VALUE_INIT_INT32(5), NULL},
+ {UPB_TABKEY_STR("TYPE_SFIXED32"), UPB_VALUE_INIT_INT32(15), NULL},
+ {UPB_TABKEY_STR("TYPE_FIXED32"), UPB_VALUE_INIT_INT32(7), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("TYPE_MESSAGE"), UPB_VALUE_INIT_INT32(11), &strentries[194]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("TYPE_INT64"), UPB_VALUE_INIT_INT32(3), &strentries[191]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("TYPE_ENUM"), UPB_VALUE_INIT_INT32(14), NULL},
+ {UPB_TABKEY_STR("TYPE_UINT32"), UPB_VALUE_INIT_INT32(13), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("TYPE_UINT64"), UPB_VALUE_INIT_INT32(4), &strentries[190]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("TYPE_SFIXED64"), UPB_VALUE_INIT_INT32(16), NULL},
+ {UPB_TABKEY_STR("TYPE_BYTES"), UPB_VALUE_INIT_INT32(12), NULL},
+ {UPB_TABKEY_STR("TYPE_SINT64"), UPB_VALUE_INIT_INT32(18), NULL},
+ {UPB_TABKEY_STR("TYPE_BOOL"), UPB_VALUE_INIT_INT32(8), NULL},
+ {UPB_TABKEY_STR("TYPE_GROUP"), UPB_VALUE_INIT_INT32(10), NULL},
+ {UPB_TABKEY_STR("TYPE_SINT32"), UPB_VALUE_INIT_INT32(17), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("CORD"), UPB_VALUE_INIT_INT32(1), NULL},
+ {UPB_TABKEY_STR("STRING"), UPB_VALUE_INIT_INT32(0), &strentries[197]},
+ {UPB_TABKEY_STR("STRING_PIECE"), UPB_VALUE_INIT_INT32(2), NULL},
+ {UPB_TABKEY_STR("CODE_SIZE"), UPB_VALUE_INIT_INT32(2), NULL},
+ {UPB_TABKEY_STR("SPEED"), UPB_VALUE_INIT_INT32(1), &strentries[203]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("LITE_RUNTIME"), UPB_VALUE_INIT_INT32(3), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("google.protobuf.SourceCodeInfo.Location"), UPB_VALUE_INIT_CONSTPTR(&msgs[17]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.UninterpretedOption"), UPB_VALUE_INIT_CONSTPTR(&msgs[18]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.FileDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[8]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.MethodDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[12]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("google.protobuf.EnumValueOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[5]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("google.protobuf.DescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[0]), &strentries[228]},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("google.protobuf.SourceCodeInfo"), UPB_VALUE_INIT_CONSTPTR(&msgs[16]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.FieldDescriptorProto.Type"), UPB_VALUE_INIT_CONSTPTR(&enums[1]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.DescriptorProto.ExtensionRange"), UPB_VALUE_INIT_CONSTPTR(&msgs[1]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_STR("google.protobuf.EnumValueDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[4]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.FieldOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[7]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.FileOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[10]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.EnumDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[2]), &strentries[233]},
+ {UPB_TABKEY_STR("google.protobuf.FieldDescriptorProto.Label"), UPB_VALUE_INIT_CONSTPTR(&enums[0]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.ServiceDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[14]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.FieldOptions.CType"), UPB_VALUE_INIT_CONSTPTR(&enums[2]), &strentries[229]},
+ {UPB_TABKEY_STR("google.protobuf.FileDescriptorSet"), UPB_VALUE_INIT_CONSTPTR(&msgs[9]), &strentries[235]},
+ {UPB_TABKEY_STR("google.protobuf.EnumOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[3]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.FieldDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[6]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.FileOptions.OptimizeMode"), UPB_VALUE_INIT_CONSTPTR(&enums[3]), &strentries[221]},
+ {UPB_TABKEY_STR("google.protobuf.ServiceOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[15]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.MessageOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[11]), NULL},
+ {UPB_TABKEY_STR("google.protobuf.MethodOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[13]), &strentries[226]},
+ {UPB_TABKEY_STR("google.protobuf.UninterpretedOption.NamePart"), UPB_VALUE_INIT_CONSTPTR(&msgs[19]), NULL},
+};
+
+static const upb_tabent intentries[14] = {
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[73]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[71]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[77]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[75]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[76]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[74]), NULL},
+ {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
+ {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[72]), NULL},
+};
+
+static const _upb_value arrays[232] = {
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[38]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[16]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[44]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[9]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[15]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[14]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[49]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[66]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[8]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[40]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[78]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[50]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[1]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[37]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[47]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[52]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[41]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[12]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[46]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[27]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[69]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[70]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[4]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[51]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[3]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[58]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[6]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[28]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[11]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[79]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[34]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[57]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[5]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[32]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[10]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[63]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[13]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[53]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[64]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[61]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[80]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[17]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[26]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[25]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[48]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[24]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[18]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[2]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[23]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[62]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[22]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[31]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[45]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[39]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[20]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[56]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[55]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[35]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[33]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[54]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[30]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[59]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[65]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[29]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[68]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[36]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[19]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[60]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[43]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[7]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[67]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[0]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR(&fields[42]),
+ UPB_VALUE_INIT_CONSTPTR(&fields[21]),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR("LABEL_OPTIONAL"),
+ UPB_VALUE_INIT_CONSTPTR("LABEL_REQUIRED"),
+ UPB_VALUE_INIT_CONSTPTR("LABEL_REPEATED"),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR("TYPE_DOUBLE"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_FLOAT"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_INT64"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_UINT64"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_INT32"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED64"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED32"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_BOOL"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_STRING"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_GROUP"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_MESSAGE"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_BYTES"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_UINT32"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_ENUM"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED32"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED64"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_SINT32"),
+ UPB_VALUE_INIT_CONSTPTR("TYPE_SINT64"),
+ UPB_VALUE_INIT_CONSTPTR("STRING"),
+ UPB_VALUE_INIT_CONSTPTR("CORD"),
+ UPB_VALUE_INIT_CONSTPTR("STRING_PIECE"),
+ UPB_ARRAY_EMPTYENT,
+ UPB_VALUE_INIT_CONSTPTR("SPEED"),
+ UPB_VALUE_INIT_CONSTPTR("CODE_SIZE"),
+ UPB_VALUE_INIT_CONSTPTR("LITE_RUNTIME"),
+};
+
+static const upb_symtab symtab = UPB_SYMTAB_INIT(UPB_STRTABLE_INIT(24, 31, UPB_CTYPE_PTR, 5, &strentries[204]), &reftables[210], &reftables[211]);
+
+const upb_symtab *upbdefs_google_protobuf_descriptor(const void *owner) {
+ upb_symtab_ref(&symtab, owner);
+ return &symtab;
+}
+
+#ifdef UPB_DEBUG_REFS
+static upb_inttable reftables[212] = {
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+ UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+};
+#endif
+
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2008-2009 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * XXX: The routines in this file that consume a string do not currently
+ * support having the string span buffers. In the future, as upb_sink and
+ * its buffering/sharing functionality evolve there should be an easy and
+ * idiomatic way of correctly handling this case. For now, we accept this
+ * limitation since we currently only parse descriptors from single strings.
+ */
+
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char *upb_strndup(const char *buf, size_t n) {
+ char *ret = malloc(n + 1);
+ if (!ret) return NULL;
+ memcpy(ret, buf, n);
+ ret[n] = '\0';
+ return ret;
+}
+
+// Returns a newly allocated string that joins input strings together, for
+// example:
+// join("Foo.Bar", "Baz") -> "Foo.Bar.Baz"
+// join("", "Baz") -> "Baz"
+// Caller owns a ref on the returned string.
+static char *upb_join(const char *base, const char *name) {
+ if (!base || strlen(base) == 0) {
+ return upb_strdup(name);
+ } else {
+ char *ret = malloc(strlen(base) + strlen(name) + 2);
+ ret[0] = '\0';
+ strcat(ret, base);
+ strcat(ret, ".");
+ strcat(ret, name);
+ return ret;
+ }
+}
+
+
+/* upb_deflist ****************************************************************/
+
+void upb_deflist_init(upb_deflist *l) {
+ l->size = 0;
+ l->defs = NULL;
+ l->len = 0;
+ l->owned = true;
+}
+
+void upb_deflist_uninit(upb_deflist *l) {
+ if (l->owned)
+ for(size_t i = 0; i < l->len; i++)
+ upb_def_unref(l->defs[i], l);
+ free(l->defs);
+}
+
+bool upb_deflist_push(upb_deflist *l, upb_def *d) {
+ if(++l->len >= l->size) {
+ size_t new_size = UPB_MAX(l->size, 4);
+ new_size *= 2;
+ l->defs = realloc(l->defs, new_size * sizeof(void *));
+ if (!l->defs) return false;
+ l->size = new_size;
+ }
+ l->defs[l->len - 1] = d;
+ return true;
+}
+
+void upb_deflist_donaterefs(upb_deflist *l, void *owner) {
+ assert(l->owned);
+ for (size_t i = 0; i < l->len; i++)
+ upb_def_donateref(l->defs[i], l, owner);
+ l->owned = false;
+}
+
+static upb_def *upb_deflist_last(upb_deflist *l) {
+ return l->defs[l->len-1];
+}
+
+// Qualify the defname for all defs starting with offset "start" with "str".
+static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) {
+ for (uint32_t i = start; i < l->len; i++) {
+ upb_def *def = l->defs[i];
+ char *name = upb_join(str, upb_def_fullname(def));
+ upb_def_setfullname(def, name, NULL);
+ free(name);
+ }
+}
+
+
+/* upb_descreader ************************************************************/
+
+void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers,
+ upb_status *status) {
+ UPB_UNUSED(status);
+ upb_deflist_init(&r->defs);
+ upb_sink_reset(upb_descreader_input(r), handlers, r);
+ r->stack_len = 0;
+ r->name = NULL;
+ r->default_string = NULL;
+}
+
+void upb_descreader_uninit(upb_descreader *r) {
+ free(r->name);
+ upb_deflist_uninit(&r->defs);
+ free(r->default_string);
+ while (r->stack_len > 0) {
+ upb_descreader_frame *f = &r->stack[--r->stack_len];
+ free(f->name);
+ }
+}
+
+upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n) {
+ *n = r->defs.len;
+ upb_deflist_donaterefs(&r->defs, owner);
+ return r->defs.defs;
+}
+
+upb_sink *upb_descreader_input(upb_descreader *r) {
+ return &r->sink;
+}
+
+static upb_msgdef *upb_descreader_top(upb_descreader *r) {
+ assert(r->stack_len > 1);
+ int index = r->stack[r->stack_len-1].start - 1;
+ assert(index >= 0);
+ return upb_downcast_msgdef_mutable(r->defs.defs[index]);
+}
+
+static upb_def *upb_descreader_last(upb_descreader *r) {
+ return upb_deflist_last(&r->defs);
+}
+
+// Start/end handlers for FileDescriptorProto and DescriptorProto (the two
+// entities that have names and can contain sub-definitions.
+void upb_descreader_startcontainer(upb_descreader *r) {
+ upb_descreader_frame *f = &r->stack[r->stack_len++];
+ f->start = r->defs.len;
+ f->name = NULL;
+}
+
+void upb_descreader_endcontainer(upb_descreader *r) {
+ upb_descreader_frame *f = &r->stack[--r->stack_len];
+ upb_deflist_qualify(&r->defs, f->name, f->start);
+ free(f->name);
+ f->name = NULL;
+}
+
+void upb_descreader_setscopename(upb_descreader *r, char *str) {
+ upb_descreader_frame *f = &r->stack[r->stack_len-1];
+ free(f->name);
+ f->name = str;
+}
+
+// Handlers for google.protobuf.FileDescriptorProto.
+static bool file_startmsg(void *r, const void *hd) {
+ UPB_UNUSED(hd);
+ upb_descreader_startcontainer(r);
+ return true;
+}
+
+static bool file_endmsg(void *closure, const void *hd, upb_status *status) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(status);
+ upb_descreader *r = closure;
+ upb_descreader_endcontainer(r);
+ return true;
+}
+
+static size_t file_onpackage(void *closure, const void *hd, const char *buf,
+ size_t n, const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ upb_descreader *r = closure;
+ // XXX: see comment at the top of the file.
+ upb_descreader_setscopename(r, upb_strndup(buf, n));
+ return n;
+}
+
+// Handlers for google.protobuf.EnumValueDescriptorProto.
+static bool enumval_startmsg(void *closure, const void *hd) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ r->saw_number = false;
+ r->saw_name = false;
+ return true;
+}
+
+static size_t enumval_onname(void *closure, const void *hd, const char *buf,
+ size_t n, const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ upb_descreader *r = closure;
+ // XXX: see comment at the top of the file.
+ free(r->name);
+ r->name = upb_strndup(buf, n);
+ r->saw_name = true;
+ return n;
+}
+
+static bool enumval_onnumber(void *closure, const void *hd, int32_t val) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ r->number = val;
+ r->saw_number = true;
+ return true;
+}
+
+static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ if(!r->saw_number || !r->saw_name) {
+ upb_status_seterrmsg(status, "Enum value missing name or number.");
+ return false;
+ }
+ upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+ upb_enumdef_addval(e, r->name, r->number, status);
+ free(r->name);
+ r->name = NULL;
+ return true;
+}
+
+
+// Handlers for google.protobuf.EnumDescriptorProto.
+static bool enum_startmsg(void *closure, const void *hd) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_deflist_push(&r->defs, UPB_UPCAST(upb_enumdef_new(&r->defs)));
+ return true;
+}
+
+static bool enum_endmsg(void *closure, const void *hd, upb_status *status) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+ if (upb_def_fullname(upb_descreader_last(r)) == NULL) {
+ upb_status_seterrmsg(status, "Enum had no name.");
+ return false;
+ }
+ if (upb_enumdef_numvals(e) == 0) {
+ upb_status_seterrmsg(status, "Enum had no values.");
+ return false;
+ }
+ return true;
+}
+
+static size_t enum_onname(void *closure, const void *hd, const char *buf,
+ size_t n, const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ upb_descreader *r = closure;
+ // XXX: see comment at the top of the file.
+ char *fullname = upb_strndup(buf, n);
+ upb_def_setfullname(upb_descreader_last(r), fullname, NULL);
+ free(fullname);
+ return n;
+}
+
+// Handlers for google.protobuf.FieldDescriptorProto
+static bool field_startmsg(void *closure, const void *hd) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ r->f = upb_fielddef_new(&r->defs);
+ free(r->default_string);
+ r->default_string = NULL;
+
+ // fielddefs default to packed, but descriptors default to non-packed.
+ upb_fielddef_setpacked(r->f, false);
+ return true;
+}
+
+// Converts the default value in string "str" into "d". Passes a ref on str.
+// Returns true on success.
+static bool parse_default(char *str, upb_fielddef *f) {
+ bool success = true;
+ char *end;
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32: {
+ long val = strtol(str, &end, 0);
+ if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end)
+ success = false;
+ else
+ upb_fielddef_setdefaultint32(f, val);
+ break;
+ }
+ case UPB_TYPE_INT64: {
+ long long val = strtoll(str, &end, 0);
+ if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end)
+ success = false;
+ else
+ upb_fielddef_setdefaultint64(f, val);
+ break;
+ }
+ case UPB_TYPE_UINT32: {
+ long val = strtoul(str, &end, 0);
+ if (val > UINT32_MAX || errno == ERANGE || *end)
+ success = false;
+ else
+ upb_fielddef_setdefaultuint32(f, val);
+ break;
+ }
+ case UPB_TYPE_UINT64: {
+ unsigned long long val = strtoull(str, &end, 0);
+ if (val > UINT64_MAX || errno == ERANGE || *end)
+ success = false;
+ else
+ upb_fielddef_setdefaultuint64(f, val);
+ break;
+ }
+ case UPB_TYPE_DOUBLE: {
+ double val = strtod(str, &end);
+ if (errno == ERANGE || *end)
+ success = false;
+ else
+ upb_fielddef_setdefaultdouble(f, val);
+ break;
+ }
+ case UPB_TYPE_FLOAT: {
+ float val = strtof(str, &end);
+ if (errno == ERANGE || *end)
+ success = false;
+ else
+ upb_fielddef_setdefaultfloat(f, val);
+ break;
+ }
+ case UPB_TYPE_BOOL: {
+ if (strcmp(str, "false") == 0)
+ upb_fielddef_setdefaultbool(f, false);
+ else if (strcmp(str, "true") == 0)
+ upb_fielddef_setdefaultbool(f, true);
+ else
+ success = false;
+ break;
+ }
+ default: abort();
+ }
+ return success;
+}
+
+static bool field_endmsg(void *closure, const void *hd, upb_status *status) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_fielddef *f = r->f;
+ // TODO: verify that all required fields were present.
+ assert(upb_fielddef_number(f) != 0);
+ assert(upb_fielddef_name(f) != NULL);
+ assert((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f));
+
+ if (r->default_string) {
+ if (upb_fielddef_issubmsg(f)) {
+ upb_status_seterrmsg(status, "Submessages cannot have defaults.");
+ return false;
+ }
+ if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+ upb_fielddef_setdefaultcstr(f, r->default_string, NULL);
+ } else {
+ if (r->default_string && !parse_default(r->default_string, f)) {
+ // We don't worry too much about giving a great error message since the
+ // compiler should have ensured this was correct.
+ upb_status_seterrmsg(status, "Error converting default value.");
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool field_onlazy(void *closure, const void *hd, bool val) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_fielddef_setlazy(r->f, val);
+ return true;
+}
+
+static bool field_onpacked(void *closure, const void *hd, bool val) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_fielddef_setpacked(r->f, val);
+ return true;
+}
+
+static bool field_ontype(void *closure, const void *hd, int32_t val) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_fielddef_setdescriptortype(r->f, val);
+ return true;
+}
+
+static bool field_onlabel(void *closure, const void *hd, int32_t val) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_fielddef_setlabel(r->f, val);
+ return true;
+}
+
+static bool field_onnumber(void *closure, const void *hd, int32_t val) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ bool ok = upb_fielddef_setnumber(r->f, val, NULL);
+ UPB_ASSERT_VAR(ok, ok);
+ return true;
+}
+
+static size_t field_onname(void *closure, const void *hd, const char *buf,
+ size_t n, const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ upb_descreader *r = closure;
+ // XXX: see comment at the top of the file.
+ char *name = upb_strndup(buf, n);
+ upb_fielddef_setname(r->f, name, NULL);
+ free(name);
+ return n;
+}
+
+static size_t field_ontypename(void *closure, const void *hd, const char *buf,
+ size_t n, const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ upb_descreader *r = closure;
+ // XXX: see comment at the top of the file.
+ char *name = upb_strndup(buf, n);
+ upb_fielddef_setsubdefname(r->f, name, NULL);
+ free(name);
+ return n;
+}
+
+static size_t field_onextendee(void *closure, const void *hd, const char *buf,
+ size_t n, const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ upb_descreader *r = closure;
+ // XXX: see comment at the top of the file.
+ char *name = upb_strndup(buf, n);
+ upb_fielddef_setcontainingtypename(r->f, name, NULL);
+ free(name);
+ return n;
+}
+
+static size_t field_ondefaultval(void *closure, const void *hd, const char *buf,
+ size_t n, const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ upb_descreader *r = closure;
+ // Have to convert from string to the correct type, but we might not know the
+ // type yet, so we save it as a string until the end of the field.
+ // XXX: see comment at the top of the file.
+ free(r->default_string);
+ r->default_string = upb_strndup(buf, n);
+ return n;
+}
+
+// Handlers for google.protobuf.DescriptorProto (representing a message).
+static bool msg_startmsg(void *closure, const void *hd) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_deflist_push(&r->defs, UPB_UPCAST(upb_msgdef_new(&r->defs)));
+ upb_descreader_startcontainer(r);
+ return true;
+}
+
+static bool msg_endmsg(void *closure, const void *hd, upb_status *status) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_msgdef *m = upb_descreader_top(r);
+ if(!upb_def_fullname(UPB_UPCAST(m))) {
+ upb_status_seterrmsg(status, "Encountered message with no name.");
+ return false;
+ }
+ upb_descreader_endcontainer(r);
+ return true;
+}
+
+static size_t msg_onname(void *closure, const void *hd, const char *buf,
+ size_t n, const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ upb_descreader *r = closure;
+ upb_msgdef *m = upb_descreader_top(r);
+ // XXX: see comment at the top of the file.
+ char *name = upb_strndup(buf, n);
+ upb_def_setfullname(UPB_UPCAST(m), name, NULL);
+ upb_descreader_setscopename(r, name); // Passes ownership of name.
+ return n;
+}
+
+static bool msg_onendfield(void *closure, const void *hd) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ upb_msgdef *m = upb_descreader_top(r);
+ upb_msgdef_addfield(m, r->f, &r->defs, NULL);
+ r->f = NULL;
+ return true;
+}
+
+static bool pushextension(void *closure, const void *hd) {
+ UPB_UNUSED(hd);
+ upb_descreader *r = closure;
+ assert(upb_fielddef_containingtypename(r->f));
+ upb_fielddef_setisextension(r->f, true);
+ upb_deflist_push(&r->defs, UPB_UPCAST(r->f));
+ r->f = NULL;
+ return true;
+}
+
+#define D(name) upbdefs_google_protobuf_ ## name(s)
+
+static void reghandlers(const void *closure, upb_handlers *h) {
+ const upb_symtab *s = closure;
+ const upb_msgdef *m = upb_handlers_msgdef(h);
+
+ if (m == D(DescriptorProto)) {
+ upb_handlers_setstartmsg(h, &msg_startmsg, NULL);
+ upb_handlers_setendmsg(h, &msg_endmsg, NULL);
+ upb_handlers_setstring(h, D(DescriptorProto_name), &msg_onname, NULL);
+ upb_handlers_setendsubmsg(h, D(DescriptorProto_field), &msg_onendfield,
+ NULL);
+ upb_handlers_setendsubmsg(h, D(DescriptorProto_extension), &pushextension,
+ NULL);
+ } else if (m == D(FileDescriptorProto)) {
+ upb_handlers_setstartmsg(h, &file_startmsg, NULL);
+ upb_handlers_setendmsg(h, &file_endmsg, NULL);
+ upb_handlers_setstring(h, D(FileDescriptorProto_package), &file_onpackage,
+ NULL);
+ upb_handlers_setendsubmsg(h, D(FileDescriptorProto_extension), &pushextension,
+ NULL);
+ } else if (m == D(EnumValueDescriptorProto)) {
+ upb_handlers_setstartmsg(h, &enumval_startmsg, NULL);
+ upb_handlers_setendmsg(h, &enumval_endmsg, NULL);
+ upb_handlers_setstring(h, D(EnumValueDescriptorProto_name), &enumval_onname, NULL);
+ upb_handlers_setint32(h, D(EnumValueDescriptorProto_number), &enumval_onnumber,
+ NULL);
+ } else if (m == D(EnumDescriptorProto)) {
+ upb_handlers_setstartmsg(h, &enum_startmsg, NULL);
+ upb_handlers_setendmsg(h, &enum_endmsg, NULL);
+ upb_handlers_setstring(h, D(EnumDescriptorProto_name), &enum_onname, NULL);
+ } else if (m == D(FieldDescriptorProto)) {
+ upb_handlers_setstartmsg(h, &field_startmsg, NULL);
+ upb_handlers_setendmsg(h, &field_endmsg, NULL);
+ upb_handlers_setint32(h, D(FieldDescriptorProto_type), &field_ontype,
+ NULL);
+ upb_handlers_setint32(h, D(FieldDescriptorProto_label), &field_onlabel,
+ NULL);
+ upb_handlers_setint32(h, D(FieldDescriptorProto_number), &field_onnumber,
+ NULL);
+ upb_handlers_setstring(h, D(FieldDescriptorProto_name), &field_onname,
+ NULL);
+ upb_handlers_setstring(h, D(FieldDescriptorProto_type_name),
+ &field_ontypename, NULL);
+ upb_handlers_setstring(h, D(FieldDescriptorProto_extendee),
+ &field_onextendee, NULL);
+ upb_handlers_setstring(h, D(FieldDescriptorProto_default_value),
+ &field_ondefaultval, NULL);
+ } else if (m == D(FieldOptions)) {
+ upb_handlers_setbool(h, D(FieldOptions_lazy), &field_onlazy, NULL);
+ upb_handlers_setbool(h, D(FieldOptions_packed), &field_onpacked, NULL);
+ }
+}
+
+#undef D
+
+const upb_handlers *upb_descreader_newhandlers(const void *owner) {
+ const upb_symtab *s = upbdefs_google_protobuf_descriptor(&s);
+ const upb_handlers *h = upb_handlers_newfrozen(
+ upbdefs_google_protobuf_FileDescriptorSet(s), owner, reghandlers, s);
+ upb_symtab_unref(s, &s);
+ return h;
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2013 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * Code to compile a upb::Handlers into bytecode for decoding a protobuf
+ * according to that specific schema and destination handlers.
+ *
+ * Compiling to bytecode is always the first step. If we are using the
+ * interpreted decoder we leave it as bytecode and interpret that. If we are
+ * using a JIT decoder we use a code generator to turn the bytecode into native
+ * code, LLVM IR, etc.
+ *
+ * Bytecode definition is in decoder.int.h.
+ */
+
+#include <stdarg.h>
+
+#ifdef UPB_DUMP_BYTECODE
+#include <stdio.h>
+#endif
+
+#define MAXLABEL 5
+#define EMPTYLABEL -1
+
+/* mgroup *********************************************************************/
+
+static void freegroup(upb_refcounted *r) {
+ mgroup *g = (mgroup*)r;
+ upb_inttable_uninit(&g->methods);
+#ifdef UPB_USE_JIT_X64
+ upb_pbdecoder_freejit(g);
+#endif
+ free(g->bytecode);
+ free(g);
+}
+
+static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit,
+ void *closure) {
+ const mgroup *g = (const mgroup*)r;
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &g->methods);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+ visit(r, UPB_UPCAST(method), closure);
+ }
+}
+
+mgroup *newgroup(const void *owner) {
+ mgroup *g = malloc(sizeof(*g));
+ static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup};
+ upb_refcounted_init(UPB_UPCAST(g), &vtbl, owner);
+ upb_inttable_init(&g->methods, UPB_CTYPE_PTR);
+ g->bytecode = NULL;
+ g->bytecode_end = NULL;
+ return g;
+}
+
+
+/* upb_pbdecodermethod ********************************************************/
+
+static void freemethod(upb_refcounted *r) {
+ upb_pbdecodermethod *method = (upb_pbdecodermethod*)r;
+ upb_byteshandler_uninit(&method->input_handler_);
+
+ if (method->dest_handlers_) {
+ upb_handlers_unref(method->dest_handlers_, method);
+ }
+
+ upb_inttable_uninit(&method->dispatch);
+ free(method);
+}
+
+static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit,
+ void *closure) {
+ const upb_pbdecodermethod *m = (const upb_pbdecodermethod*)r;
+ visit(r, m->group, closure);
+}
+
+static upb_pbdecodermethod *newmethod(const upb_handlers *dest_handlers,
+ mgroup *group) {
+ static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod};
+ upb_pbdecodermethod *ret = malloc(sizeof(*ret));
+ upb_refcounted_init(UPB_UPCAST(ret), &vtbl, &ret);
+ upb_byteshandler_init(&ret->input_handler_);
+
+ // The method references the group and vice-versa, in a circular reference.
+ upb_ref2(ret, group);
+ upb_ref2(group, ret);
+ upb_inttable_insertptr(&group->methods, dest_handlers, upb_value_ptr(ret));
+ upb_refcounted_unref(UPB_UPCAST(ret), &ret);
+
+ ret->group = UPB_UPCAST(group);
+ ret->dest_handlers_ = dest_handlers;
+ ret->is_native_ = false; // If we JIT, it will update this later.
+ upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64);
+
+ if (ret->dest_handlers_) {
+ upb_handlers_ref(ret->dest_handlers_, ret);
+ }
+ return ret;
+}
+
+void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner) {
+ upb_refcounted_ref(UPB_UPCAST(m), owner);
+}
+
+void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m,
+ const void *owner) {
+ upb_refcounted_unref(UPB_UPCAST(m), owner);
+}
+
+void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m,
+ const void *from, const void *to) {
+ upb_refcounted_donateref(UPB_UPCAST(m), from, to);
+}
+
+void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m,
+ const void *owner) {
+ upb_refcounted_checkref(UPB_UPCAST(m), owner);
+}
+
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+ const upb_pbdecodermethod *m) {
+ return m->dest_handlers_;
+}
+
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+ const upb_pbdecodermethod *m) {
+ return &m->input_handler_;
+}
+
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) {
+ return m->is_native_;
+}
+
+const upb_pbdecodermethod *upb_pbdecodermethod_new(
+ const upb_pbdecodermethodopts *opts, const void *owner) {
+ upb_pbcodecache cache;
+ upb_pbcodecache_init(&cache);
+ const upb_pbdecodermethod *ret =
+ upb_pbcodecache_getdecodermethod(&cache, opts);
+ upb_pbdecodermethod_ref(ret, owner);
+ upb_pbcodecache_uninit(&cache);
+ return ret;
+}
+
+
+/* bytecode compiler **********************************************************/
+
+// Data used only at compilation time.
+typedef struct {
+ mgroup *group;
+
+ uint32_t *pc;
+ int fwd_labels[MAXLABEL];
+ int back_labels[MAXLABEL];
+
+ // For fields marked "lazy", parse them lazily or eagerly?
+ bool lazy;
+} compiler;
+
+static compiler *newcompiler(mgroup *group, bool lazy) {
+ compiler *ret = malloc(sizeof(*ret));
+ ret->group = group;
+ ret->lazy = lazy;
+ for (int i = 0; i < MAXLABEL; i++) {
+ ret->fwd_labels[i] = EMPTYLABEL;
+ ret->back_labels[i] = EMPTYLABEL;
+ }
+ return ret;
+}
+
+static void freecompiler(compiler *c) {
+ free(c);
+}
+
+const size_t ptr_words = sizeof(void*) / sizeof(uint32_t);
+
+// How many words an instruction is.
+static int instruction_len(uint32_t instr) {
+ switch (getop(instr)) {
+ case OP_SETDISPATCH: return 1 + ptr_words;
+ case OP_TAGN: return 3;
+ case OP_SETBIGGROUPNUM: return 2;
+ default: return 1;
+ }
+}
+
+bool op_has_longofs(int32_t instruction) {
+ switch (getop(instruction)) {
+ case OP_CALL:
+ case OP_BRANCH:
+ case OP_CHECKDELIM:
+ return true;
+ // The "tag" instructions only have 8 bytes available for the jump target,
+ // but that is ok because these opcodes only require short jumps.
+ case OP_TAG1:
+ case OP_TAG2:
+ case OP_TAGN:
+ return false;
+ default:
+ assert(false);
+ return false;
+ }
+}
+
+static int32_t getofs(uint32_t instruction) {
+ if (op_has_longofs(instruction)) {
+ return (int32_t)instruction >> 8;
+ } else {
+ return (int8_t)(instruction >> 8);
+ }
+}
+
+static void setofs(uint32_t *instruction, int32_t ofs) {
+ if (op_has_longofs(*instruction)) {
+ *instruction = getop(*instruction) | ofs << 8;
+ } else {
+ *instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8);
+ }
+ assert(getofs(*instruction) == ofs); // Would fail in cases of overflow.
+}
+
+static uint32_t pcofs(compiler *c) { return c->pc - c->group->bytecode; }
+
+// Defines a local label at the current PC location. All previous forward
+// references are updated to point to this location. The location is noted
+// for any future backward references.
+static void label(compiler *c, unsigned int label) {
+ assert(label < MAXLABEL);
+ int val = c->fwd_labels[label];
+ uint32_t *codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val;
+ while (codep) {
+ int ofs = getofs(*codep);
+ setofs(codep, c->pc - codep - instruction_len(*codep));
+ codep = ofs ? codep + ofs : NULL;
+ }
+ c->fwd_labels[label] = EMPTYLABEL;
+ c->back_labels[label] = pcofs(c);
+}
+
+// Creates a reference to a numbered label; either a forward reference
+// (positive arg) or backward reference (negative arg). For forward references
+// the value returned now is actually a "next" pointer into a linked list of all
+// instructions that use this label and will be patched later when the label is
+// defined with label().
+//
+// The returned value is the offset that should be written into the instruction.
+static int32_t labelref(compiler *c, int label) {
+ assert(label < MAXLABEL);
+ if (label == LABEL_DISPATCH) {
+ // No resolving required.
+ return 0;
+ } else if (label < 0) {
+ // Backward local label. Relative to the next instruction.
+ uint32_t from = (c->pc + 1) - c->group->bytecode;
+ return c->back_labels[-label] - from;
+ } else {
+ // Forward local label: prepend to (possibly-empty) linked list.
+ int *lptr = &c->fwd_labels[label];
+ int32_t ret = (*lptr == EMPTYLABEL) ? 0 : *lptr - pcofs(c);
+ *lptr = pcofs(c);
+ return ret;
+ }
+}
+
+static void put32(compiler *c, uint32_t v) {
+ mgroup *g = c->group;
+ if (c->pc == g->bytecode_end) {
+ int ofs = pcofs(c);
+ size_t oldsize = g->bytecode_end - g->bytecode;
+ size_t newsize = UPB_MAX(oldsize * 2, 64);
+ // TODO(haberman): handle OOM.
+ g->bytecode = realloc(g->bytecode, newsize * sizeof(uint32_t));
+ g->bytecode_end = g->bytecode + newsize;
+ c->pc = g->bytecode + ofs;
+ }
+ *c->pc++ = v;
+}
+
+static void putop(compiler *c, opcode op, ...) {
+ va_list ap;
+ va_start(ap, op);
+
+ switch (op) {
+ case OP_SETDISPATCH: {
+ uintptr_t ptr = (uintptr_t)va_arg(ap, void*);
+ put32(c, OP_SETDISPATCH);
+ put32(c, ptr);
+ if (sizeof(uintptr_t) > sizeof(uint32_t))
+ put32(c, (uint64_t)ptr >> 32);
+ break;
+ }
+ case OP_STARTMSG:
+ case OP_ENDMSG:
+ case OP_PUSHLENDELIM:
+ case OP_POP:
+ case OP_SETDELIM:
+ case OP_HALT:
+ case OP_RET:
+ case OP_DISPATCH:
+ put32(c, op);
+ break;
+ case OP_PARSE_DOUBLE:
+ case OP_PARSE_FLOAT:
+ case OP_PARSE_INT64:
+ case OP_PARSE_UINT64:
+ case OP_PARSE_INT32:
+ case OP_PARSE_FIXED64:
+ case OP_PARSE_FIXED32:
+ case OP_PARSE_BOOL:
+ case OP_PARSE_UINT32:
+ case OP_PARSE_SFIXED32:
+ case OP_PARSE_SFIXED64:
+ case OP_PARSE_SINT32:
+ case OP_PARSE_SINT64:
+ case OP_STARTSEQ:
+ case OP_ENDSEQ:
+ case OP_STARTSUBMSG:
+ case OP_ENDSUBMSG:
+ case OP_STARTSTR:
+ case OP_STRING:
+ case OP_ENDSTR:
+ case OP_PUSHTAGDELIM:
+ put32(c, op | va_arg(ap, upb_selector_t) << 8);
+ break;
+ case OP_SETBIGGROUPNUM:
+ put32(c, op);
+ put32(c, va_arg(ap, int));
+ break;
+ case OP_CALL: {
+ const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *);
+ put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8);
+ break;
+ }
+ case OP_CHECKDELIM:
+ case OP_BRANCH: {
+ uint32_t instruction = op;
+ int label = va_arg(ap, int);
+ setofs(&instruction, labelref(c, label));
+ put32(c, instruction);
+ break;
+ }
+ case OP_TAG1:
+ case OP_TAG2: {
+ int label = va_arg(ap, int);
+ uint64_t tag = va_arg(ap, uint64_t);
+ uint32_t instruction = op | (tag << 16);
+ assert(tag <= 0xffff);
+ setofs(&instruction, labelref(c, label));
+ put32(c, instruction);
+ break;
+ }
+ case OP_TAGN: {
+ int label = va_arg(ap, int);
+ uint64_t tag = va_arg(ap, uint64_t);
+ uint32_t instruction = op | (upb_value_size(tag) << 16);
+ setofs(&instruction, labelref(c, label));
+ put32(c, instruction);
+ put32(c, tag);
+ put32(c, tag >> 32);
+ break;
+ }
+ }
+
+ va_end(ap);
+}
+
+#if defined(UPB_USE_JIT_X64) || defined(UPB_DUMP_BYTECODE)
+
+const char *upb_pbdecoder_getopname(unsigned int op) {
+#define OP(op) [OP_ ## op] = "OP_" #op
+#define T(op) OP(PARSE_##op)
+ static const char *names[] = {
+ "<no opcode>",
+ T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32),
+ T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64),
+ OP(STARTMSG), OP(ENDMSG), OP(STARTSEQ), OP(ENDSEQ), OP(STARTSUBMSG),
+ OP(ENDSUBMSG), OP(STARTSTR), OP(STRING), OP(ENDSTR), OP(CALL), OP(RET),
+ OP(PUSHLENDELIM), OP(PUSHTAGDELIM), OP(SETDELIM), OP(CHECKDELIM),
+ OP(BRANCH), OP(TAG1), OP(TAG2), OP(TAGN), OP(SETDISPATCH), OP(POP),
+ OP(SETBIGGROUPNUM), OP(DISPATCH), OP(HALT),
+ };
+ return op > OP_HALT ? names[0] : names[op];
+#undef OP
+#undef T
+}
+
+#endif
+
+#ifdef UPB_DUMP_BYTECODE
+
+static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) {
+
+ uint32_t *begin = p;
+
+ while (p < end) {
+ fprintf(f, "%p %8tx", p, p - begin);
+ uint32_t instr = *p++;
+ uint8_t op = getop(instr);
+ fprintf(f, " %s", upb_pbdecoder_getopname(op));
+ switch ((opcode)op) {
+ case OP_SETDISPATCH: {
+ const upb_inttable *dispatch;
+ memcpy(&dispatch, p, sizeof(void*));
+ p += ptr_words;
+ const upb_pbdecodermethod *method =
+ (void *)((char *)dispatch -
+ offsetof(upb_pbdecodermethod, dispatch));
+ fprintf(f, " %s", upb_msgdef_fullname(
+ upb_handlers_msgdef(method->dest_handlers_)));
+ break;
+ }
+ case OP_DISPATCH:
+ case OP_STARTMSG:
+ case OP_ENDMSG:
+ case OP_PUSHLENDELIM:
+ case OP_POP:
+ case OP_SETDELIM:
+ case OP_HALT:
+ case OP_RET:
+ break;
+ case OP_PARSE_DOUBLE:
+ case OP_PARSE_FLOAT:
+ case OP_PARSE_INT64:
+ case OP_PARSE_UINT64:
+ case OP_PARSE_INT32:
+ case OP_PARSE_FIXED64:
+ case OP_PARSE_FIXED32:
+ case OP_PARSE_BOOL:
+ case OP_PARSE_UINT32:
+ case OP_PARSE_SFIXED32:
+ case OP_PARSE_SFIXED64:
+ case OP_PARSE_SINT32:
+ case OP_PARSE_SINT64:
+ case OP_STARTSEQ:
+ case OP_ENDSEQ:
+ case OP_STARTSUBMSG:
+ case OP_ENDSUBMSG:
+ case OP_STARTSTR:
+ case OP_STRING:
+ case OP_ENDSTR:
+ case OP_PUSHTAGDELIM:
+ fprintf(f, " %d", instr >> 8);
+ break;
+ case OP_SETBIGGROUPNUM:
+ fprintf(f, " %d", *p++);
+ break;
+ case OP_CHECKDELIM:
+ case OP_CALL:
+ case OP_BRANCH:
+ fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+ break;
+ case OP_TAG1:
+ case OP_TAG2: {
+ fprintf(f, " tag:0x%x", instr >> 16);
+ if (getofs(instr)) {
+ fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+ }
+ break;
+ }
+ case OP_TAGN: {
+ uint64_t tag = *p++;
+ tag |= (uint64_t)*p++ << 32;
+ fprintf(f, " tag:0x%llx", (long long)tag);
+ fprintf(f, " n:%d", instr >> 16);
+ if (getofs(instr)) {
+ fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+ }
+ break;
+ }
+ }
+ fputs("\n", f);
+ }
+}
+
+#endif
+
+static uint64_t get_encoded_tag(const upb_fielddef *f, int wire_type) {
+ uint32_t tag = (upb_fielddef_number(f) << 3) | wire_type;
+ uint64_t encoded_tag = upb_vencode32(tag);
+ // No tag should be greater than 5 bytes.
+ assert(encoded_tag <= 0xffffffffff);
+ return encoded_tag;
+}
+
+static void putchecktag(compiler *c, const upb_fielddef *f,
+ int wire_type, int dest) {
+ uint64_t tag = get_encoded_tag(f, wire_type);
+ switch (upb_value_size(tag)) {
+ case 1:
+ putop(c, OP_TAG1, dest, tag);
+ break;
+ case 2:
+ putop(c, OP_TAG2, dest, tag);
+ break;
+ default:
+ putop(c, OP_TAGN, dest, tag);
+ break;
+ }
+}
+
+static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
+ upb_selector_t selector;
+ bool ok = upb_handlers_getselector(f, type, &selector);
+ UPB_ASSERT_VAR(ok, ok);
+ return selector;
+}
+
+// Takes an existing, primary dispatch table entry and repacks it with a
+// different alternate wire type. Called when we are inserting a secondary
+// dispatch table entry for an alternate wire type.
+static uint64_t repack(uint64_t dispatch, int new_wt2) {
+ uint64_t ofs;
+ uint8_t wt1;
+ uint8_t old_wt2;
+ upb_pbdecoder_unpackdispatch(dispatch, &ofs, &wt1, &old_wt2);
+ assert(old_wt2 == NO_WIRE_TYPE); // wt2 should not be set yet.
+ return upb_pbdecoder_packdispatch(ofs, wt1, new_wt2);
+}
+
+// Marks the current bytecode position as the dispatch target for this message,
+// field, and wire type.
+static void dispatchtarget(compiler *c, upb_pbdecodermethod *method,
+ const upb_fielddef *f, int wire_type) {
+ // Offset is relative to msg base.
+ uint64_t ofs = pcofs(c) - method->code_base.ofs;
+ uint32_t fn = upb_fielddef_number(f);
+ upb_inttable *d = &method->dispatch;
+ upb_value v;
+ if (upb_inttable_remove(d, fn, &v)) {
+ // TODO: prioritize based on packed setting in .proto file.
+ uint64_t repacked = repack(upb_value_getuint64(v), wire_type);
+ upb_inttable_insert(d, fn, upb_value_uint64(repacked));
+ upb_inttable_insert(d, fn + UPB_MAX_FIELDNUMBER, upb_value_uint64(ofs));
+ } else {
+ uint64_t val = upb_pbdecoder_packdispatch(ofs, wire_type, NO_WIRE_TYPE);
+ upb_inttable_insert(d, fn, upb_value_uint64(val));
+ }
+}
+
+static void putpush(compiler *c, const upb_fielddef *f) {
+ if (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) {
+ putop(c, OP_PUSHLENDELIM);
+ } else {
+ uint32_t fn = upb_fielddef_number(f);
+ if (fn >= 1 << 24) {
+ putop(c, OP_PUSHTAGDELIM, 0);
+ putop(c, OP_SETBIGGROUPNUM, fn);
+ } else {
+ putop(c, OP_PUSHTAGDELIM, fn);
+ }
+ }
+}
+
+static upb_pbdecodermethod *find_submethod(const compiler *c,
+ const upb_pbdecodermethod *method,
+ const upb_fielddef *f) {
+ const upb_handlers *sub =
+ upb_handlers_getsubhandlers(method->dest_handlers_, f);
+ upb_value v;
+ return upb_inttable_lookupptr(&c->group->methods, sub, &v)
+ ? upb_value_getptr(v)
+ : NULL;
+}
+
+static void putsel(compiler *c, opcode op, upb_selector_t sel,
+ const upb_handlers *h) {
+ if (upb_handlers_gethandler(h, sel)) {
+ putop(c, op, sel);
+ }
+}
+
+// Puts an opcode to call a callback, but only if a callback actually exists for
+// this field and handler type.
+static void maybeput(compiler *c, opcode op, const upb_handlers *h,
+ const upb_fielddef *f, upb_handlertype_t type) {
+ putsel(c, op, getsel(f, type), h);
+}
+
+static bool haslazyhandlers(const upb_handlers *h, const upb_fielddef *f) {
+ if (!upb_fielddef_lazy(f))
+ return false;
+
+ return upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STARTSTR)) ||
+ upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STRING)) ||
+ upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_ENDSTR));
+}
+
+
+/* bytecode compiler code generation ******************************************/
+
+// Symbolic names for our local labels.
+#define LABEL_LOOPSTART 1 // Top of a repeated field loop.
+#define LABEL_LOOPBREAK 2 // To jump out of a repeated loop
+#define LABEL_FIELD 3 // Jump backward to find the most recent field.
+#define LABEL_ENDMSG 4 // To reach the OP_ENDMSG instr for this msg.
+
+// Generates bytecode to parse a single non-lazy message field.
+static void generate_msgfield(compiler *c, const upb_fielddef *f,
+ upb_pbdecodermethod *method) {
+ const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+ const upb_pbdecodermethod *sub_m = find_submethod(c, method, f);
+
+ if (!sub_m) {
+ // Don't emit any code for this field at all; it will be parsed as an
+ // unknown field.
+ return;
+ }
+
+ label(c, LABEL_FIELD);
+
+ int wire_type =
+ (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE)
+ ? UPB_WIRE_TYPE_DELIMITED
+ : UPB_WIRE_TYPE_START_GROUP;
+
+ if (upb_fielddef_isseq(f)) {
+ putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+ putchecktag(c, f, wire_type, LABEL_DISPATCH);
+ dispatchtarget(c, method, f, wire_type);
+ putop(c, OP_PUSHTAGDELIM, 0);
+ putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
+ label(c, LABEL_LOOPSTART);
+ putpush(c, f);
+ putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
+ putop(c, OP_CALL, sub_m);
+ putop(c, OP_POP);
+ maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
+ if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
+ putop(c, OP_SETDELIM);
+ }
+ putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+ putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
+ putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+ label(c, LABEL_LOOPBREAK);
+ putop(c, OP_POP);
+ maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+ } else {
+ putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+ putchecktag(c, f, wire_type, LABEL_DISPATCH);
+ dispatchtarget(c, method, f, wire_type);
+ putpush(c, f);
+ putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
+ putop(c, OP_CALL, sub_m);
+ putop(c, OP_POP);
+ maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
+ if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
+ putop(c, OP_SETDELIM);
+ }
+ }
+}
+
+// Generates bytecode to parse a single string or lazy submessage field.
+static void generate_delimfield(compiler *c, const upb_fielddef *f,
+ upb_pbdecodermethod *method) {
+ const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+
+ label(c, LABEL_FIELD);
+ if (upb_fielddef_isseq(f)) {
+ putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+ putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+ dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+ putop(c, OP_PUSHTAGDELIM, 0);
+ putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
+ label(c, LABEL_LOOPSTART);
+ putop(c, OP_PUSHLENDELIM);
+ putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
+ // Need to emit even if no handler to skip past the string.
+ putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
+ putop(c, OP_POP);
+ maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
+ putop(c, OP_SETDELIM);
+ putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+ putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_LOOPBREAK);
+ putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+ label(c, LABEL_LOOPBREAK);
+ putop(c, OP_POP);
+ maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+ } else {
+ putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+ putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+ dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+ putop(c, OP_PUSHLENDELIM);
+ putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
+ putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
+ putop(c, OP_POP);
+ maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
+ putop(c, OP_SETDELIM);
+ }
+}
+
+// Generates bytecode to parse a single primitive field.
+static void generate_primitivefield(compiler *c, const upb_fielddef *f,
+ upb_pbdecodermethod *method) {
+ label(c, LABEL_FIELD);
+
+ const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+ upb_descriptortype_t descriptor_type = upb_fielddef_descriptortype(f);
+
+ // From a decoding perspective, ENUM is the same as INT32.
+ if (descriptor_type == UPB_DESCRIPTOR_TYPE_ENUM)
+ descriptor_type = UPB_DESCRIPTOR_TYPE_INT32;
+
+ opcode parse_type = (opcode)descriptor_type;
+
+ // TODO(haberman): generate packed or non-packed first depending on "packed"
+ // setting in the fielddef. This will favor (in speed) whichever was
+ // specified.
+
+ assert((int)parse_type >= 0 && parse_type <= OP_MAX);
+ upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+ int wire_type = upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
+ if (upb_fielddef_isseq(f)) {
+ putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+ putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+ dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+ putop(c, OP_PUSHLENDELIM);
+ putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); // Packed
+ label(c, LABEL_LOOPSTART);
+ putop(c, parse_type, sel);
+ putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+ putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+ dispatchtarget(c, method, f, wire_type);
+ putop(c, OP_PUSHTAGDELIM, 0);
+ putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); // Non-packed
+ label(c, LABEL_LOOPSTART);
+ putop(c, parse_type, sel);
+ putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+ putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
+ putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+ label(c, LABEL_LOOPBREAK);
+ putop(c, OP_POP); // Packed and non-packed join.
+ maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+ putop(c, OP_SETDELIM); // Could remove for non-packed by dup ENDSEQ.
+ } else {
+ putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+ putchecktag(c, f, wire_type, LABEL_DISPATCH);
+ dispatchtarget(c, method, f, wire_type);
+ putop(c, parse_type, sel);
+ }
+}
+
+// Adds bytecode for parsing the given message to the given decoderplan,
+// while adding all dispatch targets to this message's dispatch table.
+static void compile_method(compiler *c, upb_pbdecodermethod *method) {
+ assert(method);
+
+ // Clear all entries in the dispatch table.
+ upb_inttable_uninit(&method->dispatch);
+ upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64);
+
+ const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+ const upb_msgdef *md = upb_handlers_msgdef(h);
+
+ method->code_base.ofs = pcofs(c);
+ putop(c, OP_SETDISPATCH, &method->dispatch);
+ putsel(c, OP_STARTMSG, UPB_STARTMSG_SELECTOR, h);
+ label(c, LABEL_FIELD);
+ uint32_t* start_pc = c->pc;
+ upb_msg_field_iter i;
+ for(upb_msg_field_begin(&i, md);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ const upb_fielddef *f = upb_msg_iter_field(&i);
+ upb_fieldtype_t type = upb_fielddef_type(f);
+
+ if (type == UPB_TYPE_MESSAGE && !(haslazyhandlers(h, f) && c->lazy)) {
+ generate_msgfield(c, f, method);
+ } else if (type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES ||
+ type == UPB_TYPE_MESSAGE) {
+ generate_delimfield(c, f, method);
+ } else {
+ generate_primitivefield(c, f, method);
+ }
+ }
+
+ // If there were no fields, or if no handlers were defined, we need to
+ // generate a non-empty loop body so that we can at least dispatch for unknown
+ // fields and check for the end of the message.
+ if (c->pc == start_pc) {
+ // Check for end-of-message.
+ putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+ // Unconditionally dispatch.
+ putop(c, OP_DISPATCH, 0);
+ }
+
+ // For now we just loop back to the last field of the message (or if none,
+ // the DISPATCH opcode for the message).
+ putop(c, OP_BRANCH, -LABEL_FIELD);
+
+ // Insert both a label and a dispatch table entry for this end-of-msg.
+ label(c, LABEL_ENDMSG);
+ upb_value val = upb_value_uint64(pcofs(c) - method->code_base.ofs);
+ upb_inttable_insert(&method->dispatch, DISPATCH_ENDMSG, val);
+
+ putsel(c, OP_ENDMSG, UPB_ENDMSG_SELECTOR, h);
+ putop(c, OP_RET);
+
+ upb_inttable_compact(&method->dispatch);
+}
+
+// Populate "methods" with new upb_pbdecodermethod objects reachable from "h".
+// Returns the method for these handlers.
+//
+// Generates a new method for every destination handlers reachable from "h".
+static void find_methods(compiler *c, const upb_handlers *h) {
+ upb_value v;
+ if (upb_inttable_lookupptr(&c->group->methods, h, &v))
+ return;
+ newmethod(h, c->group);
+
+ // Find submethods.
+ upb_msg_field_iter i;
+ const upb_msgdef *md = upb_handlers_msgdef(h);
+ for(upb_msg_field_begin(&i, md);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ const upb_fielddef *f = upb_msg_iter_field(&i);
+ const upb_handlers *sub_h;
+ if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
+ (sub_h = upb_handlers_getsubhandlers(h, f)) != NULL) {
+ // We only generate a decoder method for submessages with handlers.
+ // Others will be parsed as unknown fields.
+ find_methods(c, sub_h);
+ }
+ }
+}
+
+// (Re-)compile bytecode for all messages in "msgs."
+// Overwrites any existing bytecode in "c".
+static void compile_methods(compiler *c) {
+ // Start over at the beginning of the bytecode.
+ c->pc = c->group->bytecode;
+
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &c->group->methods);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+ compile_method(c, method);
+ }
+}
+
+static void set_bytecode_handlers(mgroup *g) {
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &g->methods);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i));
+
+ m->code_base.ptr = g->bytecode + m->code_base.ofs;
+
+ upb_byteshandler *h = &m->input_handler_;
+ upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr);
+ upb_byteshandler_setstring(h, upb_pbdecoder_decode, g);
+ upb_byteshandler_setendstr(h, upb_pbdecoder_end, m);
+ }
+}
+
+
+/* JIT setup. *****************************************************************/
+
+#ifdef UPB_USE_JIT_X64
+
+static void sethandlers(mgroup *g, bool allowjit) {
+ g->jit_code = NULL;
+ if (allowjit) {
+ // Compile byte-code into machine code, create handlers.
+ upb_pbdecoder_jit(g);
+ } else {
+ set_bytecode_handlers(g);
+ }
+}
+
+#else // UPB_USE_JIT_X64
+
+static void sethandlers(mgroup *g, bool allowjit) {
+ // No JIT compiled in; use bytecode handlers unconditionally.
+ UPB_UNUSED(allowjit);
+ set_bytecode_handlers(g);
+}
+
+#endif // UPB_USE_JIT_X64
+
+
+// TODO(haberman): allow this to be constructed for an arbitrary set of dest
+// handlers and other mgroups (but verify we have a transitive closure).
+const mgroup *mgroup_new(const upb_handlers *dest, bool allowjit, bool lazy,
+ const void *owner) {
+ UPB_UNUSED(allowjit);
+ assert(upb_handlers_isfrozen(dest));
+
+ mgroup *g = newgroup(owner);
+ compiler *c = newcompiler(g, lazy);
+ find_methods(c, dest);
+
+ // We compile in two passes:
+ // 1. all messages are assigned relative offsets from the beginning of the
+ // bytecode (saved in method->code_base).
+ // 2. forwards OP_CALL instructions can be correctly linked since message
+ // offsets have been previously assigned.
+ //
+ // Could avoid the second pass by linking OP_CALL instructions somehow.
+ compile_methods(c);
+ compile_methods(c);
+ g->bytecode_end = c->pc;
+ freecompiler(c);
+
+#ifdef UPB_DUMP_BYTECODE
+ FILE *f = fopen("/tmp/upb-bytecode", "wb");
+ assert(f);
+ dumpbc(g->bytecode, g->bytecode_end, stderr);
+ dumpbc(g->bytecode, g->bytecode_end, f);
+ fclose(f);
+#endif
+
+ sethandlers(g, allowjit);
+ return g;
+}
+
+
+/* upb_pbcodecache ************************************************************/
+
+void upb_pbcodecache_init(upb_pbcodecache *c) {
+ upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR);
+ c->allow_jit_ = true;
+}
+
+void upb_pbcodecache_uninit(upb_pbcodecache *c) {
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &c->groups);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ const mgroup *group = upb_value_getconstptr(upb_inttable_iter_value(&i));
+ upb_refcounted_unref(UPB_UPCAST(group), c);
+ }
+ upb_inttable_uninit(&c->groups);
+}
+
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c) {
+ return c->allow_jit_;
+}
+
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow) {
+ if (upb_inttable_count(&c->groups) > 0)
+ return false;
+ c->allow_jit_ = allow;
+ return true;
+}
+
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
+ upb_pbcodecache *c, const upb_pbdecodermethodopts *opts) {
+ // Right now we build a new DecoderMethod every time.
+ // TODO(haberman): properly cache methods by their true key.
+ const mgroup *g = mgroup_new(opts->handlers, c->allow_jit_, opts->lazy, c);
+ upb_inttable_push(&c->groups, upb_value_constptr(g));
+
+ upb_value v;
+ bool ok = upb_inttable_lookupptr(&g->methods, opts->handlers, &v);
+ UPB_ASSERT_VAR(ok, ok);
+ return upb_value_getptr(v);
+}
+
+
+/* upb_pbdecodermethodopts ****************************************************/
+
+void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts,
+ const upb_handlers *h) {
+ opts->handlers = h;
+ opts->lazy = false;
+}
+
+void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy) {
+ opts->lazy = lazy;
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2008-2013 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * This file implements a VM for the interpreted (bytecode) decoder.
+ *
+ * Bytecode must previously have been generated using the bytecode compiler in
+ * compile_decoder.c. This decoder then walks through the bytecode op-by-op to
+ * parse the input.
+ *
+ * Decoding is fully resumable; we just keep a pointer to the current bytecode
+ * instruction and resume from there. A fair amount of the logic here is to
+ * handle the fact that values can span buffer seams and we have to be able to
+ * be capable of suspending/resuming from any byte in the stream. This
+ * sometimes requires keeping a few trailing bytes from the last buffer around
+ * in the "residual" buffer.
+ */
+
+#include <inttypes.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifdef UPB_DUMP_BYTECODE
+#include <stdio.h>
+#endif
+
+#define CHECK_SUSPEND(x) if (!(x)) return upb_pbdecoder_suspend(d);
+
+// Error messages that are shared between the bytecode and JIT decoders.
+const char *kPbDecoderStackOverflow = "Nesting too deep.";
+
+// Error messages shared within this file.
+static const char *kUnterminatedVarint = "Unterminated varint.";
+
+/* upb_pbdecoder **************************************************************/
+
+static opcode halt = OP_HALT;
+
+// Whether an op consumes any of the input buffer.
+static bool consumes_input(opcode op) {
+ switch (op) {
+ case OP_SETDISPATCH:
+ case OP_STARTMSG:
+ case OP_ENDMSG:
+ case OP_STARTSEQ:
+ case OP_ENDSEQ:
+ case OP_STARTSUBMSG:
+ case OP_ENDSUBMSG:
+ case OP_STARTSTR:
+ case OP_ENDSTR:
+ case OP_PUSHTAGDELIM:
+ case OP_POP:
+ case OP_SETDELIM:
+ case OP_SETBIGGROUPNUM:
+ case OP_CHECKDELIM:
+ case OP_CALL:
+ case OP_RET:
+ case OP_BRANCH:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static bool in_residual_buf(const upb_pbdecoder *d, const char *p);
+
+// It's unfortunate that we have to micro-manage the compiler this way,
+// especially since this tuning is necessarily specific to one hardware
+// configuration. But emperically on a Core i7, performance increases 30-50%
+// with these annotations. Every instance where these appear, gcc 4.2.1 made
+// the wrong decision and degraded performance in benchmarks.
+#define FORCEINLINE static inline __attribute__((always_inline))
+#define NOINLINE __attribute__((noinline))
+
+static void seterr(upb_pbdecoder *d, const char *msg) {
+ // TODO(haberman): encapsulate this access to pipeline->status, but not sure
+ // exactly what that interface should look like.
+ upb_status_seterrmsg(d->status, msg);
+}
+
+void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) {
+ seterr(d, msg);
+}
+
+
+/* Buffering ******************************************************************/
+
+// We operate on one buffer at a time, which is either the user's buffer passed
+// to our "decode" callback or some residual bytes from the previous buffer.
+
+// How many bytes can be safely read from d->ptr without reading past end-of-buf
+// or past the current delimited end.
+static size_t curbufleft(const upb_pbdecoder *d) {
+ assert(d->data_end >= d->ptr);
+ return d->data_end - d->ptr;
+}
+
+// Overall stream offset of d->ptr.
+uint64_t offset(const upb_pbdecoder *d) {
+ return d->bufstart_ofs + (d->ptr - d->buf);
+}
+
+// Advances d->ptr.
+static void advance(upb_pbdecoder *d, size_t len) {
+ assert(curbufleft(d) >= len);
+ d->ptr += len;
+}
+
+static bool in_buf(const char *p, const char *buf, const char *end) {
+ return p >= buf && p <= end;
+}
+
+static bool in_residual_buf(const upb_pbdecoder *d, const char *p) {
+ return in_buf(p, d->residual, d->residual_end);
+}
+
+// Calculates the delim_end value, which is affected by both the current buffer
+// and the parsing stack, so must be called whenever either is updated.
+static void set_delim_end(upb_pbdecoder *d) {
+ size_t delim_ofs = d->top->end_ofs - d->bufstart_ofs;
+ if (delim_ofs <= (d->end - d->buf)) {
+ d->delim_end = d->buf + delim_ofs;
+ d->data_end = d->delim_end;
+ } else {
+ d->data_end = d->end;
+ d->delim_end = NULL;
+ }
+}
+
+static void switchtobuf(upb_pbdecoder *d, const char *buf, const char *end) {
+ d->ptr = buf;
+ d->buf = buf;
+ d->end = end;
+ set_delim_end(d);
+}
+
+static void advancetobuf(upb_pbdecoder *d, const char *buf, size_t len) {
+ assert(curbufleft(d) == 0);
+ d->bufstart_ofs += (d->end - d->buf);
+ switchtobuf(d, buf, buf + len);
+}
+
+static void checkpoint(upb_pbdecoder *d) {
+ // The assertion here is in the interests of efficiency, not correctness.
+ // We are trying to ensure that we don't checkpoint() more often than
+ // necessary.
+ assert(d->checkpoint != d->ptr);
+ d->checkpoint = d->ptr;
+}
+
+// Resumes the decoder from an initial state or from a previous suspend.
+int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
+ size_t size, const upb_bufhandle *handle) {
+ UPB_UNUSED(p); // Useless; just for the benefit of the JIT.
+ d->buf_param = buf;
+ d->size_param = size;
+ d->handle = handle;
+ if (d->residual_end > d->residual) {
+ // We have residual bytes from the last buffer.
+ assert(d->ptr == d->residual);
+ } else {
+ switchtobuf(d, buf, buf + size);
+ }
+ d->checkpoint = d->ptr;
+ if (d->top->groupnum < 0) {
+ CHECK_RETURN(upb_pbdecoder_skipunknown(d, -1, 0));
+ d->checkpoint = d->ptr;
+ }
+ return DECODE_OK;
+}
+
+// Suspends the decoder at the last checkpoint, without saving any residual
+// bytes. If there are any unconsumed bytes, returns a short byte count.
+size_t upb_pbdecoder_suspend(upb_pbdecoder *d) {
+ d->pc = d->last;
+ if (d->checkpoint == d->residual) {
+ // Checkpoint was in residual buf; no user bytes were consumed.
+ d->ptr = d->residual;
+ return 0;
+ } else {
+ assert(!in_residual_buf(d, d->checkpoint));
+ assert(d->buf == d->buf_param);
+ size_t consumed = d->checkpoint - d->buf;
+ d->bufstart_ofs += consumed;
+ d->residual_end = d->residual;
+ switchtobuf(d, d->residual, d->residual_end);
+ return consumed;
+ }
+}
+
+// Suspends the decoder at the last checkpoint, and saves any unconsumed
+// bytes in our residual buffer. This is necessary if we need more user
+// bytes to form a complete value, which might not be contiguous in the
+// user's buffers. Always consumes all user bytes.
+static size_t suspend_save(upb_pbdecoder *d) {
+ // We hit end-of-buffer before we could parse a full value.
+ // Save any unconsumed bytes (if any) to the residual buffer.
+ d->pc = d->last;
+
+ if (d->checkpoint == d->residual) {
+ // Checkpoint was in residual buf; append user byte(s) to residual buf.
+ assert((d->residual_end - d->residual) + d->size_param <=
+ sizeof(d->residual));
+ if (!in_residual_buf(d, d->ptr)) {
+ d->bufstart_ofs -= (d->residual_end - d->residual);
+ }
+ memcpy(d->residual_end, d->buf_param, d->size_param);
+ d->residual_end += d->size_param;
+ } else {
+ // Checkpoint was in user buf; old residual bytes not needed.
+ assert(!in_residual_buf(d, d->checkpoint));
+ d->ptr = d->checkpoint;
+ size_t save = curbufleft(d);
+ assert(save <= sizeof(d->residual));
+ memcpy(d->residual, d->ptr, save);
+ d->residual_end = d->residual + save;
+ d->bufstart_ofs = offset(d);
+ }
+
+ switchtobuf(d, d->residual, d->residual_end);
+ return d->size_param;
+}
+
+// Skips "bytes" bytes in the stream, which may be more than available. If we
+// skip more bytes than are available, we return a long read count to the caller
+// indicating how many bytes the caller should skip before passing a new buffer.
+static int32_t skip(upb_pbdecoder *d, size_t bytes) {
+ assert(!in_residual_buf(d, d->ptr) || d->size_param == 0);
+ if (curbufleft(d) >= bytes) {
+ // Skipped data is all in current buffer.
+ advance(d, bytes);
+ return DECODE_OK;
+ } else {
+ // Skipped data extends beyond currently available buffers.
+ d->pc = d->last;
+ size_t skip = bytes - curbufleft(d);
+ d->bufstart_ofs += (d->end - d->buf) + skip;
+ d->residual_end = d->residual;
+ switchtobuf(d, d->residual, d->residual_end);
+ return d->size_param + skip;
+ }
+}
+
+// Copies the next "bytes" bytes into "buf" and advances the stream.
+// Requires that this many bytes are available in the current buffer.
+FORCEINLINE void consumebytes(upb_pbdecoder *d, void *buf, size_t bytes) {
+ assert(bytes <= curbufleft(d));
+ memcpy(buf, d->ptr, bytes);
+ advance(d, bytes);
+}
+
+// Slow path for getting the next "bytes" bytes, regardless of whether they are
+// available in the current buffer or not. Returns a status code as described
+// in decoder.int.h.
+static NOINLINE int32_t getbytes_slow(upb_pbdecoder *d, void *buf,
+ size_t bytes) {
+ const size_t avail = curbufleft(d);
+ consumebytes(d, buf, avail);
+ bytes -= avail;
+ assert(bytes > 0);
+ if (in_residual_buf(d, d->ptr)) {
+ advancetobuf(d, d->buf_param, d->size_param);
+ }
+ if (curbufleft(d) >= bytes) {
+ consumebytes(d, buf + avail, bytes);
+ return DECODE_OK;
+ } else if (d->data_end == d->delim_end) {
+ seterr(d, "Submessage ended in the middle of a value or group");
+ return upb_pbdecoder_suspend(d);
+ } else {
+ return suspend_save(d);
+ }
+}
+
+// Gets the next "bytes" bytes, regardless of whether they are available in the
+// current buffer or not. Returns a status code as described in decoder.int.h.
+FORCEINLINE int32_t getbytes(upb_pbdecoder *d, void *buf, size_t bytes) {
+ if (curbufleft(d) >= bytes) {
+ // Buffer has enough data to satisfy.
+ consumebytes(d, buf, bytes);
+ return DECODE_OK;
+ } else {
+ return getbytes_slow(d, buf, bytes);
+ }
+}
+
+static NOINLINE size_t peekbytes_slow(upb_pbdecoder *d, void *buf,
+ size_t bytes) {
+ size_t ret = curbufleft(d);
+ memcpy(buf, d->ptr, ret);
+ if (in_residual_buf(d, d->ptr)) {
+ size_t copy = UPB_MIN(bytes - ret, d->size_param);
+ memcpy(buf + ret, d->buf_param, copy);
+ ret += copy;
+ }
+ return ret;
+}
+
+FORCEINLINE size_t peekbytes(upb_pbdecoder *d, void *buf, size_t bytes) {
+ if (curbufleft(d) >= bytes) {
+ memcpy(buf, d->ptr, bytes);
+ return bytes;
+ } else {
+ return peekbytes_slow(d, buf, bytes);
+ }
+}
+
+
+/* Decoding of wire types *****************************************************/
+
+// Slow path for decoding a varint from the current buffer position.
+// Returns a status code as described in decoder.int.h.
+NOINLINE int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d,
+ uint64_t *u64) {
+ *u64 = 0;
+ uint8_t byte = 0x80;
+ int bitpos;
+ for(bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) {
+ int32_t ret = getbytes(d, &byte, 1);
+ if (ret >= 0) return ret;
+ *u64 |= (uint64_t)(byte & 0x7F) << bitpos;
+ }
+ if(bitpos == 70 && (byte & 0x80)) {
+ seterr(d, kUnterminatedVarint);
+ return upb_pbdecoder_suspend(d);
+ }
+ return DECODE_OK;
+}
+
+// Decodes a varint from the current buffer position.
+// Returns a status code as described in decoder.int.h.
+FORCEINLINE int32_t decode_varint(upb_pbdecoder *d, uint64_t *u64) {
+ if (curbufleft(d) > 0 && !(*d->ptr & 0x80)) {
+ *u64 = *d->ptr;
+ advance(d, 1);
+ return DECODE_OK;
+ } else if (curbufleft(d) >= 10) {
+ // Fast case.
+ upb_decoderet r = upb_vdecode_fast(d->ptr);
+ if (r.p == NULL) {
+ seterr(d, kUnterminatedVarint);
+ return upb_pbdecoder_suspend(d);
+ }
+ advance(d, r.p - d->ptr);
+ *u64 = r.val;
+ return DECODE_OK;
+ } else {
+ // Slow case -- varint spans buffer seam.
+ return upb_pbdecoder_decode_varint_slow(d, u64);
+ }
+}
+
+// Decodes a 32-bit varint from the current buffer position.
+// Returns a status code as described in decoder.int.h.
+FORCEINLINE int32_t decode_v32(upb_pbdecoder *d, uint32_t *u32) {
+ uint64_t u64;
+ int32_t ret = decode_varint(d, &u64);
+ if (ret >= 0) return ret;
+ if (u64 > UINT32_MAX) {
+ seterr(d, "Unterminated 32-bit varint");
+ // TODO(haberman) guarantee that this function return is >= 0 somehow,
+ // so we know this path will always be treated as error by our caller.
+ // Right now the size_t -> int32_t can overflow and produce negative values.
+ *u32 = 0;
+ return upb_pbdecoder_suspend(d);
+ }
+ *u32 = u64;
+ return DECODE_OK;
+}
+
+// Decodes a fixed32 from the current buffer position.
+// Returns a status code as described in decoder.int.h.
+// TODO: proper byte swapping for big-endian machines.
+FORCEINLINE int32_t decode_fixed32(upb_pbdecoder *d, uint32_t *u32) {
+ return getbytes(d, u32, 4);
+}
+
+// Decodes a fixed64 from the current buffer position.
+// Returns a status code as described in decoder.int.h.
+// TODO: proper byte swapping for big-endian machines.
+FORCEINLINE int32_t decode_fixed64(upb_pbdecoder *d, uint64_t *u64) {
+ return getbytes(d, u64, 8);
+}
+
+// Non-static versions of the above functions.
+// These are called by the JIT for fallback paths.
+int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32) {
+ return decode_fixed32(d, u32);
+}
+
+int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64) {
+ return decode_fixed64(d, u64);
+}
+
+static double as_double(uint64_t n) { double d; memcpy(&d, &n, 8); return d; }
+static float as_float(uint32_t n) { float f; memcpy(&f, &n, 4); return f; }
+
+// Pushes a frame onto the decoder stack.
+static bool decoder_push(upb_pbdecoder *d, uint64_t end) {
+ upb_pbdecoder_frame *fr = d->top;
+
+ if (end > fr->end_ofs) {
+ seterr(d, "Submessage end extends past enclosing submessage.");
+ return false;
+ } else if ((fr + 1) == d->limit) {
+ seterr(d, kPbDecoderStackOverflow);
+ return false;
+ }
+
+ fr++;
+ fr->end_ofs = end;
+ fr->dispatch = NULL;
+ fr->groupnum = 0;
+ d->top = fr;
+ return true;
+}
+
+static bool pushtagdelim(upb_pbdecoder *d, uint32_t arg) {
+ // While we expect to see an "end" tag (either ENDGROUP or a non-sequence
+ // field number) prior to hitting any enclosing submessage end, pushing our
+ // existing delim end prevents us from continuing to parse values from a
+ // corrupt proto that doesn't give us an END tag in time.
+ if (!decoder_push(d, d->top->end_ofs))
+ return false;
+ d->top->groupnum = arg;
+ return true;
+}
+
+// Pops a frame from the decoder stack.
+static void decoder_pop(upb_pbdecoder *d) { d->top--; }
+
+NOINLINE int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d,
+ uint64_t expected) {
+ uint64_t data = 0;
+ size_t bytes = upb_value_size(expected);
+ size_t read = peekbytes(d, &data, bytes);
+ if (read == bytes && data == expected) {
+ // Advance past matched bytes.
+ int32_t ok = getbytes(d, &data, read);
+ UPB_ASSERT_VAR(ok, ok < 0);
+ return DECODE_OK;
+ } else if (read < bytes && memcmp(&data, &expected, read) == 0) {
+ return suspend_save(d);
+ } else {
+ return DECODE_MISMATCH;
+ }
+}
+
+int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum,
+ uint8_t wire_type) {
+ if (fieldnum >= 0)
+ goto have_tag;
+
+ while (true) {
+ uint32_t tag;
+ CHECK_RETURN(decode_v32(d, &tag));
+ wire_type = tag & 0x7;
+ fieldnum = tag >> 3;
+
+have_tag:
+ if (fieldnum == 0) {
+ seterr(d, "Saw invalid field number (0)");
+ return upb_pbdecoder_suspend(d);
+ }
+
+ // TODO: deliver to unknown field callback.
+ switch (wire_type) {
+ case UPB_WIRE_TYPE_32BIT:
+ CHECK_RETURN(skip(d, 4));
+ break;
+ case UPB_WIRE_TYPE_64BIT:
+ CHECK_RETURN(skip(d, 8));
+ break;
+ case UPB_WIRE_TYPE_VARINT: {
+ uint64_t u64;
+ CHECK_RETURN(decode_varint(d, &u64));
+ break;
+ }
+ case UPB_WIRE_TYPE_DELIMITED: {
+ uint32_t len;
+ CHECK_RETURN(decode_v32(d, &len));
+ CHECK_RETURN(skip(d, len));
+ break;
+ }
+ case UPB_WIRE_TYPE_START_GROUP:
+ CHECK_SUSPEND(pushtagdelim(d, -fieldnum));
+ break;
+ case UPB_WIRE_TYPE_END_GROUP:
+ if (fieldnum == -d->top->groupnum) {
+ decoder_pop(d);
+ } else if (fieldnum == d->top->groupnum) {
+ return DECODE_ENDGROUP;
+ } else {
+ seterr(d, "Unmatched ENDGROUP tag.");
+ return upb_pbdecoder_suspend(d);
+ }
+ break;
+ default:
+ seterr(d, "Invalid wire type");
+ return upb_pbdecoder_suspend(d);
+ }
+
+ if (d->top->groupnum >= 0) {
+ return DECODE_OK;
+ }
+
+ if (d->ptr == d->delim_end) {
+ seterr(d, "Enclosing submessage ended in the middle of value or group");
+ // Unlike most errors we notice during parsing, right now we have consumed
+ // all of the user's input.
+ //
+ // There are three different options for how to handle this case:
+ //
+ // 1. decode() = short count, error = set
+ // 2. decode() = full count, error = set
+ // 3. decode() = full count, error NOT set, short count and error will
+ // be reported on next call to decode() (or end())
+ //
+ // (1) and (3) have the advantage that they preserve the invariant that an
+ // error occurs iff decode() returns a short count.
+ //
+ // (2) and (3) have the advantage of reflecting the fact that all of the
+ // bytes were in fact parsed (and possibly delivered to the unknown field
+ // handler, in the future when that is supported).
+ //
+ // (3) requires extra state in the decode (a place to store the "permanent
+ // error" that we should return for all subsequent attempts to decode).
+ // But we likely want this anyway.
+ //
+ // Right now we do (1), thanks to the fact that we checkpoint *after* this
+ // check. (3) may be a better choice long term; unclear at the moment.
+ return upb_pbdecoder_suspend(d);
+ }
+
+ checkpoint(d);
+ }
+}
+
+static void goto_endmsg(upb_pbdecoder *d) {
+ upb_value v;
+ bool found = upb_inttable_lookup32(d->top->dispatch, DISPATCH_ENDMSG, &v);
+ UPB_ASSERT_VAR(found, found);
+ d->pc = d->top->base + upb_value_getuint64(v);
+}
+
+// Parses a tag and jumps to the corresponding bytecode instruction for this
+// field.
+//
+// If the tag is unknown (or the wire type doesn't match), parses the field as
+// unknown. If the tag is a valid ENDGROUP tag, jumps to the bytecode
+// instruction for the end of message.
+static int32_t dispatch(upb_pbdecoder *d) {
+ upb_inttable *dispatch = d->top->dispatch;
+
+ // Decode tag.
+ uint32_t tag;
+ CHECK_RETURN(decode_v32(d, &tag));
+ uint8_t wire_type = tag & 0x7;
+ uint32_t fieldnum = tag >> 3;
+
+ // Lookup tag. Because of packed/non-packed compatibility, we have to
+ // check the wire type against two possibilities.
+ upb_value val;
+ if (fieldnum != DISPATCH_ENDMSG &&
+ upb_inttable_lookup32(dispatch, fieldnum, &val)) {
+ uint64_t v = upb_value_getuint64(val);
+ if (wire_type == (v & 0xff)) {
+ d->pc = d->top->base + (v >> 16);
+ return DECODE_OK;
+ } else if (wire_type == ((v >> 8) & 0xff)) {
+ bool found =
+ upb_inttable_lookup(dispatch, fieldnum + UPB_MAX_FIELDNUMBER, &val);
+ UPB_ASSERT_VAR(found, found);
+ d->pc = d->top->base + upb_value_getuint64(val);
+ return DECODE_OK;
+ }
+ }
+
+ // Unknown field or ENDGROUP.
+ int32_t ret = upb_pbdecoder_skipunknown(d, fieldnum, wire_type);
+
+ if (ret == DECODE_ENDGROUP) {
+ goto_endmsg(d);
+ return DECODE_OK;
+ } else {
+ d->pc = d->last - 1; // Rewind to CHECKDELIM.
+ return ret;
+ }
+}
+
+// Callers know that the stack is more than one deep because the opcodes that
+// call this only occur after PUSH operations.
+upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) {
+ assert(d->top != d->stack);
+ return d->top - 1;
+}
+
+
+/* The main decoding loop *****************************************************/
+
+// The main decoder VM function. Uses traditional bytecode dispatch loop with a
+// switch() statement.
+size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
+ size_t size, const upb_bufhandle *handle) {
+ upb_pbdecoder *d = closure;
+ const mgroup *group = hd;
+ assert(buf);
+ int32_t result = upb_pbdecoder_resume(d, NULL, buf, size, handle);
+ if (result == DECODE_ENDGROUP) {
+ goto_endmsg(d);
+ }
+ CHECK_RETURN(result);
+ UPB_UNUSED(group);
+
+#define VMCASE(op, code) \
+ case op: { code; if (consumes_input(op)) checkpoint(d); break; }
+#define PRIMITIVE_OP(type, wt, name, convfunc, ctype) \
+ VMCASE(OP_PARSE_ ## type, { \
+ ctype val; \
+ CHECK_RETURN(decode_ ## wt(d, &val)); \
+ upb_sink_put ## name(&d->top->sink, arg, (convfunc)(val)); \
+ })
+
+ while(1) {
+ d->last = d->pc;
+ int32_t instruction = *d->pc++;
+ opcode op = getop(instruction);
+ uint32_t arg = instruction >> 8;
+ int32_t longofs = arg;
+ assert(d->ptr != d->residual_end);
+#ifdef UPB_DUMP_BYTECODE
+ fprintf(stderr, "s_ofs=%d buf_ofs=%d data_rem=%d buf_rem=%d delim_rem=%d "
+ "%x %s (%d)\n",
+ (int)offset(d),
+ (int)(d->ptr - d->buf),
+ (int)(d->data_end - d->ptr),
+ (int)(d->end - d->ptr),
+ (int)((d->top->end_ofs - d->bufstart_ofs) - (d->ptr - d->buf)),
+ (int)(d->pc - 1 - group->bytecode),
+ upb_pbdecoder_getopname(op),
+ arg);
+#endif
+ switch (op) {
+ // Technically, we are losing data if we see a 32-bit varint that is not
+ // properly sign-extended. We could detect this and error about the data
+ // loss, but proto2 does not do this, so we pass.
+ PRIMITIVE_OP(INT32, varint, int32, int32_t, uint64_t)
+ PRIMITIVE_OP(INT64, varint, int64, int64_t, uint64_t)
+ PRIMITIVE_OP(UINT32, varint, uint32, uint32_t, uint64_t)
+ PRIMITIVE_OP(UINT64, varint, uint64, uint64_t, uint64_t)
+ PRIMITIVE_OP(FIXED32, fixed32, uint32, uint32_t, uint32_t)
+ PRIMITIVE_OP(FIXED64, fixed64, uint64, uint64_t, uint64_t)
+ PRIMITIVE_OP(SFIXED32, fixed32, int32, int32_t, uint32_t)
+ PRIMITIVE_OP(SFIXED64, fixed64, int64, int64_t, uint64_t)
+ PRIMITIVE_OP(BOOL, varint, bool, bool, uint64_t)
+ PRIMITIVE_OP(DOUBLE, fixed64, double, as_double, uint64_t)
+ PRIMITIVE_OP(FLOAT, fixed32, float, as_float, uint32_t)
+ PRIMITIVE_OP(SINT32, varint, int32, upb_zzdec_32, uint64_t)
+ PRIMITIVE_OP(SINT64, varint, int64, upb_zzdec_64, uint64_t)
+
+ VMCASE(OP_SETDISPATCH,
+ d->top->base = d->pc - 1;
+ memcpy(&d->top->dispatch, d->pc, sizeof(void*));
+ d->pc += sizeof(void*) / sizeof(uint32_t);
+ )
+ VMCASE(OP_STARTMSG,
+ CHECK_SUSPEND(upb_sink_startmsg(&d->top->sink));
+ )
+ VMCASE(OP_ENDMSG,
+ CHECK_SUSPEND(upb_sink_endmsg(&d->top->sink, d->status));
+ )
+ VMCASE(OP_STARTSEQ,
+ upb_pbdecoder_frame *outer = outer_frame(d);
+ CHECK_SUSPEND(upb_sink_startseq(&outer->sink, arg, &d->top->sink));
+ )
+ VMCASE(OP_ENDSEQ,
+ CHECK_SUSPEND(upb_sink_endseq(&d->top->sink, arg));
+ )
+ VMCASE(OP_STARTSUBMSG,
+ upb_pbdecoder_frame *outer = outer_frame(d);
+ CHECK_SUSPEND(upb_sink_startsubmsg(&outer->sink, arg, &d->top->sink));
+ )
+ VMCASE(OP_ENDSUBMSG,
+ CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg));
+ )
+ VMCASE(OP_STARTSTR,
+ uint32_t len = d->top->end_ofs - offset(d);
+ upb_pbdecoder_frame *outer = outer_frame(d);
+ CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink));
+ if (len == 0) {
+ d->pc++; // Skip OP_STRING.
+ }
+ )
+ VMCASE(OP_STRING,
+ uint32_t len = curbufleft(d);
+ size_t n = upb_sink_putstring(&d->top->sink, arg, d->ptr, len, handle);
+ if (n > len) {
+ if (n > d->top->end_ofs - offset(d)) {
+ seterr(d, "Tried to skip past end of string.");
+ return upb_pbdecoder_suspend(d);
+ } else {
+ int32_t ret = skip(d, n);
+ // This shouldn't return DECODE_OK, because n > len.
+ assert(ret >= 0);
+ return ret;
+ }
+ }
+ advance(d, n);
+ if (n < len || d->delim_end == NULL) {
+ // We aren't finished with this string yet.
+ d->pc--; // Repeat OP_STRING.
+ if (n > 0) checkpoint(d);
+ return upb_pbdecoder_suspend(d);
+ }
+ )
+ VMCASE(OP_ENDSTR,
+ CHECK_SUSPEND(upb_sink_endstr(&d->top->sink, arg));
+ )
+ VMCASE(OP_PUSHTAGDELIM,
+ CHECK_SUSPEND(pushtagdelim(d, arg));
+ )
+ VMCASE(OP_SETBIGGROUPNUM,
+ d->top->groupnum = *d->pc++;
+ )
+ VMCASE(OP_POP,
+ assert(d->top > d->stack);
+ decoder_pop(d);
+ )
+ VMCASE(OP_PUSHLENDELIM,
+ uint32_t len;
+ CHECK_RETURN(decode_v32(d, &len));
+ CHECK_SUSPEND(decoder_push(d, offset(d) + len));
+ set_delim_end(d);
+ )
+ VMCASE(OP_SETDELIM,
+ set_delim_end(d);
+ )
+ VMCASE(OP_CHECKDELIM,
+ // We are guaranteed of this assert because we never allow ourselves to
+ // consume bytes beyond data_end, which covers delim_end when non-NULL.
+ assert(!(d->delim_end && d->ptr > d->delim_end));
+ if (d->ptr == d->delim_end)
+ d->pc += longofs;
+ )
+ VMCASE(OP_CALL,
+ d->callstack[d->call_len++] = d->pc;
+ d->pc += longofs;
+ )
+ VMCASE(OP_RET,
+ assert(d->call_len > 0);
+ d->pc = d->callstack[--d->call_len];
+ )
+ VMCASE(OP_BRANCH,
+ d->pc += longofs;
+ )
+ VMCASE(OP_TAG1,
+ CHECK_SUSPEND(curbufleft(d) > 0);
+ uint8_t expected = (arg >> 8) & 0xff;
+ if (*d->ptr == expected) {
+ advance(d, 1);
+ } else {
+ int8_t shortofs;
+ badtag:
+ shortofs = arg;
+ if (shortofs == LABEL_DISPATCH) {
+ CHECK_RETURN(dispatch(d));
+ } else {
+ d->pc += shortofs;
+ break; // Avoid checkpoint().
+ }
+ }
+ )
+ VMCASE(OP_TAG2,
+ CHECK_SUSPEND(curbufleft(d) > 0);
+ uint16_t expected = (arg >> 8) & 0xffff;
+ if (curbufleft(d) >= 2) {
+ uint16_t actual;
+ memcpy(&actual, d->ptr, 2);
+ if (expected == actual) {
+ advance(d, 2);
+ } else {
+ goto badtag;
+ }
+ } else {
+ int32_t result = upb_pbdecoder_checktag_slow(d, expected);
+ if (result == DECODE_MISMATCH) goto badtag;
+ if (result >= 0) return result;
+ }
+ )
+ VMCASE(OP_TAGN, {
+ uint64_t expected;
+ memcpy(&expected, d->pc, 8);
+ d->pc += 2;
+ int32_t result = upb_pbdecoder_checktag_slow(d, expected);
+ if (result == DECODE_MISMATCH) goto badtag;
+ if (result >= 0) return result;
+ })
+ VMCASE(OP_DISPATCH, {
+ CHECK_RETURN(dispatch(d));
+ })
+ VMCASE(OP_HALT, {
+ return size;
+ })
+ }
+ }
+}
+
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) {
+ upb_pbdecoder *d = closure;
+ UPB_UNUSED(size_hint);
+ d->call_len = 1;
+ d->pc = pc;
+ return d;
+}
+
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(size_hint);
+ upb_pbdecoder *d = closure;
+ d->call_len = 0;
+ return d;
+}
+
+bool upb_pbdecoder_end(void *closure, const void *handler_data) {
+ upb_pbdecoder *d = closure;
+ const upb_pbdecodermethod *method = handler_data;
+
+ if (d->residual_end > d->residual) {
+ seterr(d, "Unexpected EOF");
+ return false;
+ }
+
+ if (d->top->end_ofs != UINT64_MAX) {
+ seterr(d, "Unexpected EOF inside delimited string");
+ return false;
+ }
+
+ // Message ends here.
+ uint64_t end = offset(d);
+ d->top->end_ofs = end;
+
+ char dummy;
+#ifdef UPB_USE_JIT_X64
+ const mgroup *group = (const mgroup*)method->group;
+ if (group->jit_code) {
+ if (d->top != d->stack)
+ d->stack->end_ofs = 0;
+ group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL);
+ } else {
+#endif
+ d->stack->end_ofs = end;
+ const uint32_t *p = d->pc;
+ // Check the previous bytecode, but guard against beginning.
+ if (p != method->code_base.ptr) p--;
+ if (getop(*p) == OP_CHECKDELIM) {
+ // Rewind from OP_TAG* to OP_CHECKDELIM.
+ assert(getop(*d->pc) == OP_TAG1 ||
+ getop(*d->pc) == OP_TAG2 ||
+ getop(*d->pc) == OP_TAGN ||
+ getop(*d->pc == OP_DISPATCH));
+ d->pc = p;
+ }
+ upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL);
+#ifdef UPB_USE_JIT_X64
+ }
+#endif
+
+ if (d->call_len != 0) {
+ seterr(d, "Unexpected EOF");
+ return false;
+ }
+
+ return true;
+}
+
+void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *m,
+ upb_status *s) {
+ d->limit = &d->stack[UPB_DECODER_MAX_NESTING];
+ upb_bytessink_reset(&d->input_, &m->input_handler_, d);
+ d->method_ = m;
+ d->callstack[0] = &halt;
+ d->status = s;
+ upb_pbdecoder_reset(d);
+}
+
+void upb_pbdecoder_reset(upb_pbdecoder *d) {
+ d->top = d->stack;
+ d->top->end_ofs = UINT64_MAX;
+ d->top->groupnum = 0;
+ d->bufstart_ofs = 0;
+ d->ptr = d->residual;
+ d->buf = d->residual;
+ d->end = d->residual;
+ d->residual_end = d->residual;
+ d->call_len = 1;
+}
+
+uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d) {
+ return offset(d);
+}
+
+// Not currently required, but to support outgrowing the static stack we need
+// this.
+void upb_pbdecoder_uninit(upb_pbdecoder *d) {
+ UPB_UNUSED(d);
+}
+
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) {
+ return d->method_;
+}
+
+bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink* sink) {
+ // TODO(haberman): do we need to test whether the decoder is already on the
+ // stack (like calling this from within a callback)? Should we support
+ // rebinding the output at all?
+ assert(sink);
+ if (d->method_->dest_handlers_) {
+ if (sink->handlers != d->method_->dest_handlers_)
+ return false;
+ }
+ upb_sink_reset(&d->top->sink, sink->handlers, sink->closure);
+ return true;
+}
+
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d) {
+ return &d->input_;
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2014 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * Since we are implementing pure handlers (ie. without any out-of-band access
+ * to pre-computed lengths), we have to buffer all submessages before we can
+ * emit even their first byte.
+ *
+ * Not knowing the size of submessages also means we can't write a perfect
+ * zero-copy implementation, even with buffering. Lengths are stored as
+ * varints, which means that we don't know how many bytes to reserve for the
+ * length until we know what the length is.
+ *
+ * This leaves us with three main choices:
+ *
+ * 1. buffer all submessage data in a temporary buffer, then copy it exactly
+ * once into the output buffer.
+ *
+ * 2. attempt to buffer data directly into the output buffer, estimating how
+ * many bytes each length will take. When our guesses are wrong, use
+ * memmove() to grow or shrink the allotted space.
+ *
+ * 3. buffer directly into the output buffer, allocating a max length
+ * ahead-of-time for each submessage length. If we overallocated, we waste
+ * space, but no memcpy() or memmove() is required. This approach requires
+ * defining a maximum size for submessages and rejecting submessages that
+ * exceed that size.
+ *
+ * (2) and (3) have the potential to have better performance, but they are more
+ * complicated and subtle to implement:
+ *
+ * (3) requires making an arbitrary choice of the maximum message size; it
+ * wastes space when submessages are shorter than this and fails
+ * completely when they are longer. This makes it more finicky and
+ * requires configuration based on the input. It also makes it impossible
+ * to perfectly match the output of reference encoders that always use the
+ * optimal amount of space for each length.
+ *
+ * (2) requires guessing the the size upfront, and if multiple lengths are
+ * guessed wrong the minimum required number of memmove() operations may
+ * be complicated to compute correctly. Implemented properly, it may have
+ * a useful amortized or average cost, but more investigation is required
+ * to determine this and what the optimal algorithm is to achieve it.
+ *
+ * (1) makes you always pay for exactly one copy, but its implementation is
+ * the simplest and its performance is predictable.
+ *
+ * So for now, we implement (1) only. If we wish to optimize later, we should
+ * be able to do it without affecting users.
+ *
+ * The strategy is to buffer the segments of data that do *not* depend on
+ * unknown lengths in one buffer, and keep a separate buffer of segment pointers
+ * and lengths. When the top-level submessage ends, we can go beginning to end,
+ * alternating the writing of lengths with memcpy() of the rest of the data.
+ * At the top level though, no buffering is required.
+ */
+
+
+#include <stdlib.h>
+
+/* low-level buffering ********************************************************/
+
+// Low-level functions for interacting with the output buffer.
+
+// TODO(haberman): handle pushback
+static void putbuf(upb_pb_encoder *e, const char *buf, size_t len) {
+ size_t n = upb_bytessink_putbuf(e->output_, e->subc, buf, len, NULL);
+ UPB_ASSERT_VAR(n, n == len);
+}
+
+static upb_pb_encoder_segment *top(upb_pb_encoder *e) {
+ return &e->segbuf[*e->top];
+}
+
+// Call to ensure that at least "bytes" bytes are available for writing at
+// e->ptr. Returns false if the bytes could not be allocated.
+static bool reserve(upb_pb_encoder *e, size_t bytes) {
+ if ((e->limit - e->ptr) < bytes) {
+ size_t needed = bytes + (e->ptr - e->buf);
+ size_t old_size = e->limit - e->buf;
+ size_t new_size = old_size;
+ while (new_size < needed) {
+ new_size *= 2;
+ }
+
+ char *realloc_from = (e->buf == e->initbuf) ? NULL : e->buf;
+ char *new_buf = realloc(realloc_from, new_size);
+
+ if (new_buf == NULL) {
+ return false;
+ }
+
+ if (realloc_from == NULL) {
+ memcpy(new_buf, e->initbuf, old_size);
+ }
+
+ e->ptr = new_buf + (e->ptr - e->buf);
+ e->runbegin = new_buf + (e->runbegin - e->buf);
+ e->limit = new_buf + new_size;
+ e->buf = new_buf;
+ }
+
+ return true;
+}
+
+// Call when "bytes" bytes have been writte at e->ptr. The caller *must* have
+// previously called reserve() with at least this many bytes.
+static void encoder_advance(upb_pb_encoder *e, size_t bytes) {
+ assert((e->limit - e->ptr) >= bytes);
+ e->ptr += bytes;
+}
+
+// Call when all of the bytes for a handler have been written. Flushes the
+// bytes if possible and necessary, returning false if this failed.
+static bool commit(upb_pb_encoder *e) {
+ if (!e->top) {
+ // We aren't inside a delimited region. Flush our accumulated bytes to
+ // the output.
+ //
+ // TODO(haberman): in the future we may want to delay flushing for
+ // efficiency reasons.
+ putbuf(e, e->buf, e->ptr - e->buf);
+ e->ptr = e->buf;
+ }
+
+ return true;
+}
+
+// Writes the given bytes to the buffer, handling reserve/advance.
+static bool encode_bytes(upb_pb_encoder *e, const void *data, size_t len) {
+ if (!reserve(e, len)) {
+ return false;
+ }
+
+ memcpy(e->ptr, data, len);
+ encoder_advance(e, len);
+ return true;
+}
+
+// Finish the current run by adding the run totals to the segment and message
+// length.
+static void accumulate(upb_pb_encoder *e) {
+ assert(e->ptr >= e->runbegin);
+ size_t run_len = e->ptr - e->runbegin;
+ e->segptr->seglen += run_len;
+ top(e)->msglen += run_len;
+ e->runbegin = e->ptr;
+}
+
+// Call to indicate the start of delimited region for which the full length is
+// not yet known. All data will be buffered until the length is known.
+// Delimited regions may be nested; their lengths will all be tracked properly.
+static bool start_delim(upb_pb_encoder *e) {
+ if (e->top) {
+ // We are already buffering, advance to the next segment and push it on the
+ // stack.
+ accumulate(e);
+
+ if (++e->top == e->stacklimit) {
+ // TODO(haberman): grow stack?
+ return false;
+ }
+
+ if (++e->segptr == e->seglimit) {
+ upb_pb_encoder_segment *realloc_from =
+ (e->segbuf == e->seginitbuf) ? NULL : e->segbuf;
+ size_t old_size =
+ (e->seglimit - e->segbuf) * sizeof(upb_pb_encoder_segment);
+ size_t new_size = old_size * 2;
+ upb_pb_encoder_segment *new_buf = realloc(realloc_from, new_size);
+
+ if (new_buf == NULL) {
+ return false;
+ }
+
+ if (realloc_from == NULL) {
+ memcpy(new_buf, e->seginitbuf, old_size);
+ }
+
+ e->segptr = new_buf + (e->segptr - e->segbuf);
+ e->seglimit = new_buf + (new_size / sizeof(upb_pb_encoder_segment));
+ e->segbuf = new_buf;
+ }
+ } else {
+ // We were previously at the top level, start buffering.
+ e->segptr = e->segbuf;
+ e->top = e->stack;
+ e->runbegin = e->ptr;
+ }
+
+ *e->top = e->segptr - e->segbuf;
+ e->segptr->seglen = 0;
+ e->segptr->msglen = 0;
+
+ return true;
+}
+
+// Call to indicate the end of a delimited region. We now know the length of
+// the delimited region. If we are not nested inside any other delimited
+// regions, we can now emit all of the buffered data we accumulated.
+static bool end_delim(upb_pb_encoder *e) {
+ accumulate(e);
+ size_t msglen = top(e)->msglen;
+
+ if (e->top == e->stack) {
+ // All lengths are now available, emit all buffered data.
+ char buf[UPB_PB_VARINT_MAX_LEN];
+ upb_pb_encoder_segment *s;
+ const char *ptr = e->buf;
+ for (s = e->segbuf; s <= e->segptr; s++) {
+ size_t lenbytes = upb_vencode64(s->msglen, buf);
+ putbuf(e, buf, lenbytes);
+ putbuf(e, ptr, s->seglen);
+ ptr += s->seglen;
+ }
+
+ e->ptr = e->buf;
+ e->top = NULL;
+ } else {
+ // Need to keep buffering; propagate length info into enclosing submessages.
+ --e->top;
+ top(e)->msglen += msglen + upb_varint_size(msglen);
+ }
+
+ return true;
+}
+
+
+/* tag_t **********************************************************************/
+
+// A precomputed (pre-encoded) tag and length.
+
+typedef struct {
+ uint8_t bytes;
+ char tag[7];
+} tag_t;
+
+// Allocates a new tag for this field, and sets it in these handlerattr.
+static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt,
+ upb_handlerattr *attr) {
+ uint32_t n = upb_fielddef_number(f);
+
+ tag_t *tag = malloc(sizeof(tag_t));
+ tag->bytes = upb_vencode64((n << 3) | wt, tag->tag);
+
+ upb_handlerattr_init(attr);
+ upb_handlerattr_sethandlerdata(attr, tag);
+ upb_handlers_addcleanup(h, tag, free);
+}
+
+static bool encode_tag(upb_pb_encoder *e, const tag_t *tag) {
+ return encode_bytes(e, tag->tag, tag->bytes);
+}
+
+
+/* encoding of wire types *****************************************************/
+
+static bool encode_fixed64(upb_pb_encoder *e, uint64_t val) {
+ // TODO(haberman): byte-swap for big endian.
+ return encode_bytes(e, &val, sizeof(uint64_t));
+}
+
+static bool encode_fixed32(upb_pb_encoder *e, uint32_t val) {
+ // TODO(haberman): byte-swap for big endian.
+ return encode_bytes(e, &val, sizeof(uint32_t));
+}
+
+static bool encode_varint(upb_pb_encoder *e, uint64_t val) {
+ if (!reserve(e, UPB_PB_VARINT_MAX_LEN)) {
+ return false;
+ }
+
+ encoder_advance(e, upb_vencode64(val, e->ptr));
+ return true;
+}
+
+static uint64_t dbl2uint64(double d) {
+ uint64_t ret;
+ memcpy(&ret, &d, sizeof(uint64_t));
+ return ret;
+}
+
+static uint32_t flt2uint32(float d) {
+ uint32_t ret;
+ memcpy(&ret, &d, sizeof(uint32_t));
+ return ret;
+}
+
+
+/* encoding of proto types ****************************************************/
+
+static bool startmsg(void *c, const void *hd) {
+ upb_pb_encoder *e = c;
+ UPB_UNUSED(hd);
+ if (e->depth++ == 0) {
+ upb_bytessink_start(e->output_, 0, &e->subc);
+ }
+ return true;
+}
+
+static bool endmsg(void *c, const void *hd, upb_status *status) {
+ upb_pb_encoder *e = c;
+ UPB_UNUSED(hd);
+ UPB_UNUSED(status);
+ if (--e->depth == 0) {
+ upb_bytessink_end(e->output_);
+ }
+ return true;
+}
+
+static void *encode_startdelimfield(void *c, const void *hd) {
+ bool ok = encode_tag(c, hd) && commit(c) && start_delim(c);
+ return ok ? c : UPB_BREAK;
+}
+
+static bool encode_enddelimfield(void *c, const void *hd) {
+ UPB_UNUSED(hd);
+ return end_delim(c);
+}
+
+static void *encode_startgroup(void *c, const void *hd) {
+ return (encode_tag(c, hd) && commit(c)) ? c : UPB_BREAK;
+}
+
+static bool encode_endgroup(void *c, const void *hd) {
+ return encode_tag(c, hd) && commit(c);
+}
+
+static void *encode_startstr(void *c, const void *hd, size_t size_hint) {
+ UPB_UNUSED(size_hint);
+ return encode_startdelimfield(c, hd);
+}
+
+static size_t encode_strbuf(void *c, const void *hd, const char *buf,
+ size_t len, const upb_bufhandle *h) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(h);
+ return encode_bytes(c, buf, len) ? len : 0;
+}
+
+#define T(type, ctype, convert, encode) \
+ static bool encode_scalar_##type(void *e, const void *hd, ctype val) { \
+ return encode_tag(e, hd) && encode(e, (convert)(val)) && commit(e); \
+ } \
+ static bool encode_packed_##type(void *e, const void *hd, ctype val) { \
+ UPB_UNUSED(hd); \
+ return encode(e, (convert)(val)); \
+ }
+
+T(double, double, dbl2uint64, encode_fixed64)
+T(float, float, flt2uint32, encode_fixed32);
+T(int64, int64_t, uint64_t, encode_varint);
+T(int32, int32_t, uint32_t, encode_varint);
+T(fixed64, uint64_t, uint64_t, encode_fixed64);
+T(fixed32, uint32_t, uint32_t, encode_fixed32);
+T(bool, bool, bool, encode_varint);
+T(uint32, uint32_t, uint32_t, encode_varint);
+T(uint64, uint64_t, uint64_t, encode_varint);
+T(enum, int32_t, uint32_t, encode_varint);
+T(sfixed32, int32_t, uint32_t, encode_fixed32);
+T(sfixed64, int64_t, uint64_t, encode_fixed64);
+T(sint32, int32_t, upb_zzenc_32, encode_varint);
+T(sint64, int64_t, upb_zzenc_64, encode_varint);
+
+#undef T
+
+
+/* code to build the handlers *************************************************/
+
+static void newhandlers_callback(const void *closure, upb_handlers *h) {
+ UPB_UNUSED(closure);
+
+ upb_handlers_setstartmsg(h, startmsg, NULL);
+ upb_handlers_setendmsg(h, endmsg, NULL);
+
+ const upb_msgdef *m = upb_handlers_msgdef(h);
+ upb_msg_field_iter i;
+ for(upb_msg_field_begin(&i, m);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ const upb_fielddef *f = upb_msg_iter_field(&i);
+ bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) &&
+ upb_fielddef_packed(f);
+ upb_handlerattr attr;
+ upb_wiretype_t wt =
+ packed ? UPB_WIRE_TYPE_DELIMITED
+ : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
+
+ // Pre-encode the tag for this field.
+ new_tag(h, f, wt, &attr);
+
+ if (packed) {
+ upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr);
+ upb_handlers_setendseq(h, f, encode_enddelimfield, &attr);
+ }
+
+#define T(upper, lower, upbtype) \
+ case UPB_DESCRIPTOR_TYPE_##upper: \
+ if (packed) { \
+ upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \
+ } else { \
+ upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \
+ } \
+ break;
+
+ switch (upb_fielddef_descriptortype(f)) {
+ T(DOUBLE, double, double);
+ T(FLOAT, float, float);
+ T(INT64, int64, int64);
+ T(INT32, int32, int32);
+ T(FIXED64, fixed64, uint64);
+ T(FIXED32, fixed32, uint32);
+ T(BOOL, bool, bool);
+ T(UINT32, uint32, uint32);
+ T(UINT64, uint64, uint64);
+ T(ENUM, enum, int32);
+ T(SFIXED32, sfixed32, int32);
+ T(SFIXED64, sfixed64, int64);
+ T(SINT32, sint32, int32);
+ T(SINT64, sint64, int64);
+ case UPB_DESCRIPTOR_TYPE_STRING:
+ case UPB_DESCRIPTOR_TYPE_BYTES:
+ upb_handlers_setstartstr(h, f, encode_startstr, &attr);
+ upb_handlers_setendstr(h, f, encode_enddelimfield, &attr);
+ upb_handlers_setstring(h, f, encode_strbuf, &attr);
+ break;
+ case UPB_DESCRIPTOR_TYPE_MESSAGE:
+ upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr);
+ upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr);
+ break;
+ case UPB_DESCRIPTOR_TYPE_GROUP: {
+ // Endgroup takes a different tag (wire_type = END_GROUP).
+ upb_handlerattr attr2;
+ new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2);
+
+ upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr);
+ upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2);
+
+ upb_handlerattr_uninit(&attr2);
+ break;
+ }
+ }
+
+#undef T
+
+ upb_handlerattr_uninit(&attr);
+ }
+}
+
+
+/* public API *****************************************************************/
+
+const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
+ const void *owner) {
+ return upb_handlers_newfrozen(m, owner, newhandlers_callback, NULL);
+}
+
+#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
+
+void upb_pb_encoder_init(upb_pb_encoder *e, const upb_handlers *h) {
+ e->output_ = NULL;
+ e->subc = NULL;
+ e->buf = e->initbuf;
+ e->ptr = e->buf;
+ e->limit = e->buf + ARRAYSIZE(e->initbuf);
+ e->segbuf = e->seginitbuf;
+ e->seglimit = e->segbuf + ARRAYSIZE(e->seginitbuf);
+ e->stacklimit = e->stack + ARRAYSIZE(e->stack);
+ upb_sink_reset(&e->input_, h, e);
+}
+
+void upb_pb_encoder_uninit(upb_pb_encoder *e) {
+ if (e->buf != e->initbuf) {
+ free(e->buf);
+ }
+
+ if (e->segbuf != e->seginitbuf) {
+ free(e->segbuf);
+ }
+}
+
+void upb_pb_encoder_resetoutput(upb_pb_encoder *e, upb_bytessink *output) {
+ upb_pb_encoder_reset(e);
+ e->output_ = output;
+ e->subc = output->closure;
+}
+
+void upb_pb_encoder_reset(upb_pb_encoder *e) {
+ e->segptr = NULL;
+ e->top = NULL;
+ e->depth = 0;
+}
+
+upb_sink *upb_pb_encoder_input(upb_pb_encoder *e) { return &e->input_; }
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2010-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n,
+ void *owner, upb_status *status) {
+ // Create handlers.
+ const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h);
+ upb_pbdecodermethodopts opts;
+ upb_pbdecodermethodopts_init(&opts, reader_h);
+ const upb_pbdecodermethod *decoder_m =
+ upb_pbdecodermethod_new(&opts, &decoder_m);
+
+ upb_pbdecoder decoder;
+ upb_descreader reader;
+
+ upb_pbdecoder_init(&decoder, decoder_m, status);
+ upb_descreader_init(&reader, reader_h, status);
+ upb_pbdecoder_resetoutput(&decoder, upb_descreader_input(&reader));
+
+ // Push input data.
+ bool ok = upb_bufsrc_putbuf(str, len, upb_pbdecoder_input(&decoder));
+
+ upb_def **ret = NULL;
+
+ if (!ok) goto cleanup;
+ upb_def **defs = upb_descreader_getdefs(&reader, owner, n);
+ ret = malloc(sizeof(upb_def*) * (*n));
+ memcpy(ret, defs, sizeof(upb_def*) * (*n));
+
+cleanup:
+ upb_pbdecoder_uninit(&decoder);
+ upb_descreader_uninit(&reader);
+ upb_handlers_unref(reader_h, &reader_h);
+ upb_pbdecodermethod_unref(decoder_m, &decoder_m);
+ return ret;
+}
+
+bool upb_load_descriptor_into_symtab(upb_symtab *s, const char *str, size_t len,
+ upb_status *status) {
+ int n;
+ upb_def **defs = upb_load_defs_from_descriptor(str, len, &n, &defs, status);
+ if (!defs) return false;
+ bool success = upb_symtab_add(s, defs, n, &defs, status);
+ free(defs);
+ return success;
+}
+
+char *upb_readfile(const char *filename, size_t *len) {
+ FILE *f = fopen(filename, "rb");
+ if(!f) return NULL;
+ if(fseek(f, 0, SEEK_END) != 0) goto error;
+ long size = ftell(f);
+ if(size < 0) goto error;
+ if(fseek(f, 0, SEEK_SET) != 0) goto error;
+ char *buf = malloc(size + 1);
+ if(size && fread(buf, size, 1, f) != 1) goto error;
+ fclose(f);
+ if (len) *len = size;
+ return buf;
+
+error:
+ fclose(f);
+ return NULL;
+}
+
+bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname,
+ upb_status *status) {
+ size_t len;
+ char *data = upb_readfile(fname, &len);
+ if (!data) {
+ if (status) upb_status_seterrf(status, "Couldn't read file: %s", fname);
+ return false;
+ }
+ bool success = upb_load_descriptor_into_symtab(symtab, data, len, status);
+ free(data);
+ return success;
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * OPT: This is not optimized at all. It uses printf() which parses the format
+ * string every time, and it allocates memory for every put.
+ */
+
+
+#include <ctype.h>
+#include <float.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define CHECK(x) if ((x) < 0) goto err;
+
+static const char *shortname(const char *longname) {
+ const char *last = strrchr(longname, '.');
+ return last ? last + 1 : longname;
+}
+
+static int indent(upb_textprinter *p) {
+ int i;
+ if (!p->single_line_)
+ for (i = 0; i < p->indent_depth_; i++)
+ upb_bytessink_putbuf(p->output_, p->subc, " ", 2, NULL);
+ return 0;
+}
+
+static int endfield(upb_textprinter *p) {
+ const char ch = (p->single_line_ ? ' ' : '\n');
+ upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL);
+ return 0;
+}
+
+static int putescaped(upb_textprinter *p, const char *buf, size_t len,
+ bool preserve_utf8) {
+ // Based on CEscapeInternal() from Google's protobuf release.
+ char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf);
+ const char *end = buf + len;
+
+ // I think hex is prettier and more useful, but proto2 uses octal; should
+ // investigate whether it can parse hex also.
+ const bool use_hex = false;
+ bool last_hex_escape = false; // true if last output char was \xNN
+
+ for (; buf < end; buf++) {
+ if (dstend - dst < 4) {
+ upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
+ dst = dstbuf;
+ }
+
+ bool is_hex_escape = false;
+ switch (*buf) {
+ case '\n': *(dst++) = '\\'; *(dst++) = 'n'; break;
+ case '\r': *(dst++) = '\\'; *(dst++) = 'r'; break;
+ case '\t': *(dst++) = '\\'; *(dst++) = 't'; break;
+ case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break;
+ case '\'': *(dst++) = '\\'; *(dst++) = '\''; break;
+ case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break;
+ default:
+ // Note that if we emit \xNN and the buf character after that is a hex
+ // digit then that digit must be escaped too to prevent it being
+ // interpreted as part of the character code by C.
+ if ((!preserve_utf8 || (uint8_t)*buf < 0x80) &&
+ (!isprint(*buf) || (last_hex_escape && isxdigit(*buf)))) {
+ sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*buf);
+ is_hex_escape = use_hex;
+ dst += 4;
+ } else {
+ *(dst++) = *buf; break;
+ }
+ }
+ last_hex_escape = is_hex_escape;
+ }
+ // Flush remaining data.
+ upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
+ return 0;
+}
+
+bool putf(upb_textprinter *p, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+ // Run once to get the length of the string.
+ va_list args_copy;
+ va_copy(args_copy, args);
+ int len = vsnprintf(NULL, 0, fmt, args_copy);
+ va_end(args_copy);
+
+ // + 1 for NULL terminator (vsnprintf() requires it even if we don't).
+ char *str = malloc(len + 1);
+ if (!str) return false;
+ int written = vsnprintf(str, len + 1, fmt, args);
+ va_end(args);
+ UPB_ASSERT_VAR(written, written == len);
+
+ bool ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL);
+ free(str);
+ return ok;
+}
+
+
+/* handlers *******************************************************************/
+
+static bool textprinter_startmsg(void *c, const void *hd) {
+ UPB_UNUSED(hd);
+ upb_textprinter *p = c;
+ if (p->indent_depth_ == 0) {
+ upb_bytessink_start(p->output_, 0, &p->subc);
+ }
+ return true;
+}
+
+static bool textprinter_endmsg(void *c, const void *hd, upb_status *s) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(s);
+ upb_textprinter *p = c;
+ if (p->indent_depth_ == 0) {
+ upb_bytessink_end(p->output_);
+ }
+ return true;
+}
+
+#define TYPE(name, ctype, fmt) \
+ static bool textprinter_put ## name(void *closure, const void *handler_data, \
+ ctype val) { \
+ upb_textprinter *p = closure; \
+ const upb_fielddef *f = handler_data; \
+ CHECK(indent(p)); \
+ putf(p, "%s: " fmt, upb_fielddef_name(f), val); \
+ CHECK(endfield(p)); \
+ return true; \
+ err: \
+ return false; \
+}
+
+static bool textprinter_putbool(void *closure, const void *handler_data,
+ bool val) {
+ upb_textprinter *p = closure;
+ const upb_fielddef *f = handler_data;
+ CHECK(indent(p));
+ putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false");
+ CHECK(endfield(p));
+ return true;
+err:
+ return false;
+}
+
+#define STRINGIFY_HELPER(x) #x
+#define STRINGIFY_MACROVAL(x) STRINGIFY_HELPER(x)
+
+TYPE(int32, int32_t, "%" PRId32)
+TYPE(int64, int64_t, "%" PRId64)
+TYPE(uint32, uint32_t, "%" PRIu32);
+TYPE(uint64, uint64_t, "%" PRIu64)
+TYPE(float, float, "%." STRINGIFY_MACROVAL(FLT_DIG) "g")
+TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g")
+
+#undef TYPE
+
+// Output a symbolic value from the enum if found, else just print as int32.
+static bool textprinter_putenum(void *closure, const void *handler_data,
+ int32_t val) {
+ upb_textprinter *p = closure;
+ const upb_fielddef *f = handler_data;
+ const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f));
+ const char *label = upb_enumdef_iton(enum_def, val);
+ if (label) {
+ indent(p);
+ putf(p, "%s: %s", upb_fielddef_name(f), label);
+ endfield(p);
+ } else {
+ if (!textprinter_putint32(closure, handler_data, val))
+ return false;
+ }
+ return true;
+}
+
+static void *textprinter_startstr(void *closure, const void *handler_data,
+ size_t size_hint) {
+ const upb_fielddef *f = handler_data;
+ UPB_UNUSED(size_hint);
+ upb_textprinter *p = closure;
+ indent(p);
+ putf(p, "%s: \"", upb_fielddef_name(f));
+ return p;
+}
+
+static bool textprinter_endstr(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_textprinter *p = closure;
+ putf(p, "\"");
+ endfield(p);
+ return true;
+}
+
+static size_t textprinter_putstr(void *closure, const void *hd, const char *buf,
+ size_t len, const upb_bufhandle *handle) {
+ UPB_UNUSED(handle);
+ upb_textprinter *p = closure;
+ const upb_fielddef *f = hd;
+ CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING));
+ return len;
+err:
+ return 0;
+}
+
+static void *textprinter_startsubmsg(void *closure, const void *handler_data) {
+ upb_textprinter *p = closure;
+ const char *name = handler_data;
+ CHECK(indent(p));
+ putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n');
+ p->indent_depth_++;
+ return p;
+err:
+ return UPB_BREAK;
+}
+
+static bool textprinter_endsubmsg(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_textprinter *p = closure;
+ p->indent_depth_--;
+ CHECK(indent(p));
+ upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL);
+ CHECK(endfield(p));
+ return true;
+err:
+ return false;
+}
+
+
+/* Public API *****************************************************************/
+
+void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h) {
+ p->single_line_ = false;
+ p->indent_depth_ = 0;
+ upb_sink_reset(&p->input_, h, p);
+}
+
+void upb_textprinter_uninit(upb_textprinter *p) {
+ UPB_UNUSED(p);
+}
+
+void upb_textprinter_reset(upb_textprinter *p, bool single_line) {
+ p->single_line_ = single_line;
+ p->indent_depth_ = 0;
+}
+
+static void onmreg(const void *c, upb_handlers *h) {
+ UPB_UNUSED(c);
+ const upb_msgdef *m = upb_handlers_msgdef(h);
+
+ upb_handlers_setstartmsg(h, textprinter_startmsg, NULL);
+ upb_handlers_setendmsg(h, textprinter_endmsg, NULL);
+
+ upb_msg_field_iter i;
+ for(upb_msg_field_begin(&i, m);
+ !upb_msg_field_done(&i);
+ upb_msg_field_next(&i)) {
+ upb_fielddef *f = upb_msg_iter_field(&i);
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, f);
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32:
+ upb_handlers_setint32(h, f, textprinter_putint32, &attr);
+ break;
+ case UPB_TYPE_INT64:
+ upb_handlers_setint64(h, f, textprinter_putint64, &attr);
+ break;
+ case UPB_TYPE_UINT32:
+ upb_handlers_setuint32(h, f, textprinter_putuint32, &attr);
+ break;
+ case UPB_TYPE_UINT64:
+ upb_handlers_setuint64(h, f, textprinter_putuint64, &attr);
+ break;
+ case UPB_TYPE_FLOAT:
+ upb_handlers_setfloat(h, f, textprinter_putfloat, &attr);
+ break;
+ case UPB_TYPE_DOUBLE:
+ upb_handlers_setdouble(h, f, textprinter_putdouble, &attr);
+ break;
+ case UPB_TYPE_BOOL:
+ upb_handlers_setbool(h, f, textprinter_putbool, &attr);
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ upb_handlers_setstartstr(h, f, textprinter_startstr, &attr);
+ upb_handlers_setstring(h, f, textprinter_putstr, &attr);
+ upb_handlers_setendstr(h, f, textprinter_endstr, &attr);
+ break;
+ case UPB_TYPE_MESSAGE: {
+ const char *name =
+ upb_fielddef_istagdelim(f)
+ ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f)))
+ : upb_fielddef_name(f);
+ upb_handlerattr_sethandlerdata(&attr, name);
+ upb_handlers_setstartsubmsg(h, f, textprinter_startsubmsg, &attr);
+ upb_handlers_setendsubmsg(h, f, textprinter_endsubmsg, &attr);
+ break;
+ }
+ case UPB_TYPE_ENUM:
+ upb_handlers_setint32(h, f, textprinter_putenum, &attr);
+ break;
+ }
+ }
+}
+
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+ const void *owner) {
+ return upb_handlers_newfrozen(m, owner, &onmreg, NULL);
+}
+
+upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; }
+
+bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output) {
+ p->output_ = output;
+ return true;
+}
+
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) {
+ p->single_line_ = single_line;
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2011 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+
+// Index is descriptor type.
+const uint8_t upb_pb_native_wire_types[] = {
+ UPB_WIRE_TYPE_END_GROUP, // ENDGROUP
+ UPB_WIRE_TYPE_64BIT, // DOUBLE
+ UPB_WIRE_TYPE_32BIT, // FLOAT
+ UPB_WIRE_TYPE_VARINT, // INT64
+ UPB_WIRE_TYPE_VARINT, // UINT64
+ UPB_WIRE_TYPE_VARINT, // INT32
+ UPB_WIRE_TYPE_64BIT, // FIXED64
+ UPB_WIRE_TYPE_32BIT, // FIXED32
+ UPB_WIRE_TYPE_VARINT, // BOOL
+ UPB_WIRE_TYPE_DELIMITED, // STRING
+ UPB_WIRE_TYPE_START_GROUP, // GROUP
+ UPB_WIRE_TYPE_DELIMITED, // MESSAGE
+ UPB_WIRE_TYPE_DELIMITED, // BYTES
+ UPB_WIRE_TYPE_VARINT, // UINT32
+ UPB_WIRE_TYPE_VARINT, // ENUM
+ UPB_WIRE_TYPE_32BIT, // SFIXED32
+ UPB_WIRE_TYPE_64BIT, // SFIXED64
+ UPB_WIRE_TYPE_VARINT, // SINT32
+ UPB_WIRE_TYPE_VARINT, // SINT64
+};
+
+// A basic branch-based decoder, uses 32-bit values to get good performance
+// on 32-bit architectures (but performs well on 64-bits also).
+// This scheme comes from the original Google Protobuf implementation (proto2).
+upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r) {
+ upb_decoderet err = {NULL, 0};
+ const char *p = r.p;
+ uint32_t low = (uint32_t)r.val;
+ uint32_t high = 0;
+ uint32_t b;
+ b = *(p++); low |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
+ b = *(p++); low |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
+ b = *(p++); low |= (b & 0x7fU) << 28;
+ high = (b & 0x7fU) >> 4; if (!(b & 0x80)) goto done;
+ b = *(p++); high |= (b & 0x7fU) << 3; if (!(b & 0x80)) goto done;
+ b = *(p++); high |= (b & 0x7fU) << 10; if (!(b & 0x80)) goto done;
+ b = *(p++); high |= (b & 0x7fU) << 17; if (!(b & 0x80)) goto done;
+ b = *(p++); high |= (b & 0x7fU) << 24; if (!(b & 0x80)) goto done;
+ b = *(p++); high |= (b & 0x7fU) << 31; if (!(b & 0x80)) goto done;
+ return err;
+
+done:
+ r.val = ((uint64_t)high << 32) | low;
+ r.p = p;
+ return r;
+}
+
+// Like the previous, but uses 64-bit values.
+upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r) {
+ const char *p = r.p;
+ uint64_t val = r.val;
+ uint64_t b;
+ upb_decoderet err = {NULL, 0};
+ b = *(p++); val |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
+ b = *(p++); val |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
+ b = *(p++); val |= (b & 0x7fU) << 28; if (!(b & 0x80)) goto done;
+ b = *(p++); val |= (b & 0x7fU) << 35; if (!(b & 0x80)) goto done;
+ b = *(p++); val |= (b & 0x7fU) << 42; if (!(b & 0x80)) goto done;
+ b = *(p++); val |= (b & 0x7fU) << 49; if (!(b & 0x80)) goto done;
+ b = *(p++); val |= (b & 0x7fU) << 56; if (!(b & 0x80)) goto done;
+ b = *(p++); val |= (b & 0x7fU) << 63; if (!(b & 0x80)) goto done;
+ return err;
+
+done:
+ r.val = val;
+ r.p = p;
+ return r;
+}
+
+// Given an encoded varint v, returns an integer with a single bit set that
+// indicates the end of the varint. Subtracting one from this value will
+// yield a mask that leaves only bits that are part of the varint. Returns
+// 0 if the varint is unterminated.
+static uint64_t upb_get_vstopbit(uint64_t v) {
+ uint64_t cbits = v | 0x7f7f7f7f7f7f7f7fULL;
+ return ~cbits & (cbits+1);
+}
+
+// A branchless decoder. Credit to Pascal Massimino for the bit-twiddling.
+upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r) {
+ uint64_t b;
+ memcpy(&b, r.p, sizeof(b));
+ uint64_t stop_bit = upb_get_vstopbit(b);
+ b = (b & 0x7f7f7f7f7f7f7f7fULL) & (stop_bit - 1);
+ b += b & 0x007f007f007f007fULL;
+ b += 3 * (b & 0x0000ffff0000ffffULL);
+ b += 15 * (b & 0x00000000ffffffffULL);
+ if (stop_bit == 0) {
+ // Error: unterminated varint.
+ upb_decoderet err_r = {(void*)0, 0};
+ return err_r;
+ }
+ upb_decoderet my_r = {r.p + ((__builtin_ctzll(stop_bit) + 1) / 8),
+ r.val | (b << 7)};
+ return my_r;
+}
+
+// A branchless decoder. Credit to Daniel Wright for the bit-twiddling.
+upb_decoderet upb_vdecode_max8_wright(upb_decoderet r) {
+ uint64_t b;
+ memcpy(&b, r.p, sizeof(b));
+ uint64_t stop_bit = upb_get_vstopbit(b);
+ b &= (stop_bit - 1);
+ b = ((b & 0x7f007f007f007f00ULL) >> 1) | (b & 0x007f007f007f007fULL);
+ b = ((b & 0xffff0000ffff0000ULL) >> 2) | (b & 0x0000ffff0000ffffULL);
+ b = ((b & 0xffffffff00000000ULL) >> 4) | (b & 0x00000000ffffffffULL);
+ if (stop_bit == 0) {
+ // Error: unterminated varint.
+ upb_decoderet err_r = {(void*)0, 0};
+ return err_r;
+ }
+ upb_decoderet my_r = {r.p + ((__builtin_ctzll(stop_bit) + 1) / 8),
+ r.val | (b << 14)};
+ return my_r;
+}
+
+#line 1 "upb/json/parser.rl"
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2014 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * A parser that uses the Ragel State Machine Compiler to generate
+ * the finite automata.
+ *
+ * Ragel only natively handles regular languages, but we can manually
+ * program it a bit to handle context-free languages like JSON, by using
+ * the "fcall" and "fret" constructs.
+ *
+ * This parser can handle the basics, but needs several things to be fleshed
+ * out:
+ *
+ * - handling of unicode escape sequences (including high surrogate pairs).
+ * - properly check and report errors for unknown fields, stack overflow,
+ * improper array nesting (or lack of nesting).
+ * - handling of base64 sequences with padding characters.
+ * - handling of push-back (non-success returns from sink functions).
+ * - handling of keys/escape-sequences/etc that span input buffers.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+
+#define PARSER_CHECK_RETURN(x) if (!(x)) return false
+
+// Used to signal that a capture has been suspended.
+static char suspend_capture;
+
+static upb_selector_t getsel_for_handlertype(upb_json_parser *p,
+ upb_handlertype_t type) {
+ upb_selector_t sel;
+ bool ok = upb_handlers_getselector(p->top->f, type, &sel);
+ UPB_ASSERT_VAR(ok, ok);
+ return sel;
+}
+
+static upb_selector_t parser_getsel(upb_json_parser *p) {
+ return getsel_for_handlertype(
+ p, upb_handlers_getprimitivehandlertype(p->top->f));
+}
+
+static bool check_stack(upb_json_parser *p) {
+ if ((p->top + 1) == p->limit) {
+ upb_status_seterrmsg(p->status, "Nesting too deep");
+ return false;
+ }
+
+ return true;
+}
+
+// There are GCC/Clang built-ins for overflow checking which we could start
+// using if there was any performance benefit to it.
+
+static bool checked_add(size_t a, size_t b, size_t *c) {
+ if (SIZE_MAX - a < b) return false;
+ *c = a + b;
+ return true;
+}
+
+static size_t saturating_multiply(size_t a, size_t b) {
+ // size_t is unsigned, so this is defined behavior even on overflow.
+ size_t ret = a * b;
+ if (b != 0 && ret / b != a) {
+ ret = SIZE_MAX;
+ }
+ return ret;
+}
+
+
+/* Base64 decoding ************************************************************/
+
+// TODO(haberman): make this streaming.
+
+static const signed char b64table[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */,
+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+ 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
+ -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
+ 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+ 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1,
+ -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+ 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+// Returns the table value sign-extended to 32 bits. Knowing that the upper
+// bits will be 1 for unrecognized characters makes it easier to check for
+// this error condition later (see below).
+int32_t b64lookup(unsigned char ch) { return b64table[ch]; }
+
+// Returns true if the given character is not a valid base64 character or
+// padding.
+bool nonbase64(unsigned char ch) { return b64lookup(ch) == -1 && ch != '='; }
+
+static bool base64_push(upb_json_parser *p, upb_selector_t sel, const char *ptr,
+ size_t len) {
+ const char *limit = ptr + len;
+ for (; ptr < limit; ptr += 4) {
+ if (limit - ptr < 4) {
+ upb_status_seterrf(p->status,
+ "Base64 input for bytes field not a multiple of 4: %s",
+ upb_fielddef_name(p->top->f));
+ return false;
+ }
+
+ uint32_t val = b64lookup(ptr[0]) << 18 |
+ b64lookup(ptr[1]) << 12 |
+ b64lookup(ptr[2]) << 6 |
+ b64lookup(ptr[3]);
+
+ // Test the upper bit; returns true if any of the characters returned -1.
+ if (val & 0x80000000) {
+ goto otherchar;
+ }
+
+ char output[3];
+ output[0] = val >> 16;
+ output[1] = (val >> 8) & 0xff;
+ output[2] = val & 0xff;
+ upb_sink_putstring(&p->top->sink, sel, output, 3, NULL);
+ }
+ return true;
+
+otherchar:
+ if (nonbase64(ptr[0]) || nonbase64(ptr[1]) || nonbase64(ptr[2]) ||
+ nonbase64(ptr[3]) ) {
+ upb_status_seterrf(p->status,
+ "Non-base64 characters in bytes field: %s",
+ upb_fielddef_name(p->top->f));
+ return false;
+ } if (ptr[2] == '=') {
+ // Last group contains only two input bytes, one output byte.
+ if (ptr[0] == '=' || ptr[1] == '=' || ptr[3] != '=') {
+ goto badpadding;
+ }
+
+ uint32_t val = b64lookup(ptr[0]) << 18 |
+ b64lookup(ptr[1]) << 12;
+
+ assert(!(val & 0x80000000));
+ char output = val >> 16;
+ upb_sink_putstring(&p->top->sink, sel, &output, 1, NULL);
+ return true;
+ } else {
+ // Last group contains only three input bytes, two output bytes.
+ if (ptr[0] == '=' || ptr[1] == '=' || ptr[2] == '=') {
+ goto badpadding;
+ }
+
+ uint32_t val = b64lookup(ptr[0]) << 18 |
+ b64lookup(ptr[1]) << 12 |
+ b64lookup(ptr[2]) << 6;
+
+ char output[2];
+ output[0] = val >> 16;
+ output[1] = (val >> 8) & 0xff;
+ upb_sink_putstring(&p->top->sink, sel, output, 2, NULL);
+ return true;
+ }
+
+badpadding:
+ upb_status_seterrf(p->status,
+ "Incorrect base64 padding for field: %s (%.*s)",
+ upb_fielddef_name(p->top->f),
+ 4, ptr);
+ return false;
+}
+
+
+/* Accumulate buffer **********************************************************/
+
+// Functionality for accumulating a buffer.
+//
+// Some parts of the parser need an entire value as a contiguous string. For
+// example, to look up a member name in a hash table, or to turn a string into
+// a number, the relevant library routines need the input string to be in
+// contiguous memory, even if the value spanned two or more buffers in the
+// input. These routines handle that.
+//
+// In the common case we can just point to the input buffer to get this
+// contiguous string and avoid any actual copy. So we optimistically begin
+// this way. But there are a few cases where we must instead copy into a
+// separate buffer:
+//
+// 1. The string was not contiguous in the input (it spanned buffers).
+//
+// 2. The string included escape sequences that need to be interpreted to get
+// the true value in a contiguous buffer.
+
+static void assert_accumulate_empty(upb_json_parser *p) {
+ UPB_UNUSED(p);
+ assert(p->accumulated == NULL);
+ assert(p->accumulated_len == 0);
+}
+
+static void accumulate_clear(upb_json_parser *p) {
+ p->accumulated = NULL;
+ p->accumulated_len = 0;
+}
+
+// Used internally by accumulate_append().
+static bool accumulate_realloc(upb_json_parser *p, size_t need) {
+ size_t new_size = UPB_MAX(p->accumulate_buf_size, 128);
+ while (new_size < need) {
+ new_size = saturating_multiply(new_size, 2);
+ }
+
+ void *mem = realloc(p->accumulate_buf, new_size);
+ if (!mem) {
+ upb_status_seterrmsg(p->status, "Out of memory allocating buffer.");
+ return false;
+ }
+
+ p->accumulate_buf = mem;
+ p->accumulate_buf_size = new_size;
+ return true;
+}
+
+// Logically appends the given data to the append buffer.
+// If "can_alias" is true, we will try to avoid actually copying, but the buffer
+// must be valid until the next accumulate_append() call (if any).
+static bool accumulate_append(upb_json_parser *p, const char *buf, size_t len,
+ bool can_alias) {
+ if (!p->accumulated && can_alias) {
+ p->accumulated = buf;
+ p->accumulated_len = len;
+ return true;
+ }
+
+ size_t need;
+ if (!checked_add(p->accumulated_len, len, &need)) {
+ upb_status_seterrmsg(p->status, "Integer overflow.");
+ return false;
+ }
+
+ if (need > p->accumulate_buf_size && !accumulate_realloc(p, need)) {
+ return false;
+ }
+
+ if (p->accumulated != p->accumulate_buf) {
+ memcpy(p->accumulate_buf, p->accumulated, p->accumulated_len);
+ p->accumulated = p->accumulate_buf;
+ }
+
+ memcpy(p->accumulate_buf + p->accumulated_len, buf, len);
+ p->accumulated_len += len;
+ return true;
+}
+
+// Returns a pointer to the data accumulated since the last accumulate_clear()
+// call, and writes the length to *len. This with point either to the input
+// buffer or a temporary accumulate buffer.
+static const char *accumulate_getptr(upb_json_parser *p, size_t *len) {
+ assert(p->accumulated);
+ *len = p->accumulated_len;
+ return p->accumulated;
+}
+
+
+/* Mult-part text data ********************************************************/
+
+// When we have text data in the input, it can often come in multiple segments.
+// For example, there may be some raw string data followed by an escape
+// sequence. The two segments are processed with different logic. Also buffer
+// seams in the input can cause multiple segments.
+//
+// As we see segments, there are two main cases for how we want to process them:
+//
+// 1. we want to push the captured input directly to string handlers.
+//
+// 2. we need to accumulate all the parts into a contiguous buffer for further
+// processing (field name lookup, string->number conversion, etc).
+
+// This is the set of states for p->multipart_state.
+enum {
+ // We are not currently processing multipart data.
+ MULTIPART_INACTIVE = 0,
+
+ // We are processing multipart data by accumulating it into a contiguous
+ // buffer.
+ MULTIPART_ACCUMULATE = 1,
+
+ // We are processing multipart data by pushing each part directly to the
+ // current string handlers.
+ MULTIPART_PUSHEAGERLY = 2
+};
+
+// Start a multi-part text value where we accumulate the data for processing at
+// the end.
+static void multipart_startaccum(upb_json_parser *p) {
+ assert_accumulate_empty(p);
+ assert(p->multipart_state == MULTIPART_INACTIVE);
+ p->multipart_state = MULTIPART_ACCUMULATE;
+}
+
+// Start a multi-part text value where we immediately push text data to a string
+// value with the given selector.
+static void multipart_start(upb_json_parser *p, upb_selector_t sel) {
+ assert_accumulate_empty(p);
+ assert(p->multipart_state == MULTIPART_INACTIVE);
+ p->multipart_state = MULTIPART_PUSHEAGERLY;
+ p->string_selector = sel;
+}
+
+static bool multipart_text(upb_json_parser *p, const char *buf, size_t len,
+ bool can_alias) {
+ switch (p->multipart_state) {
+ case MULTIPART_INACTIVE:
+ upb_status_seterrmsg(
+ p->status, "Internal error: unexpected state MULTIPART_INACTIVE");
+ return false;
+
+ case MULTIPART_ACCUMULATE:
+ if (!accumulate_append(p, buf, len, can_alias)) {
+ return false;
+ }
+ break;
+
+ case MULTIPART_PUSHEAGERLY: {
+ const upb_bufhandle *handle = can_alias ? p->handle : NULL;
+ upb_sink_putstring(&p->top->sink, p->string_selector, buf, len, handle);
+ break;
+ }
+ }
+
+ return true;
+}
+
+// Note: this invalidates the accumulate buffer! Call only after reading its
+// contents.
+static void multipart_end(upb_json_parser *p) {
+ assert(p->multipart_state != MULTIPART_INACTIVE);
+ p->multipart_state = MULTIPART_INACTIVE;
+ accumulate_clear(p);
+}
+
+
+/* Input capture **************************************************************/
+
+// Functionality for capturing a region of the input as text. Gracefully
+// handles the case where a buffer seam occurs in the middle of the captured
+// region.
+
+static void capture_begin(upb_json_parser *p, const char *ptr) {
+ assert(p->multipart_state != MULTIPART_INACTIVE);
+ assert(p->capture == NULL);
+ p->capture = ptr;
+}
+
+static bool capture_end(upb_json_parser *p, const char *ptr) {
+ assert(p->capture);
+ if (multipart_text(p, p->capture, ptr - p->capture, true)) {
+ p->capture = NULL;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// This is called at the end of each input buffer (ie. when we have hit a
+// buffer seam). If we are in the middle of capturing the input, this
+// processes the unprocessed capture region.
+static void capture_suspend(upb_json_parser *p, const char **ptr) {
+ if (!p->capture) return;
+
+ if (multipart_text(p, p->capture, *ptr - p->capture, false)) {
+ // We use this as a signal that we were in the middle of capturing, and
+ // that capturing should resume at the beginning of the next buffer.
+ //
+ // We can't use *ptr here, because we have no guarantee that this pointer
+ // will be valid when we resume (if the underlying memory is freed, then
+ // using the pointer at all, even to compare to NULL, is likely undefined
+ // behavior).
+ p->capture = &suspend_capture;
+ } else {
+ // Need to back up the pointer to the beginning of the capture, since
+ // we were not able to actually preserve it.
+ *ptr = p->capture;
+ }
+}
+
+static void capture_resume(upb_json_parser *p, const char *ptr) {
+ if (p->capture) {
+ assert(p->capture == &suspend_capture);
+ p->capture = ptr;
+ }
+}
+
+
+/* Callbacks from the parser **************************************************/
+
+// These are the functions called directly from the parser itself.
+// We define these in the same order as their declarations in the parser.
+
+static char escape_char(char in) {
+ switch (in) {
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 'n': return '\n';
+ case 'f': return '\f';
+ case 'b': return '\b';
+ case '/': return '/';
+ case '"': return '"';
+ case '\\': return '\\';
+ default:
+ assert(0);
+ return 'x';
+ }
+}
+
+static bool escape(upb_json_parser *p, const char *ptr) {
+ char ch = escape_char(*ptr);
+ return multipart_text(p, &ch, 1, false);
+}
+
+static void start_hex(upb_json_parser *p) {
+ p->digit = 0;
+}
+
+static void hexdigit(upb_json_parser *p, const char *ptr) {
+ char ch = *ptr;
+
+ p->digit <<= 4;
+
+ if (ch >= '0' && ch <= '9') {
+ p->digit += (ch - '0');
+ } else if (ch >= 'a' && ch <= 'f') {
+ p->digit += ((ch - 'a') + 10);
+ } else {
+ assert(ch >= 'A' && ch <= 'F');
+ p->digit += ((ch - 'A') + 10);
+ }
+}
+
+static bool end_hex(upb_json_parser *p) {
+ uint32_t codepoint = p->digit;
+
+ // emit the codepoint as UTF-8.
+ char utf8[3]; // support \u0000 -- \uFFFF -- need only three bytes.
+ int length = 0;
+ if (codepoint <= 0x7F) {
+ utf8[0] = codepoint;
+ length = 1;
+ } else if (codepoint <= 0x07FF) {
+ utf8[1] = (codepoint & 0x3F) | 0x80;
+ codepoint >>= 6;
+ utf8[0] = (codepoint & 0x1F) | 0xC0;
+ length = 2;
+ } else /* codepoint <= 0xFFFF */ {
+ utf8[2] = (codepoint & 0x3F) | 0x80;
+ codepoint >>= 6;
+ utf8[1] = (codepoint & 0x3F) | 0x80;
+ codepoint >>= 6;
+ utf8[0] = (codepoint & 0x0F) | 0xE0;
+ length = 3;
+ }
+ // TODO(haberman): Handle high surrogates: if codepoint is a high surrogate
+ // we have to wait for the next escape to get the full code point).
+
+ return multipart_text(p, utf8, length, false);
+}
+
+static void start_text(upb_json_parser *p, const char *ptr) {
+ capture_begin(p, ptr);
+}
+
+static bool end_text(upb_json_parser *p, const char *ptr) {
+ return capture_end(p, ptr);
+}
+
+static void start_number(upb_json_parser *p, const char *ptr) {
+ multipart_startaccum(p);
+ capture_begin(p, ptr);
+}
+
+static bool parse_number(upb_json_parser *p);
+
+static bool end_number(upb_json_parser *p, const char *ptr) {
+ if (!capture_end(p, ptr)) {
+ return false;
+ }
+
+ return parse_number(p);
+}
+
+static bool parse_number(upb_json_parser *p) {
+ // strtol() and friends unfortunately do not support specifying the length of
+ // the input string, so we need to force a copy into a NULL-terminated buffer.
+ if (!multipart_text(p, "\0", 1, false)) {
+ return false;
+ }
+
+ size_t len;
+ const char *buf = accumulate_getptr(p, &len);
+ const char *myend = buf + len - 1; // One for NULL.
+
+ char *end;
+ switch (upb_fielddef_type(p->top->f)) {
+ case UPB_TYPE_ENUM:
+ case UPB_TYPE_INT32: {
+ long val = strtol(p->accumulated, &end, 0);
+ if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || end != myend)
+ goto err;
+ else
+ upb_sink_putint32(&p->top->sink, parser_getsel(p), val);
+ break;
+ }
+ case UPB_TYPE_INT64: {
+ long long val = strtoll(p->accumulated, &end, 0);
+ if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || end != myend)
+ goto err;
+ else
+ upb_sink_putint64(&p->top->sink, parser_getsel(p), val);
+ break;
+ }
+ case UPB_TYPE_UINT32: {
+ unsigned long val = strtoul(p->accumulated, &end, 0);
+ if (val > UINT32_MAX || errno == ERANGE || end != myend)
+ goto err;
+ else
+ upb_sink_putuint32(&p->top->sink, parser_getsel(p), val);
+ break;
+ }
+ case UPB_TYPE_UINT64: {
+ unsigned long long val = strtoull(p->accumulated, &end, 0);
+ if (val > UINT64_MAX || errno == ERANGE || end != myend)
+ goto err;
+ else
+ upb_sink_putuint64(&p->top->sink, parser_getsel(p), val);
+ break;
+ }
+ case UPB_TYPE_DOUBLE: {
+ double val = strtod(p->accumulated, &end);
+ if (errno == ERANGE || end != myend)
+ goto err;
+ else
+ upb_sink_putdouble(&p->top->sink, parser_getsel(p), val);
+ break;
+ }
+ case UPB_TYPE_FLOAT: {
+ float val = strtof(p->accumulated, &end);
+ if (errno == ERANGE || end != myend)
+ goto err;
+ else
+ upb_sink_putfloat(&p->top->sink, parser_getsel(p), val);
+ break;
+ }
+ default:
+ assert(false);
+ }
+
+ multipart_end(p);
+
+ return true;
+
+err:
+ upb_status_seterrf(p->status, "error parsing number: %s", buf);
+ multipart_end(p);
+ return false;
+}
+
+static bool parser_putbool(upb_json_parser *p, bool val) {
+ if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) {
+ upb_status_seterrf(p->status,
+ "Boolean value specified for non-bool field: %s",
+ upb_fielddef_name(p->top->f));
+ return false;
+ }
+
+ bool ok = upb_sink_putbool(&p->top->sink, parser_getsel(p), val);
+ UPB_ASSERT_VAR(ok, ok);
+
+ return true;
+}
+
+static bool start_stringval(upb_json_parser *p) {
+ assert(p->top->f);
+
+ if (upb_fielddef_isstring(p->top->f)) {
+ if (!check_stack(p)) return false;
+
+ // Start a new parser frame: parser frames correspond one-to-one with
+ // handler frames, and string events occur in a sub-frame.
+ upb_jsonparser_frame *inner = p->top + 1;
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR);
+ upb_sink_startstr(&p->top->sink, sel, 0, &inner->sink);
+ inner->m = p->top->m;
+ inner->f = p->top->f;
+ inner->is_map = false;
+ inner->is_mapentry = false;
+ p->top = inner;
+
+ if (upb_fielddef_type(p->top->f) == UPB_TYPE_STRING) {
+ // For STRING fields we push data directly to the handlers as it is
+ // parsed. We don't do this yet for BYTES fields, because our base64
+ // decoder is not streaming.
+ //
+ // TODO(haberman): make base64 decoding streaming also.
+ multipart_start(p, getsel_for_handlertype(p, UPB_HANDLER_STRING));
+ return true;
+ } else {
+ multipart_startaccum(p);
+ return true;
+ }
+ } else if (upb_fielddef_type(p->top->f) == UPB_TYPE_ENUM) {
+ // No need to push a frame -- symbolic enum names in quotes remain in the
+ // current parser frame.
+ //
+ // Enum string values must accumulate so we can look up the value in a table
+ // once it is complete.
+ multipart_startaccum(p);
+ return true;
+ } else {
+ upb_status_seterrf(p->status,
+ "String specified for non-string/non-enum field: %s",
+ upb_fielddef_name(p->top->f));
+ return false;
+ }
+}
+
+static bool end_stringval(upb_json_parser *p) {
+ bool ok = true;
+
+ switch (upb_fielddef_type(p->top->f)) {
+ case UPB_TYPE_BYTES:
+ if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING),
+ p->accumulated, p->accumulated_len)) {
+ return false;
+ }
+ // Fall through.
+
+ case UPB_TYPE_STRING: {
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
+ upb_sink_endstr(&p->top->sink, sel);
+ p->top--;
+ break;
+ }
+
+ case UPB_TYPE_ENUM: {
+ // Resolve enum symbolic name to integer value.
+ const upb_enumdef *enumdef =
+ (const upb_enumdef*)upb_fielddef_subdef(p->top->f);
+
+ size_t len;
+ const char *buf = accumulate_getptr(p, &len);
+
+ int32_t int_val = 0;
+ ok = upb_enumdef_ntoi(enumdef, buf, len, &int_val);
+
+ if (ok) {
+ upb_selector_t sel = parser_getsel(p);
+ upb_sink_putint32(&p->top->sink, sel, int_val);
+ } else {
+ upb_status_seterrf(p->status, "Enum value unknown: '%.*s'", len, buf);
+ }
+
+ break;
+ }
+
+ default:
+ assert(false);
+ upb_status_seterrmsg(p->status, "Internal error in JSON decoder");
+ ok = false;
+ break;
+ }
+
+ multipart_end(p);
+
+ return ok;
+}
+
+static void start_member(upb_json_parser *p) {
+ assert(!p->top->f);
+ multipart_startaccum(p);
+}
+
+// Helper: invoked during parse_mapentry() to emit the mapentry message's key
+// field based on the current contents of the accumulate buffer.
+static bool parse_mapentry_key(upb_json_parser *p) {
+
+ size_t len;
+ const char *buf = accumulate_getptr(p, &len);
+
+ // Emit the key field. We do a bit of ad-hoc parsing here because the
+ // parser state machine has already decided that this is a string field
+ // name, and we are reinterpreting it as some arbitrary key type. In
+ // particular, integer and bool keys are quoted, so we need to parse the
+ // quoted string contents here.
+
+ p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_KEY);
+ if (p->top->f == NULL) {
+ upb_status_seterrmsg(p->status, "mapentry message has no key");
+ return false;
+ }
+ switch (upb_fielddef_type(p->top->f)) {
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_UINT64:
+ // Invoke end_number. The accum buffer has the number's text already.
+ if (!parse_number(p)) {
+ return false;
+ }
+ break;
+ case UPB_TYPE_BOOL:
+ if (len == 4 && !strncmp(buf, "true", 4)) {
+ if (!parser_putbool(p, true)) {
+ return false;
+ }
+ } else if (len == 5 && !strncmp(buf, "false", 5)) {
+ if (!parser_putbool(p, false)) {
+ return false;
+ }
+ } else {
+ upb_status_seterrmsg(p->status,
+ "Map bool key not 'true' or 'false'");
+ return false;
+ }
+ multipart_end(p);
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES: {
+ upb_sink subsink;
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR);
+ upb_sink_startstr(&p->top->sink, sel, len, &subsink);
+ sel = getsel_for_handlertype(p, UPB_HANDLER_STRING);
+ upb_sink_putstring(&subsink, sel, buf, len, NULL);
+ sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
+ upb_sink_endstr(&subsink, sel);
+ multipart_end(p);
+ break;
+ }
+ default:
+ upb_status_seterrmsg(p->status, "Invalid field type for map key");
+ return false;
+ }
+
+ return true;
+}
+
+// Helper: emit one map entry (as a submessage in the map field sequence). This
+// is invoked from end_membername(), at the end of the map entry's key string,
+// with the map key in the accumulate buffer. It parses the key from that
+// buffer, emits the handler calls to start the mapentry submessage (setting up
+// its subframe in the process), and sets up state in the subframe so that the
+// value parser (invoked next) will emit the mapentry's value field and then
+// end the mapentry message.
+
+static bool handle_mapentry(upb_json_parser *p) {
+ // Map entry: p->top->sink is the seq frame, so we need to start a frame
+ // for the mapentry itself, and then set |f| in that frame so that the map
+ // value field is parsed, and also set a flag to end the frame after the
+ // map-entry value is parsed.
+ if (!check_stack(p)) return false;
+
+ const upb_fielddef *mapfield = p->top->mapfield;
+ const upb_msgdef *mapentrymsg = upb_fielddef_msgsubdef(mapfield);
+
+ upb_jsonparser_frame *inner = p->top + 1;
+ p->top->f = mapfield;
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+ upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink);
+ inner->m = mapentrymsg;
+ inner->mapfield = mapfield;
+ inner->is_map = false;
+
+ // Don't set this to true *yet* -- we reuse parsing handlers below to push
+ // the key field value to the sink, and these handlers will pop the frame
+ // if they see is_mapentry (when invoked by the parser state machine, they
+ // would have just seen the map-entry value, not key).
+ inner->is_mapentry = false;
+ p->top = inner;
+
+ // send STARTMSG in submsg frame.
+ upb_sink_startmsg(&p->top->sink);
+
+ parse_mapentry_key(p);
+
+ // Set up the value field to receive the map-entry value.
+ p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_VALUE);
+ p->top->is_mapentry = true; // set up to pop frame after value is parsed.
+ p->top->mapfield = mapfield;
+ if (p->top->f == NULL) {
+ upb_status_seterrmsg(p->status, "mapentry message has no value");
+ return false;
+ }
+
+ return true;
+}
+
+static bool end_membername(upb_json_parser *p) {
+ assert(!p->top->f);
+
+ if (p->top->is_map) {
+ return handle_mapentry(p);
+ } else {
+ size_t len;
+ const char *buf = accumulate_getptr(p, &len);
+ const upb_fielddef *f = upb_msgdef_ntof(p->top->m, buf, len);
+
+ if (!f) {
+ // TODO(haberman): Ignore unknown fields if requested/configured to do so.
+ upb_status_seterrf(p->status, "No such field: %.*s\n", (int)len, buf);
+ return false;
+ }
+
+ p->top->f = f;
+ multipart_end(p);
+
+ return true;
+ }
+}
+
+static void end_member(upb_json_parser *p) {
+ // If we just parsed a map-entry value, end that frame too.
+ if (p->top->is_mapentry) {
+ assert(p->top > p->stack);
+ // send ENDMSG on submsg.
+ upb_status s = UPB_STATUS_INIT;
+ upb_sink_endmsg(&p->top->sink, &s);
+ const upb_fielddef* mapfield = p->top->mapfield;
+
+ // send ENDSUBMSG in repeated-field-of-mapentries frame.
+ p->top--;
+ upb_selector_t sel;
+ bool ok = upb_handlers_getselector(mapfield,
+ UPB_HANDLER_ENDSUBMSG, &sel);
+ UPB_ASSERT_VAR(ok, ok);
+ upb_sink_endsubmsg(&p->top->sink, sel);
+ }
+
+ p->top->f = NULL;
+}
+
+static bool start_subobject(upb_json_parser *p) {
+ assert(p->top->f);
+
+ if (upb_fielddef_ismap(p->top->f)) {
+ // Beginning of a map. Start a new parser frame in a repeated-field
+ // context.
+ if (!check_stack(p)) return false;
+
+ upb_jsonparser_frame *inner = p->top + 1;
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+ upb_sink_startseq(&p->top->sink, sel, &inner->sink);
+ inner->m = upb_fielddef_msgsubdef(p->top->f);
+ inner->mapfield = p->top->f;
+ inner->f = NULL;
+ inner->is_map = true;
+ inner->is_mapentry = false;
+ p->top = inner;
+
+ return true;
+ } else if (upb_fielddef_issubmsg(p->top->f)) {
+ // Beginning of a subobject. Start a new parser frame in the submsg
+ // context.
+ if (!check_stack(p)) return false;
+
+ upb_jsonparser_frame *inner = p->top + 1;
+
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+ upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink);
+ inner->m = upb_fielddef_msgsubdef(p->top->f);
+ inner->f = NULL;
+ inner->is_map = false;
+ inner->is_mapentry = false;
+ p->top = inner;
+
+ return true;
+ } else {
+ upb_status_seterrf(p->status,
+ "Object specified for non-message/group field: %s",
+ upb_fielddef_name(p->top->f));
+ return false;
+ }
+}
+
+static void end_subobject(upb_json_parser *p) {
+ if (p->top->is_map) {
+ p->top--;
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+ upb_sink_endseq(&p->top->sink, sel);
+ } else {
+ p->top--;
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG);
+ upb_sink_endsubmsg(&p->top->sink, sel);
+ }
+}
+
+static bool start_array(upb_json_parser *p) {
+ assert(p->top->f);
+
+ if (!upb_fielddef_isseq(p->top->f)) {
+ upb_status_seterrf(p->status,
+ "Array specified for non-repeated field: %s",
+ upb_fielddef_name(p->top->f));
+ return false;
+ }
+
+ if (!check_stack(p)) return false;
+
+ upb_jsonparser_frame *inner = p->top + 1;
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+ upb_sink_startseq(&p->top->sink, sel, &inner->sink);
+ inner->m = p->top->m;
+ inner->f = p->top->f;
+ inner->is_map = false;
+ inner->is_mapentry = false;
+ p->top = inner;
+
+ return true;
+}
+
+static void end_array(upb_json_parser *p) {
+ assert(p->top > p->stack);
+
+ p->top--;
+ upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+ upb_sink_endseq(&p->top->sink, sel);
+}
+
+static void start_object(upb_json_parser *p) {
+ if (!p->top->is_map) {
+ upb_sink_startmsg(&p->top->sink);
+ }
+}
+
+static void end_object(upb_json_parser *p) {
+ if (!p->top->is_map) {
+ upb_status status;
+ upb_sink_endmsg(&p->top->sink, &status);
+ }
+}
+
+
+#define CHECK_RETURN_TOP(x) if (!(x)) goto error
+
+
+/* The actual parser **********************************************************/
+
+// What follows is the Ragel parser itself. The language is specified in Ragel
+// and the actions call our C functions above.
+//
+// Ragel has an extensive set of functionality, and we use only a small part of
+// it. There are many action types but we only use a few:
+//
+// ">" -- transition into a machine
+// "%" -- transition out of a machine
+// "@" -- transition into a final state of a machine.
+//
+// "@" transitions are tricky because a machine can transition into a final
+// state repeatedly. But in some cases we know this can't happen, for example
+// a string which is delimited by a final '"' can only transition into its
+// final state once, when the closing '"' is seen.
+
+
+#line 1085 "upb/json/parser.rl"
+
+
+
+#line 997 "upb/json/parser.c"
+static const char _json_actions[] = {
+ 0, 1, 0, 1, 2, 1, 3, 1,
+ 5, 1, 6, 1, 7, 1, 8, 1,
+ 10, 1, 12, 1, 13, 1, 14, 1,
+ 15, 1, 16, 1, 17, 1, 21, 1,
+ 25, 1, 27, 2, 3, 8, 2, 4,
+ 5, 2, 6, 2, 2, 6, 8, 2,
+ 11, 9, 2, 13, 15, 2, 14, 15,
+ 2, 18, 1, 2, 19, 27, 2, 20,
+ 9, 2, 22, 27, 2, 23, 27, 2,
+ 24, 27, 2, 26, 27, 3, 14, 11,
+ 9
+};
+
+static const unsigned char _json_key_offsets[] = {
+ 0, 0, 4, 9, 14, 15, 19, 24,
+ 29, 34, 38, 42, 45, 48, 50, 54,
+ 58, 60, 62, 67, 69, 71, 80, 86,
+ 92, 98, 104, 106, 115, 116, 116, 116,
+ 121, 126, 131, 132, 133, 134, 135, 135,
+ 136, 137, 138, 138, 139, 140, 141, 141,
+ 146, 151, 152, 156, 161, 166, 171, 175,
+ 175, 178, 178, 178
+};
+
+static const char _json_trans_keys[] = {
+ 32, 123, 9, 13, 32, 34, 125, 9,
+ 13, 32, 34, 125, 9, 13, 34, 32,
+ 58, 9, 13, 32, 93, 125, 9, 13,
+ 32, 44, 125, 9, 13, 32, 44, 125,
+ 9, 13, 32, 34, 9, 13, 45, 48,
+ 49, 57, 48, 49, 57, 46, 69, 101,
+ 48, 57, 69, 101, 48, 57, 43, 45,
+ 48, 57, 48, 57, 48, 57, 46, 69,
+ 101, 48, 57, 34, 92, 34, 92, 34,
+ 47, 92, 98, 102, 110, 114, 116, 117,
+ 48, 57, 65, 70, 97, 102, 48, 57,
+ 65, 70, 97, 102, 48, 57, 65, 70,
+ 97, 102, 48, 57, 65, 70, 97, 102,
+ 34, 92, 34, 45, 91, 102, 110, 116,
+ 123, 48, 57, 34, 32, 93, 125, 9,
+ 13, 32, 44, 93, 9, 13, 32, 93,
+ 125, 9, 13, 97, 108, 115, 101, 117,
+ 108, 108, 114, 117, 101, 32, 34, 125,
+ 9, 13, 32, 34, 125, 9, 13, 34,
+ 32, 58, 9, 13, 32, 93, 125, 9,
+ 13, 32, 44, 125, 9, 13, 32, 44,
+ 125, 9, 13, 32, 34, 9, 13, 32,
+ 9, 13, 0
+};
+
+static const char _json_single_lengths[] = {
+ 0, 2, 3, 3, 1, 2, 3, 3,
+ 3, 2, 2, 1, 3, 0, 2, 2,
+ 0, 0, 3, 2, 2, 9, 0, 0,
+ 0, 0, 2, 7, 1, 0, 0, 3,
+ 3, 3, 1, 1, 1, 1, 0, 1,
+ 1, 1, 0, 1, 1, 1, 0, 3,
+ 3, 1, 2, 3, 3, 3, 2, 0,
+ 1, 0, 0, 0
+};
+
+static const char _json_range_lengths[] = {
+ 0, 1, 1, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 0, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 3, 3,
+ 3, 3, 0, 1, 0, 0, 0, 1,
+ 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 0, 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0
+};
+
+static const short _json_index_offsets[] = {
+ 0, 0, 4, 9, 14, 16, 20, 25,
+ 30, 35, 39, 43, 46, 50, 52, 56,
+ 60, 62, 64, 69, 72, 75, 85, 89,
+ 93, 97, 101, 104, 113, 115, 116, 117,
+ 122, 127, 132, 134, 136, 138, 140, 141,
+ 143, 145, 147, 148, 150, 152, 154, 155,
+ 160, 165, 167, 171, 176, 181, 186, 190,
+ 191, 194, 195, 196
+};
+
+static const char _json_indicies[] = {
+ 0, 2, 0, 1, 3, 4, 5, 3,
+ 1, 6, 7, 8, 6, 1, 9, 1,
+ 10, 11, 10, 1, 11, 1, 1, 11,
+ 12, 13, 14, 15, 13, 1, 16, 17,
+ 8, 16, 1, 17, 7, 17, 1, 18,
+ 19, 20, 1, 19, 20, 1, 22, 23,
+ 23, 21, 24, 1, 23, 23, 24, 21,
+ 25, 25, 26, 1, 26, 1, 26, 21,
+ 22, 23, 23, 20, 21, 28, 29, 27,
+ 31, 32, 30, 33, 33, 33, 33, 33,
+ 33, 33, 33, 34, 1, 35, 35, 35,
+ 1, 36, 36, 36, 1, 37, 37, 37,
+ 1, 38, 38, 38, 1, 40, 41, 39,
+ 42, 43, 44, 45, 46, 47, 48, 43,
+ 1, 49, 1, 50, 51, 53, 54, 1,
+ 53, 52, 55, 56, 54, 55, 1, 56,
+ 1, 1, 56, 52, 57, 1, 58, 1,
+ 59, 1, 60, 1, 61, 62, 1, 63,
+ 1, 64, 1, 65, 66, 1, 67, 1,
+ 68, 1, 69, 70, 71, 72, 70, 1,
+ 73, 74, 75, 73, 1, 76, 1, 77,
+ 78, 77, 1, 78, 1, 1, 78, 79,
+ 80, 81, 82, 80, 1, 83, 84, 75,
+ 83, 1, 84, 74, 84, 1, 85, 86,
+ 86, 1, 1, 1, 1, 0
+};
+
+static const char _json_trans_targs[] = {
+ 1, 0, 2, 3, 4, 56, 3, 4,
+ 56, 5, 5, 6, 7, 8, 9, 56,
+ 8, 9, 11, 12, 18, 57, 13, 15,
+ 14, 16, 17, 20, 58, 21, 20, 58,
+ 21, 19, 22, 23, 24, 25, 26, 20,
+ 58, 21, 28, 30, 31, 34, 39, 43,
+ 47, 29, 59, 59, 32, 31, 29, 32,
+ 33, 35, 36, 37, 38, 59, 40, 41,
+ 42, 59, 44, 45, 46, 59, 48, 49,
+ 55, 48, 49, 55, 50, 50, 51, 52,
+ 53, 54, 55, 53, 54, 59, 56
+};
+
+static const char _json_trans_actions[] = {
+ 0, 0, 0, 21, 77, 53, 0, 47,
+ 23, 17, 0, 0, 15, 19, 19, 50,
+ 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 3, 13, 0, 0, 35,
+ 5, 11, 0, 38, 7, 7, 7, 41,
+ 44, 9, 62, 56, 25, 0, 0, 0,
+ 31, 29, 33, 59, 15, 0, 27, 0,
+ 0, 0, 0, 0, 0, 68, 0, 0,
+ 0, 71, 0, 0, 0, 65, 21, 77,
+ 53, 0, 47, 23, 17, 0, 0, 15,
+ 19, 19, 50, 0, 0, 74, 0
+};
+
+static const int json_start = 1;
+static const int json_first_final = 56;
+static const int json_error = 0;
+
+static const int json_en_number_machine = 10;
+static const int json_en_string_machine = 19;
+static const int json_en_value_machine = 27;
+static const int json_en_main = 1;
+
+
+#line 1088 "upb/json/parser.rl"
+
+size_t parse(void *closure, const void *hd, const char *buf, size_t size,
+ const upb_bufhandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ upb_json_parser *parser = closure;
+ parser->handle = handle;
+
+ // Variables used by Ragel's generated code.
+ int cs = parser->current_state;
+ int *stack = parser->parser_stack;
+ int top = parser->parser_top;
+
+ const char *p = buf;
+ const char *pe = buf + size;
+
+ capture_resume(parser, buf);
+
+
+#line 1168 "upb/json/parser.c"
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _keys = _json_trans_keys + _json_key_offsets[cs];
+ _trans = _json_index_offsets[cs];
+
+ _klen = _json_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (unsigned int)(_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _json_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += (unsigned int)((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ _trans = _json_indicies[_trans];
+ cs = _json_trans_targs[_trans];
+
+ if ( _json_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _json_actions + _json_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+#line 1000 "upb/json/parser.rl"
+ { p--; {cs = stack[--top]; goto _again;} }
+ break;
+ case 1:
+#line 1001 "upb/json/parser.rl"
+ { p--; {stack[top++] = cs; cs = 10; goto _again;} }
+ break;
+ case 2:
+#line 1005 "upb/json/parser.rl"
+ { start_text(parser, p); }
+ break;
+ case 3:
+#line 1006 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(end_text(parser, p)); }
+ break;
+ case 4:
+#line 1012 "upb/json/parser.rl"
+ { start_hex(parser); }
+ break;
+ case 5:
+#line 1013 "upb/json/parser.rl"
+ { hexdigit(parser, p); }
+ break;
+ case 6:
+#line 1014 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(end_hex(parser)); }
+ break;
+ case 7:
+#line 1020 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(escape(parser, p)); }
+ break;
+ case 8:
+#line 1026 "upb/json/parser.rl"
+ { p--; {cs = stack[--top]; goto _again;} }
+ break;
+ case 9:
+#line 1029 "upb/json/parser.rl"
+ { {stack[top++] = cs; cs = 19; goto _again;} }
+ break;
+ case 10:
+#line 1031 "upb/json/parser.rl"
+ { p--; {stack[top++] = cs; cs = 27; goto _again;} }
+ break;
+ case 11:
+#line 1036 "upb/json/parser.rl"
+ { start_member(parser); }
+ break;
+ case 12:
+#line 1037 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(end_membername(parser)); }
+ break;
+ case 13:
+#line 1040 "upb/json/parser.rl"
+ { end_member(parser); }
+ break;
+ case 14:
+#line 1046 "upb/json/parser.rl"
+ { start_object(parser); }
+ break;
+ case 15:
+#line 1049 "upb/json/parser.rl"
+ { end_object(parser); }
+ break;
+ case 16:
+#line 1055 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(start_array(parser)); }
+ break;
+ case 17:
+#line 1059 "upb/json/parser.rl"
+ { end_array(parser); }
+ break;
+ case 18:
+#line 1064 "upb/json/parser.rl"
+ { start_number(parser, p); }
+ break;
+ case 19:
+#line 1065 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(end_number(parser, p)); }
+ break;
+ case 20:
+#line 1067 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(start_stringval(parser)); }
+ break;
+ case 21:
+#line 1068 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(end_stringval(parser)); }
+ break;
+ case 22:
+#line 1070 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(parser_putbool(parser, true)); }
+ break;
+ case 23:
+#line 1072 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(parser_putbool(parser, false)); }
+ break;
+ case 24:
+#line 1074 "upb/json/parser.rl"
+ { /* null value */ }
+ break;
+ case 25:
+#line 1076 "upb/json/parser.rl"
+ { CHECK_RETURN_TOP(start_subobject(parser)); }
+ break;
+ case 26:
+#line 1077 "upb/json/parser.rl"
+ { end_subobject(parser); }
+ break;
+ case 27:
+#line 1082 "upb/json/parser.rl"
+ { p--; {cs = stack[--top]; goto _again;} }
+ break;
+#line 1354 "upb/json/parser.c"
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ _out: {}
+ }
+
+#line 1107 "upb/json/parser.rl"
+
+ if (p != pe) {
+ upb_status_seterrf(parser->status, "Parse error at %s\n", p);
+ } else {
+ capture_suspend(parser, &p);
+ }
+
+error:
+ // Save parsing state back to parser.
+ parser->current_state = cs;
+ parser->parser_top = top;
+
+ return p - buf;
+}
+
+bool end(void *closure, const void *hd) {
+ UPB_UNUSED(closure);
+ UPB_UNUSED(hd);
+ return true;
+}
+
+
+/* Public API *****************************************************************/
+
+void upb_json_parser_init(upb_json_parser *p, upb_status *status) {
+ p->limit = p->stack + UPB_JSON_MAX_DEPTH;
+ p->accumulate_buf = NULL;
+ p->accumulate_buf_size = 0;
+ upb_byteshandler_init(&p->input_handler_);
+ upb_byteshandler_setstring(&p->input_handler_, parse, NULL);
+ upb_byteshandler_setendstr(&p->input_handler_, end, NULL);
+ upb_bytessink_reset(&p->input_, &p->input_handler_, p);
+ p->status = status;
+}
+
+void upb_json_parser_uninit(upb_json_parser *p) {
+ upb_byteshandler_uninit(&p->input_handler_);
+ free(p->accumulate_buf);
+}
+
+void upb_json_parser_reset(upb_json_parser *p) {
+ p->top = p->stack;
+ p->top->f = NULL;
+ p->top->is_map = false;
+ p->top->is_mapentry = false;
+
+ int cs;
+ int top;
+ // Emit Ragel initialization of the parser.
+
+#line 1418 "upb/json/parser.c"
+ {
+ cs = json_start;
+ top = 0;
+ }
+
+#line 1157 "upb/json/parser.rl"
+ p->current_state = cs;
+ p->parser_top = top;
+ accumulate_clear(p);
+ p->multipart_state = MULTIPART_INACTIVE;
+ p->capture = NULL;
+}
+
+void upb_json_parser_resetoutput(upb_json_parser *p, upb_sink *sink) {
+ upb_json_parser_reset(p);
+ upb_sink_reset(&p->top->sink, sink->handlers, sink->closure);
+ p->top->m = upb_handlers_msgdef(sink->handlers);
+ p->accumulated = NULL;
+}
+
+upb_bytessink *upb_json_parser_input(upb_json_parser *p) {
+ return &p->input_;
+}
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2014 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * This currently uses snprintf() to format primitives, and could be optimized
+ * further.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+// StringPiece; a pointer plus a length.
+typedef struct {
+ const char *ptr;
+ size_t len;
+} strpc;
+
+strpc *newstrpc(upb_handlers *h, const upb_fielddef *f) {
+ strpc *ret = malloc(sizeof(*ret));
+ ret->ptr = upb_fielddef_name(f);
+ ret->len = strlen(ret->ptr);
+ upb_handlers_addcleanup(h, ret, free);
+ return ret;
+}
+
+// ------------ JSON string printing: values, maps, arrays --------------------
+
+static void print_data(
+ upb_json_printer *p, const char *buf, unsigned int len) {
+ // TODO: Will need to change if we support pushback from the sink.
+ size_t n = upb_bytessink_putbuf(p->output_, p->subc_, buf, len, NULL);
+ UPB_ASSERT_VAR(n, n == len);
+}
+
+static void print_comma(upb_json_printer *p) {
+ if (!p->first_elem_[p->depth_]) {
+ print_data(p, ",", 1);
+ }
+ p->first_elem_[p->depth_] = false;
+}
+
+// Helpers that print properly formatted elements to the JSON output stream.
+
+// Used for escaping control chars in strings.
+static const char kControlCharLimit = 0x20;
+
+static inline bool is_json_escaped(char c) {
+ // See RFC 4627.
+ unsigned char uc = (unsigned char)c;
+ return uc < kControlCharLimit || uc == '"' || uc == '\\';
+}
+
+static inline char* json_nice_escape(char c) {
+ switch (c) {
+ case '"': return "\\\"";
+ case '\\': return "\\\\";
+ case '\b': return "\\b";
+ case '\f': return "\\f";
+ case '\n': return "\\n";
+ case '\r': return "\\r";
+ case '\t': return "\\t";
+ default: return NULL;
+ }
+}
+
+// Write a properly escaped string chunk. The surrounding quotes are *not*
+// printed; this is so that the caller has the option of emitting the string
+// content in chunks.
+static void putstring(upb_json_printer *p, const char *buf, unsigned int len) {
+ const char* unescaped_run = NULL;
+ for (unsigned int i = 0; i < len; i++) {
+ char c = buf[i];
+ // Handle escaping.
+ if (is_json_escaped(c)) {
+ // Use a "nice" escape, like \n, if one exists for this character.
+ const char* escape = json_nice_escape(c);
+ // If we don't have a specific 'nice' escape code, use a \uXXXX-style
+ // escape.
+ char escape_buf[8];
+ if (!escape) {
+ unsigned char byte = (unsigned char)c;
+ snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)byte);
+ escape = escape_buf;
+ }
+
+ // N.B. that we assume that the input encoding is equal to the output
+ // encoding (both UTF-8 for now), so for chars >= 0x20 and != \, ", we
+ // can simply pass the bytes through.
+
+ // If there's a current run of unescaped chars, print that run first.
+ if (unescaped_run) {
+ print_data(p, unescaped_run, &buf[i] - unescaped_run);
+ unescaped_run = NULL;
+ }
+ // Then print the escape code.
+ print_data(p, escape, strlen(escape));
+ } else {
+ // Add to the current unescaped run of characters.
+ if (unescaped_run == NULL) {
+ unescaped_run = &buf[i];
+ }
+ }
+ }
+
+ // If the string ended in a run of unescaped characters, print that last run.
+ if (unescaped_run) {
+ print_data(p, unescaped_run, &buf[len] - unescaped_run);
+ }
+}
+
+#define CHKLENGTH(x) if (!(x)) return -1;
+
+// Helpers that format floating point values according to our custom formats.
+// Right now we use %.8g and %.17g for float/double, respectively, to match
+// proto2::util::JsonFormat's defaults. May want to change this later.
+
+static size_t fmt_double(double val, char* buf, size_t length) {
+ size_t n = snprintf(buf, length, "%.17g", val);
+ CHKLENGTH(n > 0 && n < length);
+ return n;
+}
+
+static size_t fmt_float(float val, char* buf, size_t length) {
+ size_t n = snprintf(buf, length, "%.8g", val);
+ CHKLENGTH(n > 0 && n < length);
+ return n;
+}
+
+static size_t fmt_bool(bool val, char* buf, size_t length) {
+ size_t n = snprintf(buf, length, "%s", (val ? "true" : "false"));
+ CHKLENGTH(n > 0 && n < length);
+ return n;
+}
+
+static size_t fmt_int64(long val, char* buf, size_t length) {
+ size_t n = snprintf(buf, length, "%ld", val);
+ CHKLENGTH(n > 0 && n < length);
+ return n;
+}
+
+static size_t fmt_uint64(unsigned long long val, char* buf, size_t length) {
+ size_t n = snprintf(buf, length, "%llu", val);
+ CHKLENGTH(n > 0 && n < length);
+ return n;
+}
+
+// Print a map key given a field name. Called by scalar field handlers and by
+// startseq for repeated fields.
+static bool putkey(void *closure, const void *handler_data) {
+ upb_json_printer *p = closure;
+ const strpc *key = handler_data;
+ print_comma(p);
+ print_data(p, "\"", 1);
+ putstring(p, key->ptr, key->len);
+ print_data(p, "\":", 2);
+ return true;
+}
+
+#define CHKFMT(val) if ((val) == -1) return false;
+#define CHK(val) if (!(val)) return false;
+
+#define TYPE_HANDLERS(type, fmt_func) \
+ static bool put##type(void *closure, const void *handler_data, type val) { \
+ upb_json_printer *p = closure; \
+ UPB_UNUSED(handler_data); \
+ char data[64]; \
+ size_t length = fmt_func(val, data, sizeof(data)); \
+ CHKFMT(length); \
+ print_data(p, data, length); \
+ return true; \
+ } \
+ static bool scalar_##type(void *closure, const void *handler_data, \
+ type val) { \
+ CHK(putkey(closure, handler_data)); \
+ CHK(put##type(closure, handler_data, val)); \
+ return true; \
+ } \
+ static bool repeated_##type(void *closure, const void *handler_data, \
+ type val) { \
+ upb_json_printer *p = closure; \
+ print_comma(p); \
+ CHK(put##type(closure, handler_data, val)); \
+ return true; \
+ }
+
+#define TYPE_HANDLERS_MAPKEY(type, fmt_func) \
+ static bool putmapkey_##type(void *closure, const void *handler_data, \
+ type val) { \
+ upb_json_printer *p = closure; \
+ print_data(p, "\"", 1); \
+ CHK(put##type(closure, handler_data, val)); \
+ print_data(p, "\":", 2); \
+ return true; \
+ }
+
+TYPE_HANDLERS(double, fmt_double);
+TYPE_HANDLERS(float, fmt_float);
+TYPE_HANDLERS(bool, fmt_bool);
+TYPE_HANDLERS(int32_t, fmt_int64);
+TYPE_HANDLERS(uint32_t, fmt_int64);
+TYPE_HANDLERS(int64_t, fmt_int64);
+TYPE_HANDLERS(uint64_t, fmt_uint64);
+
+// double and float are not allowed to be map keys.
+TYPE_HANDLERS_MAPKEY(bool, fmt_bool);
+TYPE_HANDLERS_MAPKEY(int32_t, fmt_int64);
+TYPE_HANDLERS_MAPKEY(uint32_t, fmt_int64);
+TYPE_HANDLERS_MAPKEY(int64_t, fmt_int64);
+TYPE_HANDLERS_MAPKEY(uint64_t, fmt_uint64);
+
+#undef TYPE_HANDLERS
+#undef TYPE_HANDLERS_MAPKEY
+
+typedef struct {
+ void *keyname;
+ const upb_enumdef *enumdef;
+} EnumHandlerData;
+
+static bool scalar_enum(void *closure, const void *handler_data,
+ int32_t val) {
+ const EnumHandlerData *hd = handler_data;
+ upb_json_printer *p = closure;
+ CHK(putkey(closure, hd->keyname));
+
+ const char *symbolic_name = upb_enumdef_iton(hd->enumdef, val);
+ if (symbolic_name) {
+ print_data(p, "\"", 1);
+ putstring(p, symbolic_name, strlen(symbolic_name));
+ print_data(p, "\"", 1);
+ } else {
+ putint32_t(closure, NULL, val);
+ }
+
+ return true;
+}
+
+static void print_enum_symbolic_name(upb_json_printer *p,
+ const upb_enumdef *def,
+ int32_t val) {
+ const char *symbolic_name = upb_enumdef_iton(def, val);
+ if (symbolic_name) {
+ print_data(p, "\"", 1);
+ putstring(p, symbolic_name, strlen(symbolic_name));
+ print_data(p, "\"", 1);
+ } else {
+ putint32_t(p, NULL, val);
+ }
+}
+
+static bool repeated_enum(void *closure, const void *handler_data,
+ int32_t val) {
+ const EnumHandlerData *hd = handler_data;
+ upb_json_printer *p = closure;
+ print_comma(p);
+
+ print_enum_symbolic_name(p, hd->enumdef, val);
+
+ return true;
+}
+
+static bool mapvalue_enum(void *closure, const void *handler_data,
+ int32_t val) {
+ const EnumHandlerData *hd = handler_data;
+ upb_json_printer *p = closure;
+
+ print_enum_symbolic_name(p, hd->enumdef, val);
+
+ return true;
+}
+
+static void *scalar_startsubmsg(void *closure, const void *handler_data) {
+ return putkey(closure, handler_data) ? closure : UPB_BREAK;
+}
+
+static void *repeated_startsubmsg(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_json_printer *p = closure;
+ print_comma(p);
+ return closure;
+}
+
+static void start_frame(upb_json_printer *p) {
+ p->depth_++;
+ p->first_elem_[p->depth_] = true;
+ print_data(p, "{", 1);
+}
+
+static void end_frame(upb_json_printer *p) {
+ print_data(p, "}", 1);
+ p->depth_--;
+}
+
+static bool printer_startmsg(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_json_printer *p = closure;
+ if (p->depth_ == 0) {
+ upb_bytessink_start(p->output_, 0, &p->subc_);
+ }
+ start_frame(p);
+ return true;
+}
+
+static bool printer_endmsg(void *closure, const void *handler_data, upb_status *s) {
+ UPB_UNUSED(handler_data);
+ UPB_UNUSED(s);
+ upb_json_printer *p = closure;
+ end_frame(p);
+ if (p->depth_ == 0) {
+ upb_bytessink_end(p->output_);
+ }
+ return true;
+}
+
+static void *startseq(void *closure, const void *handler_data) {
+ upb_json_printer *p = closure;
+ CHK(putkey(closure, handler_data));
+ p->depth_++;
+ p->first_elem_[p->depth_] = true;
+ print_data(p, "[", 1);
+ return closure;
+}
+
+static bool endseq(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_json_printer *p = closure;
+ print_data(p, "]", 1);
+ p->depth_--;
+ return true;
+}
+
+static void *startmap(void *closure, const void *handler_data) {
+ upb_json_printer *p = closure;
+ CHK(putkey(closure, handler_data));
+ p->depth_++;
+ p->first_elem_[p->depth_] = true;
+ print_data(p, "{", 1);
+ return closure;
+}
+
+static bool endmap(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_json_printer *p = closure;
+ print_data(p, "}", 1);
+ p->depth_--;
+ return true;
+}
+
+static size_t putstr(void *closure, const void *handler_data, const char *str,
+ size_t len, const upb_bufhandle *handle) {
+ UPB_UNUSED(handler_data);
+ UPB_UNUSED(handle);
+ upb_json_printer *p = closure;
+ putstring(p, str, len);
+ return len;
+}
+
+// This has to Base64 encode the bytes, because JSON has no "bytes" type.
+static size_t putbytes(void *closure, const void *handler_data, const char *str,
+ size_t len, const upb_bufhandle *handle) {
+ UPB_UNUSED(handler_data);
+ UPB_UNUSED(handle);
+ upb_json_printer *p = closure;
+
+ // This is the regular base64, not the "web-safe" version.
+ static const char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ // Base64-encode.
+ char data[16000];
+ const char *limit = data + sizeof(data);
+ const unsigned char *from = (const unsigned char*)str;
+ char *to = data;
+ size_t remaining = len;
+ while (remaining > 2) {
+ // TODO(haberman): handle encoded lengths > sizeof(data)
+ UPB_ASSERT_VAR(limit, (limit - to) >= 4);
+
+ to[0] = base64[from[0] >> 2];
+ to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)];
+ to[2] = base64[((from[1] & 0xf) << 2) | (from[2] >> 6)];
+ to[3] = base64[from[2] & 0x3f];
+
+ remaining -= 3;
+ to += 4;
+ from += 3;
+ }
+
+ switch (remaining) {
+ case 2:
+ to[0] = base64[from[0] >> 2];
+ to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)];
+ to[2] = base64[(from[1] & 0xf) << 2];
+ to[3] = '=';
+ to += 4;
+ from += 2;
+ break;
+ case 1:
+ to[0] = base64[from[0] >> 2];
+ to[1] = base64[((from[0] & 0x3) << 4)];
+ to[2] = '=';
+ to[3] = '=';
+ to += 4;
+ from += 1;
+ break;
+ }
+
+ size_t bytes = to - data;
+ print_data(p, "\"", 1);
+ putstring(p, data, bytes);
+ print_data(p, "\"", 1);
+ return len;
+}
+
+static void *scalar_startstr(void *closure, const void *handler_data,
+ size_t size_hint) {
+ UPB_UNUSED(handler_data);
+ UPB_UNUSED(size_hint);
+ upb_json_printer *p = closure;
+ CHK(putkey(closure, handler_data));
+ print_data(p, "\"", 1);
+ return p;
+}
+
+static size_t scalar_str(void *closure, const void *handler_data,
+ const char *str, size_t len,
+ const upb_bufhandle *handle) {
+ CHK(putstr(closure, handler_data, str, len, handle));
+ return len;
+}
+
+static bool scalar_endstr(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_json_printer *p = closure;
+ print_data(p, "\"", 1);
+ return true;
+}
+
+static void *repeated_startstr(void *closure, const void *handler_data,
+ size_t size_hint) {
+ UPB_UNUSED(handler_data);
+ UPB_UNUSED(size_hint);
+ upb_json_printer *p = closure;
+ print_comma(p);
+ print_data(p, "\"", 1);
+ return p;
+}
+
+static size_t repeated_str(void *closure, const void *handler_data,
+ const char *str, size_t len,
+ const upb_bufhandle *handle) {
+ CHK(putstr(closure, handler_data, str, len, handle));
+ return len;
+}
+
+static bool repeated_endstr(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_json_printer *p = closure;
+ print_data(p, "\"", 1);
+ return true;
+}
+
+static void *mapkeyval_startstr(void *closure, const void *handler_data,
+ size_t size_hint) {
+ UPB_UNUSED(handler_data);
+ UPB_UNUSED(size_hint);
+ upb_json_printer *p = closure;
+ print_data(p, "\"", 1);
+ return p;
+}
+
+static size_t mapkey_str(void *closure, const void *handler_data,
+ const char *str, size_t len,
+ const upb_bufhandle *handle) {
+ CHK(putstr(closure, handler_data, str, len, handle));
+ return len;
+}
+
+static bool mapkey_endstr(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_json_printer *p = closure;
+ print_data(p, "\":", 2);
+ return true;
+}
+
+static bool mapvalue_endstr(void *closure, const void *handler_data) {
+ UPB_UNUSED(handler_data);
+ upb_json_printer *p = closure;
+ print_data(p, "\"", 1);
+ return true;
+}
+
+static size_t scalar_bytes(void *closure, const void *handler_data,
+ const char *str, size_t len,
+ const upb_bufhandle *handle) {
+ CHK(putkey(closure, handler_data));
+ CHK(putbytes(closure, handler_data, str, len, handle));
+ return len;
+}
+
+static size_t repeated_bytes(void *closure, const void *handler_data,
+ const char *str, size_t len,
+ const upb_bufhandle *handle) {
+ upb_json_printer *p = closure;
+ print_comma(p);
+ CHK(putbytes(closure, handler_data, str, len, handle));
+ return len;
+}
+
+static size_t mapkey_bytes(void *closure, const void *handler_data,
+ const char *str, size_t len,
+ const upb_bufhandle *handle) {
+ upb_json_printer *p = closure;
+ CHK(putbytes(closure, handler_data, str, len, handle));
+ print_data(p, ":", 1);
+ return len;
+}
+
+static void set_enum_hd(upb_handlers *h,
+ const upb_fielddef *f,
+ upb_handlerattr *attr) {
+ EnumHandlerData *hd = malloc(sizeof(EnumHandlerData));
+ hd->enumdef = (const upb_enumdef *)upb_fielddef_subdef(f);
+ hd->keyname = newstrpc(h, f);
+ upb_handlers_addcleanup(h, hd, free);
+ upb_handlerattr_sethandlerdata(attr, hd);
+}
+
+// Set up handlers for a mapentry submessage (i.e., an individual key/value pair
+// in a map).
+//
+// TODO: Handle missing key, missing value, out-of-order key/value, or repeated
+// key or value cases properly. The right way to do this is to allocate a
+// temporary structure at the start of a mapentry submessage, store key and
+// value data in it as key and value handlers are called, and then print the
+// key/value pair once at the end of the submessage. If we don't do this, we
+// should at least detect the case and throw an error. However, so far all of
+// our sources that emit mapentry messages do so canonically (with one key
+// field, and then one value field), so this is not a pressing concern at the
+// moment.
+void printer_sethandlers_mapentry(const void *closure, upb_handlers *h) {
+ UPB_UNUSED(closure);
+ const upb_msgdef *md = upb_handlers_msgdef(h);
+
+ // A mapentry message is printed simply as '"key": value'. Rather than
+ // special-case key and value for every type below, we just handle both
+ // fields explicitly here.
+ const upb_fielddef* key_field = upb_msgdef_itof(md, UPB_MAPENTRY_KEY);
+ const upb_fielddef* value_field = upb_msgdef_itof(md, UPB_MAPENTRY_VALUE);
+
+ upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER;
+
+ switch (upb_fielddef_type(key_field)) {
+ case UPB_TYPE_INT32:
+ upb_handlers_setint32(h, key_field, putmapkey_int32_t, &empty_attr);
+ break;
+ case UPB_TYPE_INT64:
+ upb_handlers_setint64(h, key_field, putmapkey_int64_t, &empty_attr);
+ break;
+ case UPB_TYPE_UINT32:
+ upb_handlers_setuint32(h, key_field, putmapkey_uint32_t, &empty_attr);
+ break;
+ case UPB_TYPE_UINT64:
+ upb_handlers_setuint64(h, key_field, putmapkey_uint64_t, &empty_attr);
+ break;
+ case UPB_TYPE_BOOL:
+ upb_handlers_setbool(h, key_field, putmapkey_bool, &empty_attr);
+ break;
+ case UPB_TYPE_STRING:
+ upb_handlers_setstartstr(h, key_field, mapkeyval_startstr, &empty_attr);
+ upb_handlers_setstring(h, key_field, mapkey_str, &empty_attr);
+ upb_handlers_setendstr(h, key_field, mapkey_endstr, &empty_attr);
+ break;
+ case UPB_TYPE_BYTES:
+ upb_handlers_setstring(h, key_field, mapkey_bytes, &empty_attr);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ switch (upb_fielddef_type(value_field)) {
+ case UPB_TYPE_INT32:
+ upb_handlers_setint32(h, value_field, putint32_t, &empty_attr);
+ break;
+ case UPB_TYPE_INT64:
+ upb_handlers_setint64(h, value_field, putint64_t, &empty_attr);
+ break;
+ case UPB_TYPE_UINT32:
+ upb_handlers_setuint32(h, value_field, putuint32_t, &empty_attr);
+ break;
+ case UPB_TYPE_UINT64:
+ upb_handlers_setuint64(h, value_field, putuint64_t, &empty_attr);
+ break;
+ case UPB_TYPE_BOOL:
+ upb_handlers_setbool(h, value_field, putbool, &empty_attr);
+ break;
+ case UPB_TYPE_FLOAT:
+ upb_handlers_setfloat(h, value_field, putfloat, &empty_attr);
+ break;
+ case UPB_TYPE_DOUBLE:
+ upb_handlers_setdouble(h, value_field, putdouble, &empty_attr);
+ break;
+ case UPB_TYPE_STRING:
+ upb_handlers_setstartstr(h, value_field, mapkeyval_startstr, &empty_attr);
+ upb_handlers_setstring(h, value_field, putstr, &empty_attr);
+ upb_handlers_setendstr(h, value_field, mapvalue_endstr, &empty_attr);
+ break;
+ case UPB_TYPE_BYTES:
+ upb_handlers_setstring(h, value_field, putbytes, &empty_attr);
+ break;
+ case UPB_TYPE_ENUM: {
+ upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
+ set_enum_hd(h, value_field, &enum_attr);
+ upb_handlers_setint32(h, value_field, mapvalue_enum, &enum_attr);
+ upb_handlerattr_uninit(&enum_attr);
+ break;
+ }
+ case UPB_TYPE_MESSAGE:
+ // No handler necessary -- the submsg handlers will print the message
+ // as appropriate.
+ break;
+ }
+
+ upb_handlerattr_uninit(&empty_attr);
+}
+
+void printer_sethandlers(const void *closure, upb_handlers *h) {
+ UPB_UNUSED(closure);
+ const upb_msgdef *md = upb_handlers_msgdef(h);
+ bool is_mapentry = upb_msgdef_mapentry(md);
+ upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER;
+
+ if (is_mapentry) {
+ // mapentry messages are sufficiently different that we handle them
+ // separately.
+ printer_sethandlers_mapentry(closure, h);
+ return;
+ }
+
+ upb_handlers_setstartmsg(h, printer_startmsg, &empty_attr);
+ upb_handlers_setendmsg(h, printer_endmsg, &empty_attr);
+
+#define TYPE(type, name, ctype) \
+ case type: \
+ if (upb_fielddef_isseq(f)) { \
+ upb_handlers_set##name(h, f, repeated_##ctype, &empty_attr); \
+ } else { \
+ upb_handlers_set##name(h, f, scalar_##ctype, &name_attr); \
+ } \
+ break;
+
+ upb_msg_field_iter i;
+ upb_msg_field_begin(&i, md);
+ for(; !upb_msg_field_done(&i); upb_msg_field_next(&i)) {
+ const upb_fielddef *f = upb_msg_iter_field(&i);
+
+ upb_handlerattr name_attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&name_attr, newstrpc(h, f));
+
+ if (upb_fielddef_ismap(f)) {
+ upb_handlers_setstartseq(h, f, startmap, &name_attr);
+ upb_handlers_setendseq(h, f, endmap, &name_attr);
+ } else if (upb_fielddef_isseq(f)) {
+ upb_handlers_setstartseq(h, f, startseq, &name_attr);
+ upb_handlers_setendseq(h, f, endseq, &empty_attr);
+ }
+
+ switch (upb_fielddef_type(f)) {
+ TYPE(UPB_TYPE_FLOAT, float, float);
+ TYPE(UPB_TYPE_DOUBLE, double, double);
+ TYPE(UPB_TYPE_BOOL, bool, bool);
+ TYPE(UPB_TYPE_INT32, int32, int32_t);
+ TYPE(UPB_TYPE_UINT32, uint32, uint32_t);
+ TYPE(UPB_TYPE_INT64, int64, int64_t);
+ TYPE(UPB_TYPE_UINT64, uint64, uint64_t);
+ case UPB_TYPE_ENUM: {
+ // For now, we always emit symbolic names for enums. We may want an
+ // option later to control this behavior, but we will wait for a real
+ // need first.
+ upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
+ set_enum_hd(h, f, &enum_attr);
+
+ if (upb_fielddef_isseq(f)) {
+ upb_handlers_setint32(h, f, repeated_enum, &enum_attr);
+ } else {
+ upb_handlers_setint32(h, f, scalar_enum, &enum_attr);
+ }
+
+ upb_handlerattr_uninit(&enum_attr);
+ break;
+ }
+ case UPB_TYPE_STRING:
+ if (upb_fielddef_isseq(f)) {
+ upb_handlers_setstartstr(h, f, repeated_startstr, &empty_attr);
+ upb_handlers_setstring(h, f, repeated_str, &empty_attr);
+ upb_handlers_setendstr(h, f, repeated_endstr, &empty_attr);
+ } else {
+ upb_handlers_setstartstr(h, f, scalar_startstr, &name_attr);
+ upb_handlers_setstring(h, f, scalar_str, &empty_attr);
+ upb_handlers_setendstr(h, f, scalar_endstr, &empty_attr);
+ }
+ break;
+ case UPB_TYPE_BYTES:
+ // XXX: this doesn't support strings that span buffers yet. The base64
+ // encoder will need to be made resumable for this to work properly.
+ if (upb_fielddef_isseq(f)) {
+ upb_handlers_setstring(h, f, repeated_bytes, &empty_attr);
+ } else {
+ upb_handlers_setstring(h, f, scalar_bytes, &name_attr);
+ }
+ break;
+ case UPB_TYPE_MESSAGE:
+ if (upb_fielddef_isseq(f)) {
+ upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &name_attr);
+ } else {
+ upb_handlers_setstartsubmsg(h, f, scalar_startsubmsg, &name_attr);
+ }
+ break;
+ }
+
+ upb_handlerattr_uninit(&name_attr);
+ }
+
+ upb_handlerattr_uninit(&empty_attr);
+#undef TYPE
+}
+
+/* Public API *****************************************************************/
+
+void upb_json_printer_init(upb_json_printer *p, const upb_handlers *h) {
+ p->output_ = NULL;
+ p->depth_ = 0;
+ upb_sink_reset(&p->input_, h, p);
+}
+
+void upb_json_printer_uninit(upb_json_printer *p) {
+ UPB_UNUSED(p);
+}
+
+void upb_json_printer_reset(upb_json_printer *p) {
+ p->depth_ = 0;
+}
+
+void upb_json_printer_resetoutput(upb_json_printer *p, upb_bytessink *output) {
+ upb_json_printer_reset(p);
+ p->output_ = output;
+}
+
+upb_sink *upb_json_printer_input(upb_json_printer *p) {
+ return &p->input_;
+}
+
+const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+ const void *owner) {
+ return upb_handlers_newfrozen(md, owner, printer_sethandlers, NULL);
+}
diff --git a/ruby/ext/google/protobuf_c/upb.h b/ruby/ext/google/protobuf_c/upb.h
new file mode 100644
index 00000000..8f6d3643
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/upb.h
@@ -0,0 +1,8050 @@
+// Amalgamated source file
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * Defs are upb's internal representation of the constructs that can appear
+ * in a .proto file:
+ *
+ * - upb_msgdef: describes a "message" construct.
+ * - upb_fielddef: describes a message field.
+ * - upb_enumdef: describes an enum.
+ * (TODO: definitions of services).
+ *
+ * Like upb_refcounted objects, defs are mutable only until frozen, and are
+ * only thread-safe once frozen.
+ *
+ * This is a mixed C/C++ interface that offers a full API to both languages.
+ * See the top-level README for more information.
+ */
+
+#ifndef UPB_DEF_H_
+#define UPB_DEF_H_
+
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * A refcounting scheme that supports circular refs. It accomplishes this by
+ * partitioning the set of objects into groups such that no cycle spans groups;
+ * we can then reference-count the group as a whole and ignore refs within the
+ * group. When objects are mutable, these groups are computed very
+ * conservatively; we group any objects that have ever had a link between them.
+ * When objects are frozen, we compute strongly-connected components which
+ * allows us to be precise and only group objects that are actually cyclic.
+ *
+ * This is a mixed C/C++ interface that offers a full API to both languages.
+ * See the top-level README for more information.
+ */
+
+#ifndef UPB_REFCOUNTED_H_
+#define UPB_REFCOUNTED_H_
+
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * This header is INTERNAL-ONLY! Its interfaces are not public or stable!
+ * This file defines very fast int->upb_value (inttable) and string->upb_value
+ * (strtable) hash tables.
+ *
+ * The table uses chained scatter with Brent's variation (inspired by the Lua
+ * implementation of hash tables). The hash function for strings is Austin
+ * Appleby's "MurmurHash."
+ *
+ * The inttable uses uintptr_t as its key, which guarantees it can be used to
+ * store pointers or integers of at least 32 bits (upb isn't really useful on
+ * systems where sizeof(void*) < 4).
+ *
+ * The table must be homogenous (all values of the same type). In debug
+ * mode, we check this on insert and lookup.
+ */
+
+#ifndef UPB_TABLE_H_
+#define UPB_TABLE_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * This file contains shared definitions that are widely used across upb.
+ *
+ * This is a mixed C/C++ interface that offers a full API to both languages.
+ * See the top-level README for more information.
+ */
+
+#ifndef UPB_H_
+#define UPB_H_
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+// inline if possible, emit standalone code if required.
+#ifdef __cplusplus
+#define UPB_INLINE inline
+#else
+#define UPB_INLINE static inline
+#endif
+
+#if __STDC_VERSION__ >= 199901L
+#define UPB_C99
+#endif
+
+#if ((defined(__cplusplus) && __cplusplus >= 201103L) || \
+ defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(UPB_NO_CXX11)
+#define UPB_CXX11
+#endif
+
+#ifdef UPB_CXX11
+#include <type_traits>
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
+ class_name(const class_name&) = delete; \
+ void operator=(const class_name&) = delete;
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+ class_name() = delete; \
+ ~class_name() = delete; \
+ /* Friend Pointer<T> so it can access base class. */ \
+ friend class Pointer<full_class_name>; \
+ friend class Pointer<const full_class_name>; \
+ UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
+#define UPB_ASSERT_STDLAYOUT(type) \
+ static_assert(std::is_standard_layout<type>::value, \
+ #type " must be standard layout");
+#else // !defined(UPB_CXX11)
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
+ class_name(const class_name&); \
+ void operator=(const class_name&);
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+ class_name(); \
+ ~class_name(); \
+ /* Friend Pointer<T> so it can access base class. */ \
+ friend class Pointer<full_class_name>; \
+ friend class Pointer<const full_class_name>; \
+ UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
+#define UPB_ASSERT_STDLAYOUT(type)
+#endif
+
+
+#ifdef __cplusplus
+
+#define UPB_PRIVATE_FOR_CPP private:
+#define UPB_DECLARE_TYPE(cppname, cname) typedef cppname cname;
+#define UPB_BEGIN_EXTERN_C extern "C" {
+#define UPB_END_EXTERN_C }
+#define UPB_DEFINE_STRUCT0(cname, members) members;
+#define UPB_DEFINE_STRUCT(cname, cbase, members) \
+ public: \
+ cbase* base() { return &base_; } \
+ const cbase* base() const { return &base_; } \
+ \
+ private: \
+ cbase base_; \
+ members;
+#define UPB_DEFINE_CLASS0(cppname, cppmethods, members) \
+ class cppname { \
+ cppmethods \
+ members \
+ }; \
+ UPB_ASSERT_STDLAYOUT(cppname);
+#define UPB_DEFINE_CLASS1(cppname, cppbase, cppmethods, members) \
+ UPB_DEFINE_CLASS0(cppname, cppmethods, members) \
+ namespace upb { \
+ template <> \
+ class Pointer<cppname> : public PointerBase<cppname, cppbase> { \
+ public: \
+ explicit Pointer(cppname* ptr) : PointerBase(ptr) {} \
+ }; \
+ template <> \
+ class Pointer<const cppname> \
+ : public PointerBase<const cppname, const cppbase> { \
+ public: \
+ explicit Pointer(const cppname* ptr) : PointerBase(ptr) {} \
+ }; \
+ }
+#define UPB_DEFINE_CLASS2(cppname, cppbase, cppbase2, cppmethods, members) \
+ UPB_DEFINE_CLASS0(cppname, UPB_QUOTE(cppmethods), members) \
+ namespace upb { \
+ template <> \
+ class Pointer<cppname> : public PointerBase2<cppname, cppbase, cppbase2> { \
+ public: \
+ explicit Pointer(cppname* ptr) : PointerBase2(ptr) {} \
+ }; \
+ template <> \
+ class Pointer<const cppname> \
+ : public PointerBase2<const cppname, const cppbase, const cppbase2> { \
+ public: \
+ explicit Pointer(const cppname* ptr) : PointerBase2(ptr) {} \
+ }; \
+ }
+
+#else // !defined(__cplusplus)
+
+#define UPB_PRIVATE_FOR_CPP
+#define UPB_DECLARE_TYPE(cppname, cname) \
+ struct cname; \
+ typedef struct cname cname;
+#define UPB_BEGIN_EXTERN_C
+#define UPB_END_EXTERN_C
+#define UPB_DEFINE_STRUCT0(cname, members) \
+ struct cname { \
+ members; \
+ };
+#define UPB_DEFINE_STRUCT(cname, cbase, members) \
+ struct cname { \
+ cbase base; \
+ members; \
+ };
+#define UPB_DEFINE_CLASS0(cppname, cppmethods, members) members
+#define UPB_DEFINE_CLASS1(cppname, cppbase, cppmethods, members) members
+#define UPB_DEFINE_CLASS2(cppname, cppbase, cppbase2, cppmethods, members) \
+ members
+
+#endif // defined(__cplusplus)
+
+#ifdef __GNUC__
+#define UPB_NORETURN __attribute__((__noreturn__))
+#else
+#define UPB_NORETURN
+#endif
+
+#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
+#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#define UPB_UNUSED(var) (void)var
+
+// Code with commas confuses the preprocessor when passed as arguments, whether
+// C++ type names with commas (eg. Foo<int, int>) or code blocks that declare
+// variables (ie. int foo, bar).
+#define UPB_QUOTE(...) __VA_ARGS__
+
+// For asserting something about a variable when the variable is not used for
+// anything else. This prevents "unused variable" warnings when compiling in
+// debug mode.
+#define UPB_ASSERT_VAR(var, predicate) UPB_UNUSED(var); assert(predicate)
+
+// Generic function type.
+typedef void upb_func();
+
+/* Casts **********************************************************************/
+
+// Upcasts for C. For downcasts see the definitions of the subtypes.
+#define UPB_UPCAST(obj) (&(obj)->base)
+#define UPB_UPCAST2(obj) UPB_UPCAST(UPB_UPCAST(obj))
+
+#ifdef __cplusplus
+
+// Downcasts for C++. We can't use C++ inheritance directly and maintain
+// compatibility with C. So our inheritance is undeclared in C++.
+// Specializations of these casting functions are defined for appropriate type
+// pairs, and perform the necessary checks.
+//
+// Example:
+// upb::Def* def = <...>;
+// upb::MessageDef* = upb::dyn_cast<upb::MessageDef*>(def);
+
+namespace upb {
+
+// Casts to a direct subclass. The caller must know that cast is correct; an
+// incorrect cast will throw an assertion failure in debug mode.
+template<class To, class From> To down_cast(From* f);
+
+// Casts to a direct subclass. If the class does not actually match the given
+// subtype, returns NULL.
+template<class To, class From> To dyn_cast(From* f);
+
+// Pointer<T> is a simple wrapper around a T*. It is only constructed for
+// upcast() below, and its sole purpose is to be implicitly convertable to T* or
+// pointers to base classes, just as a pointer would be in regular C++ if the
+// inheritance were directly expressed as C++ inheritance.
+template <class T> class Pointer;
+
+// Casts to any base class, or the type itself (ie. can be a no-op).
+template <class T> inline Pointer<T> upcast(T *f) { return Pointer<T>(f); }
+
+template <class T, class Base>
+class PointerBase {
+ public:
+ explicit PointerBase(T* ptr) : ptr_(ptr) {}
+ operator T*() { return ptr_; }
+ operator Base*() { return ptr_->base(); }
+
+ private:
+ T* ptr_;
+};
+
+template <class T, class Base, class Base2>
+class PointerBase2 : public PointerBase<T, Base> {
+ public:
+ explicit PointerBase2(T* ptr) : PointerBase<T, Base>(ptr) {}
+ operator Base2*() { return Pointer<Base>(*this); }
+};
+
+}
+
+#endif
+
+
+/* upb::reffed_ptr ************************************************************/
+
+#ifdef __cplusplus
+
+#include <algorithm> // For std::swap().
+
+namespace upb {
+
+// Provides RAII semantics for upb refcounted objects. Each reffed_ptr owns a
+// ref on whatever object it points to (if any).
+template <class T> class reffed_ptr {
+ public:
+ reffed_ptr() : ptr_(NULL) {}
+
+ // If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor.
+ template <class U>
+ reffed_ptr(U* val, const void* ref_donor = NULL)
+ : ptr_(upb::upcast(val)) {
+ if (ref_donor) {
+ assert(ptr_);
+ ptr_->DonateRef(ref_donor, this);
+ } else if (ptr_) {
+ ptr_->Ref(this);
+ }
+ }
+
+ template <class U>
+ reffed_ptr(const reffed_ptr<U>& other)
+ : ptr_(upb::upcast(other.get())) {
+ if (ptr_) ptr_->Ref(this);
+ }
+
+ ~reffed_ptr() { if (ptr_) ptr_->Unref(this); }
+
+ template <class U>
+ reffed_ptr& operator=(const reffed_ptr<U>& other) {
+ reset(other.get());
+ return *this;
+ }
+
+ reffed_ptr& operator=(const reffed_ptr& other) {
+ reset(other.get());
+ return *this;
+ }
+
+ // TODO(haberman): add C++11 move construction/assignment for greater
+ // efficiency.
+
+ void swap(reffed_ptr& other) {
+ if (ptr_ == other.ptr_) {
+ return;
+ }
+
+ if (ptr_) ptr_->DonateRef(this, &other);
+ if (other.ptr_) other.ptr_->DonateRef(&other, this);
+ std::swap(ptr_, other.ptr_);
+ }
+
+ T& operator*() const {
+ assert(ptr_);
+ return *ptr_;
+ }
+
+ T* operator->() const {
+ assert(ptr_);
+ return ptr_;
+ }
+
+ T* get() const { return ptr_; }
+
+ // If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor.
+ template <class U>
+ void reset(U* ptr = NULL, const void* ref_donor = NULL) {
+ reffed_ptr(ptr, ref_donor).swap(*this);
+ }
+
+ template <class U>
+ reffed_ptr<U> down_cast() {
+ return reffed_ptr<U>(upb::down_cast<U*>(get()));
+ }
+
+ template <class U>
+ reffed_ptr<U> dyn_cast() {
+ return reffed_ptr<U>(upb::dyn_cast<U*>(get()));
+ }
+
+ // Plain release() is unsafe; if we were the only owner, it would leak the
+ // object. Instead we provide this:
+ T* ReleaseTo(const void* new_owner) {
+ T* ret = NULL;
+ ptr_->DonateRef(this, new_owner);
+ std::swap(ret, ptr_);
+ return ret;
+ }
+
+ private:
+ T* ptr_;
+};
+
+} // namespace upb
+
+#endif // __cplusplus
+
+
+/* upb::Status ****************************************************************/
+
+#ifdef __cplusplus
+namespace upb {
+class ErrorSpace;
+class Status;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::ErrorSpace, upb_errorspace);
+UPB_DECLARE_TYPE(upb::Status, upb_status);
+
+// The maximum length of an error message before it will get truncated.
+#define UPB_STATUS_MAX_MESSAGE 128
+
+// An error callback function is used to report errors from some component.
+// The function can return "true" to indicate that the component should try
+// to recover and proceed, but this is not always possible.
+typedef bool upb_errcb_t(void *closure, const upb_status* status);
+
+UPB_DEFINE_CLASS0(upb::ErrorSpace,
+,
+UPB_DEFINE_STRUCT0(upb_errorspace,
+ const char *name;
+ // Should the error message in the status object according to this code.
+ void (*set_message)(upb_status* status, int code);
+));
+
+// Object representing a success or failure status.
+// It owns no resources and allocates no memory, so it should work
+// even in OOM situations.
+UPB_DEFINE_CLASS0(upb::Status,
+ public:
+ Status();
+
+ // Returns true if there is no error.
+ bool ok() const;
+
+ // Optional error space and code, useful if the caller wants to
+ // programmatically check the specific kind of error.
+ ErrorSpace* error_space();
+ int code() const;
+
+ const char *error_message() const;
+
+ // The error message will be truncated if it is longer than
+ // UPB_STATUS_MAX_MESSAGE-4.
+ void SetErrorMessage(const char* msg);
+ void SetFormattedErrorMessage(const char* fmt, ...);
+
+ // If there is no error message already, this will use the ErrorSpace to
+ // populate the error message for this code. The caller can still call
+ // SetErrorMessage() to give a more specific message.
+ void SetErrorCode(ErrorSpace* space, int code);
+
+ // Resets the status to a successful state with no message.
+ void Clear();
+
+ void CopyFrom(const Status& other);
+
+ private:
+ UPB_DISALLOW_COPY_AND_ASSIGN(Status);
+,
+UPB_DEFINE_STRUCT0(upb_status,
+ bool ok_;
+
+ // Specific status code defined by some error space (optional).
+ int code_;
+ upb_errorspace *error_space_;
+
+ // Error message; NULL-terminated.
+ char msg[UPB_STATUS_MAX_MESSAGE];
+));
+
+#define UPB_STATUS_INIT {true, 0, NULL, {0}}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// The returned string is invalidated by any other call into the status.
+const char *upb_status_errmsg(const upb_status *status);
+bool upb_ok(const upb_status *status);
+upb_errorspace *upb_status_errspace(const upb_status *status);
+int upb_status_errcode(const upb_status *status);
+
+// Any of the functions that write to a status object allow status to be NULL,
+// to support use cases where the function's caller does not care about the
+// status message.
+void upb_status_clear(upb_status *status);
+void upb_status_seterrmsg(upb_status *status, const char *msg);
+void upb_status_seterrf(upb_status *status, const char *fmt, ...);
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args);
+void upb_status_seterrcode(upb_status *status, upb_errorspace *space, int code);
+void upb_status_copy(upb_status *to, const upb_status *from);
+
+#ifdef __cplusplus
+} // extern "C"
+
+namespace upb {
+
+// C++ Wrappers
+inline Status::Status() { Clear(); }
+inline bool Status::ok() const { return upb_ok(this); }
+inline const char* Status::error_message() const {
+ return upb_status_errmsg(this);
+}
+inline void Status::SetErrorMessage(const char* msg) {
+ upb_status_seterrmsg(this, msg);
+}
+inline void Status::SetFormattedErrorMessage(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ upb_status_vseterrf(this, fmt, args);
+ va_end(args);
+}
+inline void Status::SetErrorCode(ErrorSpace* space, int code) {
+ upb_status_seterrcode(this, space, code);
+}
+inline void Status::Clear() { upb_status_clear(this); }
+inline void Status::CopyFrom(const Status& other) {
+ upb_status_copy(this, &other);
+}
+
+} // namespace upb
+
+#endif
+
+#endif /* UPB_H_ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* upb_value ******************************************************************/
+
+// A tagged union (stored untagged inside the table) so that we can check that
+// clients calling table accessors are correctly typed without having to have
+// an explosion of accessors.
+typedef enum {
+ UPB_CTYPE_INT32 = 1,
+ UPB_CTYPE_INT64 = 2,
+ UPB_CTYPE_UINT32 = 3,
+ UPB_CTYPE_UINT64 = 4,
+ UPB_CTYPE_BOOL = 5,
+ UPB_CTYPE_CSTR = 6,
+ UPB_CTYPE_PTR = 7,
+ UPB_CTYPE_CONSTPTR = 8,
+ UPB_CTYPE_FPTR = 9,
+} upb_ctype_t;
+
+typedef union {
+ int32_t int32;
+ int64_t int64;
+ uint64_t uint64;
+ uint32_t uint32;
+ bool _bool;
+ char *cstr;
+ void *ptr;
+ const void *constptr;
+ upb_func *fptr;
+} _upb_value;
+
+typedef struct {
+ _upb_value val;
+#ifndef NDEBUG
+ // In debug mode we carry the value type around also so we can check accesses
+ // to be sure the right member is being read.
+ upb_ctype_t ctype;
+#endif
+} upb_value;
+
+#ifdef UPB_C99
+#define UPB_VALUE_INIT(v, member) {.member = v}
+#endif
+#define UPB__VALUE_INIT_NONE UPB_VALUE_INIT(NULL, ptr)
+
+#ifdef NDEBUG
+#define SET_TYPE(dest, val) UPB_UNUSED(val)
+#define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE}
+#else
+#define SET_TYPE(dest, val) dest = val
+// Non-existent type, all reads will fail.
+#define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE, -1}
+#endif
+
+#define UPB_VALUE_INIT_INT32(v) UPB_VALUE_INIT(v, int32)
+#define UPB_VALUE_INIT_INT64(v) UPB_VALUE_INIT(v, int64)
+#define UPB_VALUE_INIT_UINT32(v) UPB_VALUE_INIT(v, uint32)
+#define UPB_VALUE_INIT_UINT64(v) UPB_VALUE_INIT(v, uint64)
+#define UPB_VALUE_INIT_BOOL(v) UPB_VALUE_INIT(v, _bool)
+#define UPB_VALUE_INIT_CSTR(v) UPB_VALUE_INIT(v, cstr)
+#define UPB_VALUE_INIT_PTR(v) UPB_VALUE_INIT(v, ptr)
+#define UPB_VALUE_INIT_CONSTPTR(v) UPB_VALUE_INIT(v, constptr)
+#define UPB_VALUE_INIT_FPTR(v) UPB_VALUE_INIT(v, fptr)
+
+// Like strdup(), which isn't always available since it's not ANSI C.
+char *upb_strdup(const char *s);
+// Variant that works with a length-delimited rather than NULL-delimited string,
+// as supported by strtable.
+char *upb_strdup2(const char *s, size_t len);
+
+UPB_INLINE void _upb_value_setval(upb_value *v, _upb_value val,
+ upb_ctype_t ctype) {
+ v->val = val;
+ SET_TYPE(v->ctype, ctype);
+}
+
+UPB_INLINE upb_value _upb_value_val(_upb_value val, upb_ctype_t ctype) {
+ upb_value ret;
+ _upb_value_setval(&ret, val, ctype);
+ return ret;
+}
+
+// For each value ctype, define the following set of functions:
+//
+// // Get/set an int32 from a upb_value.
+// int32_t upb_value_getint32(upb_value val);
+// void upb_value_setint32(upb_value *val, int32_t cval);
+//
+// // Construct a new upb_value from an int32.
+// upb_value upb_value_int32(int32_t val);
+#define FUNCS(name, membername, type_t, proto_type) \
+ UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \
+ val->val.uint64 = 0; \
+ SET_TYPE(val->ctype, proto_type); \
+ val->val.membername = cval; \
+ } \
+ UPB_INLINE upb_value upb_value_ ## name(type_t val) { \
+ upb_value ret; \
+ upb_value_set ## name(&ret, val); \
+ return ret; \
+ } \
+ UPB_INLINE type_t upb_value_get ## name(upb_value val) { \
+ assert(val.ctype == proto_type); \
+ return val.val.membername; \
+ }
+
+FUNCS(int32, int32, int32_t, UPB_CTYPE_INT32);
+FUNCS(int64, int64, int64_t, UPB_CTYPE_INT64);
+FUNCS(uint32, uint32, uint32_t, UPB_CTYPE_UINT32);
+FUNCS(uint64, uint64, uint64_t, UPB_CTYPE_UINT64);
+FUNCS(bool, _bool, bool, UPB_CTYPE_BOOL);
+FUNCS(cstr, cstr, char*, UPB_CTYPE_CSTR);
+FUNCS(ptr, ptr, void*, UPB_CTYPE_PTR);
+FUNCS(constptr, constptr, const void*, UPB_CTYPE_CONSTPTR);
+FUNCS(fptr, fptr, upb_func*, UPB_CTYPE_FPTR);
+
+#undef FUNCS
+
+
+/* upb_table ******************************************************************/
+
+typedef union {
+ uintptr_t num;
+ struct {
+ // We own this. NULL-terminated but may also contain binary data; see
+ // explicit length below.
+ // TODO: move the length to the start of the string in order to reduce
+ // tabkey's size (to one machine word) in a way that supports static
+ // initialization.
+ const char *str;
+ size_t length;
+ } s;
+} upb_tabkey;
+
+#define UPB_TABKEY_NUM(n) {n}
+#ifdef UPB_C99
+// Given that |s| is a string literal, sizeof(s) gives us a
+// compile-time-constant strlen(). We must ensure that this works for static
+// data initializers.
+#define UPB_TABKEY_STR(strval) { .s = { .str = strval, \
+ .length = sizeof(strval) - 1 } }
+#endif
+// TODO(haberman): C++
+#define UPB_TABKEY_NONE {0}
+
+typedef struct _upb_tabent {
+ upb_tabkey key;
+ _upb_value val;
+ // Internal chaining. This is const so we can create static initializers for
+ // tables. We cast away const sometimes, but *only* when the containing
+ // upb_table is known to be non-const. This requires a bit of care, but
+ // the subtlety is confined to table.c.
+ const struct _upb_tabent *next;
+} upb_tabent;
+
+typedef struct {
+ size_t count; // Number of entries in the hash part.
+ size_t mask; // Mask to turn hash value -> bucket.
+ upb_ctype_t ctype; // Type of all values.
+ uint8_t size_lg2; // Size of the hash table part is 2^size_lg2 entries.
+
+ // Hash table entries.
+ // Making this const isn't entirely accurate; what we really want is for it to
+ // have the same const-ness as the table it's inside. But there's no way to
+ // declare that in C. So we have to make it const so that we can statically
+ // initialize const hash tables. Then we cast away const when we have to.
+ const upb_tabent *entries;
+} upb_table;
+
+typedef struct {
+ upb_table t;
+} upb_strtable;
+
+#define UPB_STRTABLE_INIT(count, mask, ctype, size_lg2, entries) \
+ {{count, mask, ctype, size_lg2, entries}}
+
+#define UPB_EMPTY_STRTABLE_INIT(ctype) \
+ UPB_STRTABLE_INIT(0, 0, ctype, 0, NULL)
+
+typedef struct {
+ upb_table t; // For entries that don't fit in the array part.
+ const _upb_value *array; // Array part of the table. See const note above.
+ size_t array_size; // Array part size.
+ size_t array_count; // Array part number of elements.
+} upb_inttable;
+
+#define UPB_INTTABLE_INIT(count, mask, ctype, size_lg2, ent, a, asize, acount) \
+ {{count, mask, ctype, size_lg2, ent}, a, asize, acount}
+
+#define UPB_EMPTY_INTTABLE_INIT(ctype) \
+ UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0)
+
+#define UPB_ARRAY_EMPTYVAL -1
+#define UPB_ARRAY_EMPTYENT UPB_VALUE_INIT_INT64(UPB_ARRAY_EMPTYVAL)
+
+UPB_INLINE size_t upb_table_size(const upb_table *t) {
+ if (t->size_lg2 == 0)
+ return 0;
+ else
+ return 1 << t->size_lg2;
+}
+
+// Internal-only functions, in .h file only out of necessity.
+UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) {
+ return e->key.num == 0;
+}
+
+// Used by some of the unit tests for generic hashing functionality.
+uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed);
+
+UPB_INLINE upb_tabkey upb_intkey(uintptr_t key) {
+ upb_tabkey k;
+ k.num = key;
+ return k;
+}
+
+UPB_INLINE uint32_t upb_inthash(uintptr_t key) {
+ return (uint32_t)key;
+}
+
+static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) {
+ return t->entries + (hash & t->mask);
+}
+
+UPB_INLINE bool upb_arrhas(_upb_value v) {
+ return v.uint64 != (uint64_t)UPB_ARRAY_EMPTYVAL;
+}
+
+// Initialize and uninitialize a table, respectively. If memory allocation
+// failed, false is returned that the table is uninitialized.
+bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype);
+bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype);
+void upb_inttable_uninit(upb_inttable *table);
+void upb_strtable_uninit(upb_strtable *table);
+
+// Returns the number of values in the table.
+size_t upb_inttable_count(const upb_inttable *t);
+UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) {
+ return t->t.count;
+}
+
+// Inserts the given key into the hashtable with the given value. The key must
+// not already exist in the hash table. For string tables, the key must be
+// NULL-terminated, and the table will make an internal copy of the key.
+// Inttables must not insert a value of UINTPTR_MAX.
+//
+// If a table resize was required but memory allocation failed, false is
+// returned and the table is unchanged.
+bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val);
+bool upb_strtable_insert2(upb_strtable *t, const char *key, size_t len,
+ upb_value val);
+
+// For NULL-terminated strings.
+UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key,
+ upb_value val) {
+ return upb_strtable_insert2(t, key, strlen(key), val);
+}
+
+// Looks up key in this table, returning "true" if the key was found.
+// If v is non-NULL, copies the value for this key into *v.
+bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v);
+bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
+ upb_value *v);
+
+// For NULL-terminated strings.
+UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key,
+ upb_value *v) {
+ return upb_strtable_lookup2(t, key, strlen(key), v);
+}
+
+// Removes an item from the table. Returns true if the remove was successful,
+// and stores the removed item in *val if non-NULL.
+bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val);
+bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len,
+ upb_value *val);
+
+// For NULL-terminated strings.
+UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key,
+ upb_value *v) {
+ return upb_strtable_remove2(t, key, strlen(key), v);
+}
+
+// Updates an existing entry in an inttable. If the entry does not exist,
+// returns false and does nothing. Unlike insert/remove, this does not
+// invalidate iterators.
+bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val);
+
+// Handy routines for treating an inttable like a stack. May not be mixed with
+// other insert/remove calls.
+bool upb_inttable_push(upb_inttable *t, upb_value val);
+upb_value upb_inttable_pop(upb_inttable *t);
+
+// Convenience routines for inttables with pointer keys.
+bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val);
+bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val);
+bool upb_inttable_lookupptr(
+ const upb_inttable *t, const void *key, upb_value *val);
+
+// Optimizes the table for the current set of entries, for both memory use and
+// lookup time. Client should call this after all entries have been inserted;
+// inserting more entries is legal, but will likely require a table resize.
+void upb_inttable_compact(upb_inttable *t);
+
+// A special-case inlinable version of the lookup routine for 32-bit integers.
+UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key,
+ upb_value *v) {
+ *v = upb_value_int32(0); // Silence compiler warnings.
+ if (key < t->array_size) {
+ _upb_value arrval = t->array[key];
+ if (upb_arrhas(arrval)) {
+ _upb_value_setval(v, arrval, t->t.ctype);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ const upb_tabent *e;
+ if (t->t.entries == NULL) return false;
+ for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) {
+ if ((uint32_t)e->key.num == key) {
+ _upb_value_setval(v, e->val, t->t.ctype);
+ return true;
+ }
+ if (e->next == NULL) return false;
+ }
+ }
+}
+
+// Exposed for testing only.
+bool upb_strtable_resize(upb_strtable *t, size_t size_lg2);
+
+/* Iterators ******************************************************************/
+
+// Iterators for int and string tables. We are subject to some kind of unusual
+// design constraints:
+//
+// For high-level languages:
+// - we must be able to guarantee that we don't crash or corrupt memory even if
+// the program accesses an invalidated iterator.
+//
+// For C++11 range-based for:
+// - iterators must be copyable
+// - iterators must be comparable
+// - it must be possible to construct an "end" value.
+//
+// Iteration order is undefined.
+//
+// Modifying the table invalidates iterators. upb_{str,int}table_done() is
+// guaranteed to work even on an invalidated iterator, as long as the table it
+// is iterating over has not been freed. Calling next() or accessing data from
+// an invalidated iterator yields unspecified elements from the table, but it is
+// guaranteed not to crash and to return real table elements (except when done()
+// is true).
+
+
+/* upb_strtable_iter **********************************************************/
+
+// upb_strtable_iter i;
+// upb_strtable_begin(&i, t);
+// for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+// const char *key = upb_strtable_iter_key(&i);
+// const upb_value val = upb_strtable_iter_value(&i);
+// // ...
+// }
+
+typedef struct {
+ const upb_strtable *t;
+ size_t index;
+} upb_strtable_iter;
+
+void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t);
+void upb_strtable_next(upb_strtable_iter *i);
+bool upb_strtable_done(const upb_strtable_iter *i);
+const char *upb_strtable_iter_key(upb_strtable_iter *i);
+size_t upb_strtable_iter_keylength(upb_strtable_iter *i);
+upb_value upb_strtable_iter_value(const upb_strtable_iter *i);
+void upb_strtable_iter_setdone(upb_strtable_iter *i);
+bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
+ const upb_strtable_iter *i2);
+
+
+/* upb_inttable_iter **********************************************************/
+
+// upb_inttable_iter i;
+// upb_inttable_begin(&i, t);
+// for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+// uintptr_t key = upb_inttable_iter_key(&i);
+// upb_value val = upb_inttable_iter_value(&i);
+// // ...
+// }
+
+typedef struct {
+ const upb_inttable *t;
+ size_t index;
+ bool array_part;
+} upb_inttable_iter;
+
+void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t);
+void upb_inttable_next(upb_inttable_iter *i);
+bool upb_inttable_done(const upb_inttable_iter *i);
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i);
+upb_value upb_inttable_iter_value(const upb_inttable_iter *i);
+void upb_inttable_iter_setdone(upb_inttable_iter *i);
+bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
+ const upb_inttable_iter *i2);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* UPB_TABLE_H_ */
+
+// Reference tracking will check ref()/unref() operations to make sure the
+// ref ownership is correct. Where possible it will also make tools like
+// Valgrind attribute ref leaks to the code that took the leaked ref, not
+// the code that originally created the object.
+//
+// Enabling this requires the application to define upb_lock()/upb_unlock()
+// functions that acquire/release a global mutex (or #define UPB_THREAD_UNSAFE).
+#ifndef NDEBUG
+#define UPB_DEBUG_REFS
+#endif
+
+#ifdef __cplusplus
+namespace upb { class RefCounted; }
+#endif
+
+UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted);
+
+struct upb_refcounted_vtbl;
+
+UPB_DEFINE_CLASS0(upb::RefCounted,
+ public:
+ // Returns true if the given object is frozen.
+ bool IsFrozen() const;
+
+ // Increases the ref count, the new ref is owned by "owner" which must not
+ // already own a ref (and should not itself be a refcounted object if the ref
+ // could possibly be circular; see below).
+ // Thread-safe iff "this" is frozen.
+ void Ref(const void *owner) const;
+
+ // Release a ref that was acquired from upb_refcounted_ref() and collects any
+ // objects it can.
+ void Unref(const void *owner) const;
+
+ // Moves an existing ref from "from" to "to", without changing the overall
+ // ref count. DonateRef(foo, NULL, owner) is the same as Ref(foo, owner),
+ // but "to" may not be NULL.
+ void DonateRef(const void *from, const void *to) const;
+
+ // Verifies that a ref to the given object is currently held by the given
+ // owner. Only effective in UPB_DEBUG_REFS builds.
+ void CheckRef(const void *owner) const;
+
+ private:
+ UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted);
+,
+UPB_DEFINE_STRUCT0(upb_refcounted,
+ // A single reference count shared by all objects in the group.
+ uint32_t *group;
+
+ // A singly-linked list of all objects in the group.
+ upb_refcounted *next;
+
+ // Table of function pointers for this type.
+ const struct upb_refcounted_vtbl *vtbl;
+
+ // Maintained only when mutable, this tracks the number of refs (but not
+ // ref2's) to this object. *group should be the sum of all individual_count
+ // in the group.
+ uint32_t individual_count;
+
+ bool is_frozen;
+
+#ifdef UPB_DEBUG_REFS
+ upb_inttable *refs; // Maps owner -> trackedref for incoming refs.
+ upb_inttable *ref2s; // Set of targets for outgoing ref2s.
+#endif
+));
+
+UPB_BEGIN_EXTERN_C // {
+
+// It is better to use tracked refs when possible, for the extra debugging
+// capability. But if this is not possible (because you don't have easy access
+// to a stable pointer value that is associated with the ref), you can pass
+// UPB_UNTRACKED_REF instead.
+extern const void *UPB_UNTRACKED_REF;
+
+// Native C API.
+bool upb_refcounted_isfrozen(const upb_refcounted *r);
+void upb_refcounted_ref(const upb_refcounted *r, const void *owner);
+void upb_refcounted_unref(const upb_refcounted *r, const void *owner);
+void upb_refcounted_donateref(
+ const upb_refcounted *r, const void *from, const void *to);
+void upb_refcounted_checkref(const upb_refcounted *r, const void *owner);
+
+
+// Internal-to-upb Interface ///////////////////////////////////////////////////
+
+typedef void upb_refcounted_visit(const upb_refcounted *r,
+ const upb_refcounted *subobj,
+ void *closure);
+
+struct upb_refcounted_vtbl {
+ // Must visit all subobjects that are currently ref'd via upb_refcounted_ref2.
+ // Must be longjmp()-safe.
+ void (*visit)(const upb_refcounted *r, upb_refcounted_visit *visit, void *c);
+
+ // Must free the object and release all references to other objects.
+ void (*free)(upb_refcounted *r);
+};
+
+// Initializes the refcounted with a single ref for the given owner. Returns
+// false if memory could not be allocated.
+bool upb_refcounted_init(upb_refcounted *r,
+ const struct upb_refcounted_vtbl *vtbl,
+ const void *owner);
+
+// Adds a ref from one refcounted object to another ("from" must not already
+// own a ref). These refs may be circular; cycles will be collected correctly
+// (if conservatively). These refs do not need to be freed in from's free()
+// function.
+void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from);
+
+// Removes a ref that was acquired from upb_refcounted_ref2(), and collects any
+// object it can. This is only necessary when "from" no longer points to "r",
+// and not from from's "free" function.
+void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from);
+
+#define upb_ref2(r, from) \
+ upb_refcounted_ref2((const upb_refcounted*)r, (upb_refcounted*)from)
+#define upb_unref2(r, from) \
+ upb_refcounted_unref2((const upb_refcounted*)r, (upb_refcounted*)from)
+
+// Freezes all mutable object reachable by ref2() refs from the given roots.
+// This will split refcounting groups into precise SCC groups, so that
+// refcounting of frozen objects can be more aggressive. If memory allocation
+// fails, or if more than 2**31 mutable objects are reachable from "roots", or
+// if the maximum depth of the graph exceeds "maxdepth", false is returned and
+// the objects are unchanged.
+//
+// After this operation succeeds, the objects are frozen/const, and may not be
+// used through non-const pointers. In particular, they may not be passed as
+// the second parameter of upb_refcounted_{ref,unref}2(). On the upside, all
+// operations on frozen refcounteds are threadsafe, and objects will be freed
+// at the precise moment that they become unreachable.
+//
+// Caller must own refs on each object in the "roots" list.
+bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
+ int maxdepth);
+
+// Shared by all compiled-in refcounted objects.
+extern uint32_t static_refcount;
+
+UPB_END_EXTERN_C // }
+
+#ifdef UPB_DEBUG_REFS
+#define UPB_REFCOUNT_INIT(refs, ref2s) \
+ {&static_refcount, NULL, NULL, 0, true, refs, ref2s}
+#else
+#define UPB_REFCOUNT_INIT(refs, ref2s) {&static_refcount, NULL, NULL, 0, true}
+#endif
+
+#ifdef __cplusplus
+// C++ Wrappers.
+namespace upb {
+inline bool RefCounted::IsFrozen() const {
+ return upb_refcounted_isfrozen(this);
+}
+inline void RefCounted::Ref(const void *owner) const {
+ upb_refcounted_ref(this, owner);
+}
+inline void RefCounted::Unref(const void *owner) const {
+ upb_refcounted_unref(this, owner);
+}
+inline void RefCounted::DonateRef(const void *from, const void *to) const {
+ upb_refcounted_donateref(this, from, to);
+}
+inline void RefCounted::CheckRef(const void *owner) const {
+ upb_refcounted_checkref(this, owner);
+}
+} // namespace upb
+#endif
+
+#endif // UPB_REFCOUNT_H_
+
+#ifdef __cplusplus
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace upb {
+class Def;
+class EnumDef;
+class FieldDef;
+class MessageDef;
+class OneofDef;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::Def, upb_def);
+UPB_DECLARE_TYPE(upb::EnumDef, upb_enumdef);
+UPB_DECLARE_TYPE(upb::FieldDef, upb_fielddef);
+UPB_DECLARE_TYPE(upb::MessageDef, upb_msgdef);
+UPB_DECLARE_TYPE(upb::OneofDef, upb_oneofdef);
+
+// Maximum field number allowed for FieldDefs. This is an inherent limit of the
+// protobuf wire format.
+#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1)
+
+// The maximum message depth that the type graph can have. This is a resource
+// limit for the C stack since we sometimes need to recursively traverse the
+// graph. Cycles are ok; the traversal will stop when it detects a cycle, but
+// we must hit the cycle before the maximum depth is reached.
+//
+// If having a single static limit is too inflexible, we can add another variant
+// of Def::Freeze that allows specifying this as a parameter.
+#define UPB_MAX_MESSAGE_DEPTH 64
+
+
+/* upb::Def: base class for defs *********************************************/
+
+// All the different kind of defs we support. These correspond 1:1 with
+// declarations in a .proto file.
+typedef enum {
+ UPB_DEF_MSG,
+ UPB_DEF_FIELD,
+ UPB_DEF_ENUM,
+ UPB_DEF_ONEOF,
+ UPB_DEF_SERVICE, // Not yet implemented.
+ UPB_DEF_ANY = -1, // Wildcard for upb_symtab_get*()
+} upb_deftype_t;
+
+// The base class of all defs. Its base is upb::RefCounted (use upb::upcast()
+// to convert).
+UPB_DEFINE_CLASS1(upb::Def, upb::RefCounted,
+ public:
+ typedef upb_deftype_t Type;
+
+ Def* Dup(const void *owner) const;
+
+ // Functionality from upb::RefCounted.
+ bool IsFrozen() const;
+ void Ref(const void* owner) const;
+ void Unref(const void* owner) const;
+ void DonateRef(const void* from, const void* to) const;
+ void CheckRef(const void* owner) const;
+
+ Type def_type() const;
+
+ // "fullname" is the def's fully-qualified name (eg. foo.bar.Message).
+ const char *full_name() const;
+
+ // The def must be mutable. Caller retains ownership of fullname. Defs are
+ // not required to have a name; if a def has no name when it is frozen, it
+ // will remain an anonymous def. On failure, returns false and details in "s"
+ // if non-NULL.
+ bool set_full_name(const char* fullname, upb::Status* s);
+ bool set_full_name(const std::string &fullname, upb::Status* s);
+
+ // Freezes the given defs; this validates all constraints and marks the defs
+ // as frozen (read-only). "defs" may not contain any fielddefs, but fields
+ // of any msgdefs will be frozen.
+ //
+ // Symbolic references to sub-types and enum defaults must have already been
+ // resolved. Any mutable defs reachable from any of "defs" must also be in
+ // the list; more formally, "defs" must be a transitive closure of mutable
+ // defs.
+ //
+ // After this operation succeeds, the finalized defs must only be accessed
+ // through a const pointer!
+ static bool Freeze(Def* const* defs, int n, Status* status);
+ static bool Freeze(const std::vector<Def*>& defs, Status* status);
+
+ private:
+ UPB_DISALLOW_POD_OPS(Def, upb::Def);
+,
+UPB_DEFINE_STRUCT(upb_def, upb_refcounted,
+ const char *fullname;
+ upb_deftype_t type : 8;
+ // Used as a flag during the def's mutable stage. Must be false unless
+ // it is currently being used by a function on the stack. This allows
+ // us to easily determine which defs were passed into the function's
+ // current invocation.
+ bool came_from_user;
+));
+
+#define UPB_DEF_INIT(name, type, refs, ref2s) \
+ { UPB_REFCOUNT_INIT(refs, ref2s), name, type, false }
+
+UPB_BEGIN_EXTERN_C // {
+
+// Native C API.
+upb_def *upb_def_dup(const upb_def *def, const void *owner);
+
+// From upb_refcounted.
+bool upb_def_isfrozen(const upb_def *def);
+void upb_def_ref(const upb_def *def, const void *owner);
+void upb_def_unref(const upb_def *def, const void *owner);
+void upb_def_donateref(const upb_def *def, const void *from, const void *to);
+void upb_def_checkref(const upb_def *def, const void *owner);
+
+upb_deftype_t upb_def_type(const upb_def *d);
+const char *upb_def_fullname(const upb_def *d);
+bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s);
+bool upb_def_freeze(upb_def *const *defs, int n, upb_status *s);
+
+UPB_END_EXTERN_C // }
+
+
+/* upb::Def casts *************************************************************/
+
+#ifdef __cplusplus
+#define UPB_CPP_CASTS(cname, cpptype) \
+ namespace upb { \
+ template <> \
+ inline cpptype *down_cast<cpptype *, Def>(Def * def) { \
+ return upb_downcast_##cname##_mutable(def); \
+ } \
+ template <> \
+ inline cpptype *dyn_cast<cpptype *, Def>(Def * def) { \
+ return upb_dyncast_##cname##_mutable(def); \
+ } \
+ template <> \
+ inline const cpptype *down_cast<const cpptype *, const Def>( \
+ const Def *def) { \
+ return upb_downcast_##cname(def); \
+ } \
+ template <> \
+ inline const cpptype *dyn_cast<const cpptype *, const Def>(const Def *def) { \
+ return upb_dyncast_##cname(def); \
+ } \
+ template <> \
+ inline const cpptype *down_cast<const cpptype *, Def>(Def * def) { \
+ return upb_downcast_##cname(def); \
+ } \
+ template <> \
+ inline const cpptype *dyn_cast<const cpptype *, Def>(Def * def) { \
+ return upb_dyncast_##cname(def); \
+ } \
+ } // namespace upb
+#else
+#define UPB_CPP_CASTS(cname, cpptype)
+#endif
+
+// Dynamic casts, for determining if a def is of a particular type at runtime.
+// Downcasts, for when some wants to assert that a def is of a particular type.
+// These are only checked if we are building debug.
+#define UPB_DEF_CASTS(lower, upper, cpptype) \
+ UPB_INLINE const upb_##lower *upb_dyncast_##lower(const upb_def *def) { \
+ if (upb_def_type(def) != UPB_DEF_##upper) return NULL; \
+ return (upb_##lower *)def; \
+ } \
+ UPB_INLINE const upb_##lower *upb_downcast_##lower(const upb_def *def) { \
+ assert(upb_def_type(def) == UPB_DEF_##upper); \
+ return (const upb_##lower *)def; \
+ } \
+ UPB_INLINE upb_##lower *upb_dyncast_##lower##_mutable(upb_def *def) { \
+ return (upb_##lower *)upb_dyncast_##lower(def); \
+ } \
+ UPB_INLINE upb_##lower *upb_downcast_##lower##_mutable(upb_def *def) { \
+ return (upb_##lower *)upb_downcast_##lower(def); \
+ } \
+ UPB_CPP_CASTS(lower, cpptype)
+
+#define UPB_DEFINE_DEF(cppname, lower, upper, cppmethods, members) \
+ UPB_DEFINE_CLASS2(cppname, upb::Def, upb::RefCounted, UPB_QUOTE(cppmethods), \
+ members) \
+ UPB_DEF_CASTS(lower, upper, cppname)
+
+
+/* upb::FieldDef **************************************************************/
+
+// The types a field can have. Note that this list is not identical to the
+// types defined in descriptor.proto, which gives INT32 and SINT32 separate
+// types (we distinguish the two with the "integer encoding" enum below).
+typedef enum {
+ UPB_TYPE_FLOAT = 1,
+ UPB_TYPE_DOUBLE = 2,
+ UPB_TYPE_BOOL = 3,
+ UPB_TYPE_STRING = 4,
+ UPB_TYPE_BYTES = 5,
+ UPB_TYPE_MESSAGE = 6,
+ UPB_TYPE_ENUM = 7, // Enum values are int32.
+ UPB_TYPE_INT32 = 8,
+ UPB_TYPE_UINT32 = 9,
+ UPB_TYPE_INT64 = 10,
+ UPB_TYPE_UINT64 = 11,
+} upb_fieldtype_t;
+
+// The repeated-ness of each field; this matches descriptor.proto.
+typedef enum {
+ UPB_LABEL_OPTIONAL = 1,
+ UPB_LABEL_REQUIRED = 2,
+ UPB_LABEL_REPEATED = 3,
+} upb_label_t;
+
+// How integers should be encoded in serializations that offer multiple
+// integer encoding methods.
+typedef enum {
+ UPB_INTFMT_VARIABLE = 1,
+ UPB_INTFMT_FIXED = 2,
+ UPB_INTFMT_ZIGZAG = 3, // Only for signed types (INT32/INT64).
+} upb_intfmt_t;
+
+// Descriptor types, as defined in descriptor.proto.
+typedef enum {
+ UPB_DESCRIPTOR_TYPE_DOUBLE = 1,
+ UPB_DESCRIPTOR_TYPE_FLOAT = 2,
+ UPB_DESCRIPTOR_TYPE_INT64 = 3,
+ UPB_DESCRIPTOR_TYPE_UINT64 = 4,
+ UPB_DESCRIPTOR_TYPE_INT32 = 5,
+ UPB_DESCRIPTOR_TYPE_FIXED64 = 6,
+ UPB_DESCRIPTOR_TYPE_FIXED32 = 7,
+ UPB_DESCRIPTOR_TYPE_BOOL = 8,
+ UPB_DESCRIPTOR_TYPE_STRING = 9,
+ UPB_DESCRIPTOR_TYPE_GROUP = 10,
+ UPB_DESCRIPTOR_TYPE_MESSAGE = 11,
+ UPB_DESCRIPTOR_TYPE_BYTES = 12,
+ UPB_DESCRIPTOR_TYPE_UINT32 = 13,
+ UPB_DESCRIPTOR_TYPE_ENUM = 14,
+ UPB_DESCRIPTOR_TYPE_SFIXED32 = 15,
+ UPB_DESCRIPTOR_TYPE_SFIXED64 = 16,
+ UPB_DESCRIPTOR_TYPE_SINT32 = 17,
+ UPB_DESCRIPTOR_TYPE_SINT64 = 18,
+} upb_descriptortype_t;
+
+
+// A upb_fielddef describes a single field in a message. It is most often
+// found as a part of a upb_msgdef, but can also stand alone to represent
+// an extension.
+//
+// Its base class is upb::Def (use upb::upcast() to convert).
+UPB_DEFINE_DEF(upb::FieldDef, fielddef, FIELD,
+ public:
+ typedef upb_fieldtype_t Type;
+ typedef upb_label_t Label;
+ typedef upb_intfmt_t IntegerFormat;
+ typedef upb_descriptortype_t DescriptorType;
+
+ // These return true if the given value is a valid member of the enumeration.
+ static bool CheckType(int32_t val);
+ static bool CheckLabel(int32_t val);
+ static bool CheckDescriptorType(int32_t val);
+ static bool CheckIntegerFormat(int32_t val);
+
+ // These convert to the given enumeration; they require that the value is
+ // valid.
+ static Type ConvertType(int32_t val);
+ static Label ConvertLabel(int32_t val);
+ static DescriptorType ConvertDescriptorType(int32_t val);
+ static IntegerFormat ConvertIntegerFormat(int32_t val);
+
+ // Returns NULL if memory allocation failed.
+ static reffed_ptr<FieldDef> New();
+
+ // Duplicates the given field, returning NULL if memory allocation failed.
+ // When a fielddef is duplicated, the subdef (if any) is made symbolic if it
+ // wasn't already. If the subdef is set but has no name (which is possible
+ // since msgdefs are not required to have a name) the new fielddef's subdef
+ // will be unset.
+ FieldDef* Dup(const void* owner) const;
+
+ // Functionality from upb::RefCounted.
+ bool IsFrozen() const;
+ void Ref(const void* owner) const;
+ void Unref(const void* owner) const;
+ void DonateRef(const void* from, const void* to) const;
+ void CheckRef(const void* owner) const;
+
+ // Functionality from upb::Def.
+ const char* full_name() const;
+
+ bool type_is_set() const; // Whether set_[descriptor_]type() has been called.
+ Type type() const; // Requires that type_is_set() == true.
+ Label label() const; // Defaults to UPB_LABEL_OPTIONAL.
+ const char* name() const; // NULL if uninitialized.
+ uint32_t number() const; // Returns 0 if uninitialized.
+ bool is_extension() const;
+
+ // For UPB_TYPE_MESSAGE fields only where is_tag_delimited() == false,
+ // indicates whether this field should have lazy parsing handlers that yield
+ // the unparsed string for the submessage.
+ //
+ // TODO(haberman): I think we want to move this into a FieldOptions container
+ // when we add support for custom options (the FieldOptions struct will
+ // contain both regular FieldOptions like "lazy" *and* custom options).
+ bool lazy() const;
+
+ // For non-string, non-submessage fields, this indicates whether binary
+ // protobufs are encoded in packed or non-packed format.
+ //
+ // TODO(haberman): see note above about putting options like this into a
+ // FieldOptions container.
+ bool packed() const;
+
+ // An integer that can be used as an index into an array of fields for
+ // whatever message this field belongs to. Guaranteed to be less than
+ // f->containing_type()->field_count(). May only be accessed once the def has
+ // been finalized.
+ int index() const;
+
+ // The MessageDef to which this field belongs.
+ //
+ // If this field has been added to a MessageDef, that message can be retrieved
+ // directly (this is always the case for frozen FieldDefs).
+ //
+ // If the field has not yet been added to a MessageDef, you can set the name
+ // of the containing type symbolically instead. This is mostly useful for
+ // extensions, where the extension is declared separately from the message.
+ const MessageDef* containing_type() const;
+ const char* containing_type_name();
+
+ // The OneofDef to which this field belongs, or NULL if this field is not part
+ // of a oneof.
+ const OneofDef* containing_oneof() const;
+
+ // The field's type according to the enum in descriptor.proto. This is not
+ // the same as UPB_TYPE_*, because it distinguishes between (for example)
+ // INT32 and SINT32, whereas our "type" enum does not. This return of
+ // descriptor_type() is a function of type(), integer_format(), and
+ // is_tag_delimited(). Likewise set_descriptor_type() sets all three
+ // appropriately.
+ DescriptorType descriptor_type() const;
+
+ // Convenient field type tests.
+ bool IsSubMessage() const;
+ bool IsString() const;
+ bool IsSequence() const;
+ bool IsPrimitive() const;
+ bool IsMap() const;
+
+ // How integers are encoded. Only meaningful for integer types.
+ // Defaults to UPB_INTFMT_VARIABLE, and is reset when "type" changes.
+ IntegerFormat integer_format() const;
+
+ // Whether a submessage field is tag-delimited or not (if false, then
+ // length-delimited). May only be set when type() == UPB_TYPE_MESSAGE.
+ bool is_tag_delimited() const;
+
+ // Returns the non-string default value for this fielddef, which may either
+ // be something the client set explicitly or the "default default" (0 for
+ // numbers, empty for strings). The field's type indicates the type of the
+ // returned value, except for enum fields that are still mutable.
+ //
+ // Requires that the given function matches the field's current type.
+ int64_t default_int64() const;
+ int32_t default_int32() const;
+ uint64_t default_uint64() const;
+ uint32_t default_uint32() const;
+ bool default_bool() const;
+ float default_float() const;
+ double default_double() const;
+
+ // The resulting string is always NULL-terminated. If non-NULL, the length
+ // will be stored in *len.
+ const char *default_string(size_t* len) const;
+
+ // For frozen UPB_TYPE_ENUM fields, enum defaults can always be read as either
+ // string or int32, and both of these methods will always return true.
+ //
+ // For mutable UPB_TYPE_ENUM fields, the story is a bit more complicated.
+ // Enum defaults are unusual. They can be specified either as string or int32,
+ // but to be valid the enum must have that value as a member. And if no
+ // default is specified, the "default default" comes from the EnumDef.
+ //
+ // We allow reading the default as either an int32 or a string, but only if
+ // we have a meaningful value to report. We have a meaningful value if it was
+ // set explicitly, or if we could get the "default default" from the EnumDef.
+ // Also if you explicitly set the name and we find the number in the EnumDef
+ bool EnumHasStringDefault() const;
+ bool EnumHasInt32Default() const;
+
+ // Submessage and enum fields must reference a "subdef", which is the
+ // upb::MessageDef or upb::EnumDef that defines their type. Note that when
+ // the FieldDef is mutable it may not have a subdef *yet*, but this function
+ // still returns true to indicate that the field's type requires a subdef.
+ bool HasSubDef() const;
+
+ // Returns the enum or submessage def for this field, if any. The field's
+ // type must match (ie. you may only call enum_subdef() for fields where
+ // type() == UPB_TYPE_ENUM). Returns NULL if the subdef has not been set or
+ // is currently set symbolically.
+ const EnumDef* enum_subdef() const;
+ const MessageDef* message_subdef() const;
+
+ // Returns the generic subdef for this field. Requires that HasSubDef() (ie.
+ // only works for UPB_TYPE_ENUM and UPB_TYPE_MESSAGE fields).
+ const Def* subdef() const;
+
+ // Returns the symbolic name of the subdef. If the subdef is currently set
+ // unresolved (ie. set symbolically) returns the symbolic name. If it has
+ // been resolved to a specific subdef, returns the name from that subdef.
+ const char* subdef_name() const;
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Setters (non-const methods), only valid for mutable FieldDefs!
+ //////////////////////////////////////////////////////////////////////////////
+
+ bool set_full_name(const char* fullname, upb::Status* s);
+ bool set_full_name(const std::string& fullname, upb::Status* s);
+
+ // This may only be called if containing_type() == NULL (ie. the field has not
+ // been added to a message yet).
+ bool set_containing_type_name(const char *name, Status* status);
+ bool set_containing_type_name(const std::string& name, Status* status);
+
+ // Defaults to false. When we freeze, we ensure that this can only be true
+ // for length-delimited message fields. Prior to freezing this can be true or
+ // false with no restrictions.
+ void set_lazy(bool lazy);
+
+ // Defaults to true. Sets whether this field is encoded in packed format.
+ void set_packed(bool packed);
+
+ // "type" or "descriptor_type" MUST be set explicitly before the fielddef is
+ // finalized. These setters require that the enum value is valid; if the
+ // value did not come directly from an enum constant, the caller should
+ // validate it first with the functions above (CheckFieldType(), etc).
+ void set_type(Type type);
+ void set_label(Label label);
+ void set_descriptor_type(DescriptorType type);
+ void set_is_extension(bool is_extension);
+
+ // "number" and "name" must be set before the FieldDef is added to a
+ // MessageDef, and may not be set after that.
+ //
+ // "name" is the same as full_name()/set_full_name(), but since fielddefs
+ // most often use simple, non-qualified names, we provide this accessor
+ // also. Generally only extensions will want to think of this name as
+ // fully-qualified.
+ bool set_number(uint32_t number, upb::Status* s);
+ bool set_name(const char* name, upb::Status* s);
+ bool set_name(const std::string& name, upb::Status* s);
+
+ void set_integer_format(IntegerFormat format);
+ bool set_tag_delimited(bool tag_delimited, upb::Status* s);
+
+ // Sets default value for the field. The call must exactly match the type
+ // of the field. Enum fields may use either setint32 or setstring to set
+ // the default numerically or symbolically, respectively, but symbolic
+ // defaults must be resolved before finalizing (see ResolveEnumDefault()).
+ //
+ // Changing the type of a field will reset its default.
+ void set_default_int64(int64_t val);
+ void set_default_int32(int32_t val);
+ void set_default_uint64(uint64_t val);
+ void set_default_uint32(uint32_t val);
+ void set_default_bool(bool val);
+ void set_default_float(float val);
+ void set_default_double(double val);
+ bool set_default_string(const void *str, size_t len, Status *s);
+ bool set_default_string(const std::string &str, Status *s);
+ void set_default_cstr(const char *str, Status *s);
+
+ // Before a fielddef is frozen, its subdef may be set either directly (with a
+ // upb::Def*) or symbolically. Symbolic refs must be resolved before the
+ // containing msgdef can be frozen (see upb_resolve() above). upb always
+ // guarantees that any def reachable from a live def will also be kept alive.
+ //
+ // Both methods require that upb_hassubdef(f) (so the type must be set prior
+ // to calling these methods). Returns false if this is not the case, or if
+ // the given subdef is not of the correct type. The subdef is reset if the
+ // field's type is changed. The subdef can be set to NULL to clear it.
+ bool set_subdef(const Def* subdef, Status* s);
+ bool set_enum_subdef(const EnumDef* subdef, Status* s);
+ bool set_message_subdef(const MessageDef* subdef, Status* s);
+ bool set_subdef_name(const char* name, Status* s);
+ bool set_subdef_name(const std::string &name, Status* s);
+
+ private:
+ UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef);
+,
+UPB_DEFINE_STRUCT(upb_fielddef, upb_def,
+ union {
+ int64_t sint;
+ uint64_t uint;
+ double dbl;
+ float flt;
+ void *bytes;
+ } defaultval;
+ union {
+ const upb_msgdef *def; // If !msg_is_symbolic.
+ char *name; // If msg_is_symbolic.
+ } msg;
+ union {
+ const upb_def *def; // If !subdef_is_symbolic.
+ char *name; // If subdef_is_symbolic.
+ } sub; // The msgdef or enumdef for this field, if upb_hassubdef(f).
+ bool subdef_is_symbolic;
+ bool msg_is_symbolic;
+ const upb_oneofdef *oneof;
+ bool default_is_string;
+ bool type_is_set_; // False until type is explicitly set.
+ bool is_extension_;
+ bool lazy_;
+ bool packed_;
+ upb_intfmt_t intfmt;
+ bool tagdelim;
+ upb_fieldtype_t type_;
+ upb_label_t label_;
+ uint32_t number_;
+ uint32_t selector_base; // Used to index into a upb::Handlers table.
+ uint32_t index_;
+));
+
+#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, lazy, \
+ packed, name, num, msgdef, subdef, selector_base, \
+ index, defaultval, refs, ref2s) \
+ { \
+ UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, {msgdef}, \
+ {subdef}, NULL, false, false, \
+ type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \
+ lazy, packed, intfmt, tagdelim, type, label, num, selector_base, index \
+ }
+
+UPB_BEGIN_EXTERN_C // {
+
+// Native C API.
+upb_fielddef *upb_fielddef_new(const void *owner);
+upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner);
+
+// From upb_refcounted.
+bool upb_fielddef_isfrozen(const upb_fielddef *f);
+void upb_fielddef_ref(const upb_fielddef *f, const void *owner);
+void upb_fielddef_unref(const upb_fielddef *f, const void *owner);
+void upb_fielddef_donateref(const upb_fielddef *f, const void *from,
+ const void *to);
+void upb_fielddef_checkref(const upb_fielddef *f, const void *owner);
+
+// From upb_def.
+const char *upb_fielddef_fullname(const upb_fielddef *f);
+bool upb_fielddef_setfullname(upb_fielddef *f, const char *fullname,
+ upb_status *s);
+
+bool upb_fielddef_typeisset(const upb_fielddef *f);
+upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f);
+upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f);
+upb_label_t upb_fielddef_label(const upb_fielddef *f);
+uint32_t upb_fielddef_number(const upb_fielddef *f);
+const char *upb_fielddef_name(const upb_fielddef *f);
+bool upb_fielddef_isextension(const upb_fielddef *f);
+bool upb_fielddef_lazy(const upb_fielddef *f);
+bool upb_fielddef_packed(const upb_fielddef *f);
+const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f);
+const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f);
+upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f);
+const char *upb_fielddef_containingtypename(upb_fielddef *f);
+upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f);
+uint32_t upb_fielddef_index(const upb_fielddef *f);
+bool upb_fielddef_istagdelim(const upb_fielddef *f);
+bool upb_fielddef_issubmsg(const upb_fielddef *f);
+bool upb_fielddef_isstring(const upb_fielddef *f);
+bool upb_fielddef_isseq(const upb_fielddef *f);
+bool upb_fielddef_isprimitive(const upb_fielddef *f);
+bool upb_fielddef_ismap(const upb_fielddef *f);
+int64_t upb_fielddef_defaultint64(const upb_fielddef *f);
+int32_t upb_fielddef_defaultint32(const upb_fielddef *f);
+uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f);
+uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f);
+bool upb_fielddef_defaultbool(const upb_fielddef *f);
+float upb_fielddef_defaultfloat(const upb_fielddef *f);
+double upb_fielddef_defaultdouble(const upb_fielddef *f);
+const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len);
+bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f);
+bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f);
+bool upb_fielddef_hassubdef(const upb_fielddef *f);
+const upb_def *upb_fielddef_subdef(const upb_fielddef *f);
+const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f);
+const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f);
+const char *upb_fielddef_subdefname(const upb_fielddef *f);
+
+void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type);
+void upb_fielddef_setdescriptortype(upb_fielddef *f, int type);
+void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label);
+bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s);
+bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s);
+bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name,
+ upb_status *s);
+void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension);
+void upb_fielddef_setlazy(upb_fielddef *f, bool lazy);
+void upb_fielddef_setpacked(upb_fielddef *f, bool packed);
+void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt);
+void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim);
+void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t val);
+void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t val);
+void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t val);
+void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t val);
+void upb_fielddef_setdefaultbool(upb_fielddef *f, bool val);
+void upb_fielddef_setdefaultfloat(upb_fielddef *f, float val);
+void upb_fielddef_setdefaultdouble(upb_fielddef *f, double val);
+bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len,
+ upb_status *s);
+void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str,
+ upb_status *s);
+bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef,
+ upb_status *s);
+bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef,
+ upb_status *s);
+bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef,
+ upb_status *s);
+bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
+ upb_status *s);
+
+bool upb_fielddef_checklabel(int32_t label);
+bool upb_fielddef_checktype(int32_t type);
+bool upb_fielddef_checkdescriptortype(int32_t type);
+bool upb_fielddef_checkintfmt(int32_t fmt);
+
+UPB_END_EXTERN_C // }
+
+
+/* upb::MessageDef ************************************************************/
+
+typedef upb_inttable_iter upb_msg_field_iter;
+typedef upb_strtable_iter upb_msg_oneof_iter;
+
+// Structure that describes a single .proto message type.
+//
+// Its base class is upb::Def (use upb::upcast() to convert).
+UPB_DEFINE_DEF(upb::MessageDef, msgdef, MSG, UPB_QUOTE(
+ public:
+ // Returns NULL if memory allocation failed.
+ static reffed_ptr<MessageDef> New();
+
+ // Functionality from upb::RefCounted.
+ bool IsFrozen() const;
+ void Ref(const void* owner) const;
+ void Unref(const void* owner) const;
+ void DonateRef(const void* from, const void* to) const;
+ void CheckRef(const void* owner) const;
+
+ // Functionality from upb::Def.
+ const char* full_name() const;
+ bool set_full_name(const char* fullname, Status* s);
+ bool set_full_name(const std::string& fullname, Status* s);
+
+ // Call to freeze this MessageDef.
+ // WARNING: this will fail if this message has any unfrozen submessages!
+ // Messages with cycles must be frozen as a batch using upb::Def::Freeze().
+ bool Freeze(Status* s);
+
+ // The number of fields that belong to the MessageDef.
+ int field_count() const;
+
+ // The number of oneofs that belong to the MessageDef.
+ int oneof_count() const;
+
+ // Adds a field (upb_fielddef object) to a msgdef. Requires that the msgdef
+ // and the fielddefs are mutable. The fielddef's name and number must be
+ // set, and the message may not already contain any field with this name or
+ // number, and this fielddef may not be part of another message. In error
+ // cases false is returned and the msgdef is unchanged.
+ //
+ // If the given field is part of a oneof, this call succeeds if and only if
+ // that oneof is already part of this msgdef. (Note that adding a oneof to a
+ // msgdef automatically adds all of its fields to the msgdef at the time that
+ // the oneof is added, so it is usually more idiomatic to add the oneof's
+ // fields first then add the oneof to the msgdef. This case is supported for
+ // convenience.)
+ //
+ // If |f| is already part of this MessageDef, this method performs no action
+ // and returns true (success). Thus, this method is idempotent.
+ bool AddField(FieldDef* f, Status* s);
+ bool AddField(const reffed_ptr<FieldDef>& f, Status* s);
+
+ // Adds a oneof (upb_oneofdef object) to a msgdef. Requires that the msgdef,
+ // oneof, and any fielddefs are mutable, that the fielddefs contained in the
+ // oneof do not have any name or number conflicts with existing fields in the
+ // msgdef, and that the oneof's name is unique among all oneofs in the msgdef.
+ // If the oneof is added successfully, all of its fields will be added
+ // directly to the msgdef as well. In error cases, false is returned and the
+ // msgdef is unchanged.
+ bool AddOneof(OneofDef* o, Status* s);
+ bool AddOneof(const reffed_ptr<OneofDef>& o, Status* s);
+
+ // These return NULL if the field is not found.
+ FieldDef* FindFieldByNumber(uint32_t number);
+ FieldDef* FindFieldByName(const char *name, size_t len);
+ const FieldDef* FindFieldByNumber(uint32_t number) const;
+ const FieldDef* FindFieldByName(const char* name, size_t len) const;
+
+
+ FieldDef* FindFieldByName(const char *name) {
+ return FindFieldByName(name, strlen(name));
+ }
+ const FieldDef* FindFieldByName(const char *name) const {
+ return FindFieldByName(name, strlen(name));
+ }
+
+ template <class T>
+ FieldDef* FindFieldByName(const T& str) {
+ return FindFieldByName(str.c_str(), str.size());
+ }
+ template <class T>
+ const FieldDef* FindFieldByName(const T& str) const {
+ return FindFieldByName(str.c_str(), str.size());
+ }
+
+ OneofDef* FindOneofByName(const char* name, size_t len);
+ const OneofDef* FindOneofByName(const char* name, size_t len) const;
+
+ OneofDef* FindOneofByName(const char* name) {
+ return FindOneofByName(name, strlen(name));
+ }
+ const OneofDef* FindOneofByName(const char* name) const {
+ return FindOneofByName(name, strlen(name));
+ }
+
+ template<class T>
+ OneofDef* FindOneofByName(const T& str) {
+ return FindOneofByName(str.c_str(), str.size());
+ }
+ template<class T>
+ const OneofDef* FindOneofByName(const T& str) const {
+ return FindOneofByName(str.c_str(), str.size());
+ }
+
+ // Returns a new msgdef that is a copy of the given msgdef (and a copy of all
+ // the fields) but with any references to submessages broken and replaced
+ // with just the name of the submessage. Returns NULL if memory allocation
+ // failed.
+ //
+ // TODO(haberman): which is more useful, keeping fields resolved or
+ // unresolving them? If there's no obvious answer, Should this functionality
+ // just be moved into symtab.c?
+ MessageDef* Dup(const void* owner) const;
+
+ // Is this message a map entry?
+ void setmapentry(bool map_entry);
+ bool mapentry() const;
+
+ // Iteration over fields. The order is undefined.
+ class field_iterator
+ : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+ public:
+ explicit field_iterator(MessageDef* md);
+ static field_iterator end(MessageDef* md);
+
+ void operator++();
+ FieldDef* operator*() const;
+ bool operator!=(const field_iterator& other) const;
+ bool operator==(const field_iterator& other) const;
+
+ private:
+ upb_msg_field_iter iter_;
+ };
+
+ class const_field_iterator
+ : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+ public:
+ explicit const_field_iterator(const MessageDef* md);
+ static const_field_iterator end(const MessageDef* md);
+
+ void operator++();
+ const FieldDef* operator*() const;
+ bool operator!=(const const_field_iterator& other) const;
+ bool operator==(const const_field_iterator& other) const;
+
+ private:
+ upb_msg_field_iter iter_;
+ };
+
+ // Iteration over oneofs. The order is undefined.
+ class oneof_iterator
+ : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+ public:
+ explicit oneof_iterator(MessageDef* md);
+ static oneof_iterator end(MessageDef* md);
+
+ void operator++();
+ OneofDef* operator*() const;
+ bool operator!=(const oneof_iterator& other) const;
+ bool operator==(const oneof_iterator& other) const;
+
+ private:
+ upb_msg_oneof_iter iter_;
+ };
+
+ class const_oneof_iterator
+ : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+ public:
+ explicit const_oneof_iterator(const MessageDef* md);
+ static const_oneof_iterator end(const MessageDef* md);
+
+ void operator++();
+ const OneofDef* operator*() const;
+ bool operator!=(const const_oneof_iterator& other) const;
+ bool operator==(const const_oneof_iterator& other) const;
+
+ private:
+ upb_msg_oneof_iter iter_;
+ };
+
+ class FieldAccessor {
+ public:
+ explicit FieldAccessor(MessageDef* msg) : msg_(msg) {}
+ field_iterator begin() { return msg_->field_begin(); }
+ field_iterator end() { return msg_->field_end(); }
+ private:
+ MessageDef* msg_;
+ };
+
+ class ConstFieldAccessor {
+ public:
+ explicit ConstFieldAccessor(const MessageDef* msg) : msg_(msg) {}
+ const_field_iterator begin() { return msg_->field_begin(); }
+ const_field_iterator end() { return msg_->field_end(); }
+ private:
+ const MessageDef* msg_;
+ };
+
+ class OneofAccessor {
+ public:
+ explicit OneofAccessor(MessageDef* msg) : msg_(msg) {}
+ oneof_iterator begin() { return msg_->oneof_begin(); }
+ oneof_iterator end() { return msg_->oneof_end(); }
+ private:
+ MessageDef* msg_;
+ };
+
+ class ConstOneofAccessor {
+ public:
+ explicit ConstOneofAccessor(const MessageDef* msg) : msg_(msg) {}
+ const_oneof_iterator begin() { return msg_->oneof_begin(); }
+ const_oneof_iterator end() { return msg_->oneof_end(); }
+ private:
+ const MessageDef* msg_;
+ };
+
+ field_iterator field_begin();
+ field_iterator field_end();
+ const_field_iterator field_begin() const;
+ const_field_iterator field_end() const;
+
+ oneof_iterator oneof_begin();
+ oneof_iterator oneof_end();
+ const_oneof_iterator oneof_begin() const;
+ const_oneof_iterator oneof_end() const;
+
+ FieldAccessor fields() { return FieldAccessor(this); }
+ ConstFieldAccessor fields() const { return ConstFieldAccessor(this); }
+ OneofAccessor oneofs() { return OneofAccessor(this); }
+ ConstOneofAccessor oneofs() const { return ConstOneofAccessor(this); }
+
+ private:
+ UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef);
+),
+UPB_DEFINE_STRUCT(upb_msgdef, upb_def,
+ size_t selector_count;
+ uint32_t submsg_field_count;
+
+ // Tables for looking up fields by number and name.
+ upb_inttable itof; // int to field
+ upb_strtable ntof; // name to field
+
+ // Tables for looking up oneofs by name.
+ upb_strtable ntoo; // name to oneof
+
+ // Is this a map-entry message?
+ // TODO: set this flag properly for static descriptors; regenerate
+ // descriptor.upb.c.
+ bool map_entry;
+
+ // TODO(haberman): proper extension ranges (there can be multiple).
+));
+
+// TODO: also support static initialization of the oneofs table. This will be
+// needed if we compile in descriptors that contain oneofs.
+#define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \
+ refs, ref2s) \
+ { \
+ UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, \
+ submsg_field_count, itof, ntof, \
+ UPB_EMPTY_STRTABLE_INIT(UPB_CTYPE_PTR), false \
+ }
+
+UPB_BEGIN_EXTERN_C // {
+
+// Returns NULL if memory allocation failed.
+upb_msgdef *upb_msgdef_new(const void *owner);
+
+// From upb_refcounted.
+bool upb_msgdef_isfrozen(const upb_msgdef *m);
+void upb_msgdef_ref(const upb_msgdef *m, const void *owner);
+void upb_msgdef_unref(const upb_msgdef *m, const void *owner);
+void upb_msgdef_donateref(const upb_msgdef *m, const void *from,
+ const void *to);
+void upb_msgdef_checkref(const upb_msgdef *m, const void *owner);
+bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status);
+
+// From upb_def.
+const char *upb_msgdef_fullname(const upb_msgdef *m);
+bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s);
+
+upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner);
+bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
+ upb_status *s);
+bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
+ upb_status *s);
+
+// Field lookup in a couple of different variations:
+// - itof = int to field
+// - ntof = name to field
+// - ntofz = name to field, null-terminated string.
+const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i);
+const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
+ size_t len);
+int upb_msgdef_numfields(const upb_msgdef *m);
+
+UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m,
+ const char *name) {
+ return upb_msgdef_ntof(m, name, strlen(name));
+}
+
+UPB_INLINE upb_fielddef *upb_msgdef_itof_mutable(upb_msgdef *m, uint32_t i) {
+ return (upb_fielddef*)upb_msgdef_itof(m, i);
+}
+
+UPB_INLINE upb_fielddef *upb_msgdef_ntof_mutable(upb_msgdef *m,
+ const char *name, size_t len) {
+ return (upb_fielddef *)upb_msgdef_ntof(m, name, len);
+}
+
+// Oneof lookup:
+// - ntoo = name to oneof
+// - ntooz = name to oneof, null-terminated string.
+const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
+ size_t len);
+int upb_msgdef_numoneofs(const upb_msgdef *m);
+
+UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m,
+ const char *name) {
+ return upb_msgdef_ntoo(m, name, strlen(name));
+}
+
+UPB_INLINE upb_oneofdef *upb_msgdef_ntoo_mutable(upb_msgdef *m,
+ const char *name, size_t len) {
+ return (upb_oneofdef *)upb_msgdef_ntoo(m, name, len);
+}
+
+void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry);
+bool upb_msgdef_mapentry(const upb_msgdef *m);
+
+// Well-known field tag numbers for map-entry messages.
+#define UPB_MAPENTRY_KEY 1
+#define UPB_MAPENTRY_VALUE 2
+
+const upb_oneofdef *upb_msgdef_findoneof(const upb_msgdef *m,
+ const char *name);
+int upb_msgdef_numoneofs(const upb_msgdef *m);
+
+// upb_msg_field_iter i;
+// for(upb_msg_field_begin(&i, m);
+// !upb_msg_field_done(&i);
+// upb_msg_field_next(&i)) {
+// upb_fielddef *f = upb_msg_iter_field(&i);
+// // ...
+// }
+//
+// For C we don't have separate iterators for const and non-const.
+// It is the caller's responsibility to cast the upb_fielddef* to
+// const if the upb_msgdef* is const.
+void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m);
+void upb_msg_field_next(upb_msg_field_iter *iter);
+bool upb_msg_field_done(const upb_msg_field_iter *iter);
+upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter);
+void upb_msg_field_iter_setdone(upb_msg_field_iter *iter);
+
+// Similar to above, we also support iterating through the oneofs in a msgdef.
+void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m);
+void upb_msg_oneof_next(upb_msg_oneof_iter *iter);
+bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter);
+upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter);
+void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter);
+
+UPB_END_EXTERN_C // }
+
+
+/* upb::EnumDef ***************************************************************/
+
+typedef upb_strtable_iter upb_enum_iter;
+
+// Class that represents an enum. Its base class is upb::Def (convert with
+// upb::upcast()).
+UPB_DEFINE_DEF(upb::EnumDef, enumdef, ENUM,
+ public:
+ // Returns NULL if memory allocation failed.
+ static reffed_ptr<EnumDef> New();
+
+ // Functionality from upb::RefCounted.
+ bool IsFrozen() const;
+ void Ref(const void* owner) const;
+ void Unref(const void* owner) const;
+ void DonateRef(const void* from, const void* to) const;
+ void CheckRef(const void* owner) const;
+
+ // Functionality from upb::Def.
+ const char* full_name() const;
+ bool set_full_name(const char* fullname, Status* s);
+ bool set_full_name(const std::string& fullname, Status* s);
+
+ // Call to freeze this EnumDef.
+ bool Freeze(Status* s);
+
+ // The value that is used as the default when no field default is specified.
+ // If not set explicitly, the first value that was added will be used.
+ // The default value must be a member of the enum.
+ // Requires that value_count() > 0.
+ int32_t default_value() const;
+
+ // Sets the default value. If this value is not valid, returns false and an
+ // error message in status.
+ bool set_default_value(int32_t val, Status* status);
+
+ // Returns the number of values currently defined in the enum. Note that
+ // multiple names can refer to the same number, so this may be greater than
+ // the total number of unique numbers.
+ int value_count() const;
+
+ // Adds a single name/number pair to the enum. Fails if this name has
+ // already been used by another value.
+ bool AddValue(const char* name, int32_t num, Status* status);
+ bool AddValue(const std::string& name, int32_t num, Status* status);
+
+ // Lookups from name to integer, returning true if found.
+ bool FindValueByName(const char* name, int32_t* num) const;
+
+ // Finds the name corresponding to the given number, or NULL if none was
+ // found. If more than one name corresponds to this number, returns the
+ // first one that was added.
+ const char* FindValueByNumber(int32_t num) const;
+
+ // Returns a new EnumDef with all the same values. The new EnumDef will be
+ // owned by the given owner.
+ EnumDef* Dup(const void* owner) const;
+
+ // Iteration over name/value pairs. The order is undefined.
+ // Adding an enum val invalidates any iterators.
+ //
+ // TODO: make compatible with range-for, with elements as pairs?
+ class Iterator {
+ public:
+ explicit Iterator(const EnumDef*);
+
+ int32_t number();
+ const char *name();
+ bool Done();
+ void Next();
+
+ private:
+ upb_enum_iter iter_;
+ };
+
+ private:
+ UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef);
+,
+UPB_DEFINE_STRUCT(upb_enumdef, upb_def,
+ upb_strtable ntoi;
+ upb_inttable iton;
+ int32_t defaultval;
+));
+
+#define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval, refs, ref2s) \
+ { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntoi, iton, defaultval }
+
+UPB_BEGIN_EXTERN_C // {
+
+// Native C API.
+upb_enumdef *upb_enumdef_new(const void *owner);
+upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner);
+
+// From upb_refcounted.
+void upb_enumdef_unref(const upb_enumdef *e, const void *owner);
+bool upb_enumdef_isfrozen(const upb_enumdef *e);
+void upb_enumdef_ref(const upb_enumdef *e, const void *owner);
+void upb_enumdef_donateref(const upb_enumdef *m, const void *from,
+ const void *to);
+void upb_enumdef_checkref(const upb_enumdef *e, const void *owner);
+bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status);
+
+// From upb_def.
+const char *upb_enumdef_fullname(const upb_enumdef *e);
+bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname,
+ upb_status *s);
+
+int32_t upb_enumdef_default(const upb_enumdef *e);
+bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s);
+int upb_enumdef_numvals(const upb_enumdef *e);
+bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
+ upb_status *status);
+
+// Enum lookups:
+// - ntoi: look up a name with specified length.
+// - ntoiz: look up a name provided as a null-terminated string.
+// - iton: look up an integer, returning the name as a null-terminated string.
+bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len,
+ int32_t *num);
+UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e,
+ const char *name, int32_t *num) {
+ return upb_enumdef_ntoi(e, name, strlen(name), num);
+}
+const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num);
+
+// upb_enum_iter i;
+// for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) {
+// // ...
+// }
+void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e);
+void upb_enum_next(upb_enum_iter *iter);
+bool upb_enum_done(upb_enum_iter *iter);
+const char *upb_enum_iter_name(upb_enum_iter *iter);
+int32_t upb_enum_iter_number(upb_enum_iter *iter);
+
+UPB_END_EXTERN_C // }
+
+/* upb::OneofDef **************************************************************/
+
+typedef upb_inttable_iter upb_oneof_iter;
+
+// Class that represents a oneof. Its base class is upb::Def (convert with
+// upb::upcast()).
+UPB_DEFINE_DEF(upb::OneofDef, oneofdef, ONEOF, UPB_QUOTE(
+ public:
+ // Returns NULL if memory allocation failed.
+ static reffed_ptr<OneofDef> New();
+
+ // Functionality from upb::RefCounted.
+ bool IsFrozen() const;
+ void Ref(const void* owner) const;
+ void Unref(const void* owner) const;
+ void DonateRef(const void* from, const void* to) const;
+ void CheckRef(const void* owner) const;
+
+ // Functionality from upb::Def.
+ const char* full_name() const;
+
+ // Returns the MessageDef that owns this OneofDef.
+ const MessageDef* containing_type() const;
+
+ // Returns the name of this oneof. This is the name used to look up the oneof
+ // by name once added to a message def.
+ const char* name() const;
+ bool set_name(const char* name, Status* s);
+
+ // Returns the number of fields currently defined in the oneof.
+ int field_count() const;
+
+ // Adds a field to the oneof. The field must not have been added to any other
+ // oneof or msgdef. If the oneof is not yet part of a msgdef, then when the
+ // oneof is eventually added to a msgdef, all fields added to the oneof will
+ // also be added to the msgdef at that time. If the oneof is already part of a
+ // msgdef, the field must either be a part of that msgdef already, or must not
+ // be a part of any msgdef; in the latter case, the field is added to the
+ // msgdef as a part of this operation.
+ //
+ // The field may only have an OPTIONAL label, never REQUIRED or REPEATED.
+ //
+ // If |f| is already part of this MessageDef, this method performs no action
+ // and returns true (success). Thus, this method is idempotent.
+ bool AddField(FieldDef* field, Status* s);
+ bool AddField(const reffed_ptr<FieldDef>& field, Status* s);
+
+ // Looks up by name.
+ const FieldDef* FindFieldByName(const char* name, size_t len) const;
+ FieldDef* FindFieldByName(const char* name, size_t len);
+ const FieldDef* FindFieldByName(const char* name) const {
+ return FindFieldByName(name, strlen(name));
+ }
+ FieldDef* FindFieldByName(const char* name) {
+ return FindFieldByName(name, strlen(name));
+ }
+
+ template <class T>
+ FieldDef* FindFieldByName(const T& str) {
+ return FindFieldByName(str.c_str(), str.size());
+ }
+ template <class T>
+ const FieldDef* FindFieldByName(const T& str) const {
+ return FindFieldByName(str.c_str(), str.size());
+ }
+
+ // Looks up by tag number.
+ const FieldDef* FindFieldByNumber(uint32_t num) const;
+
+ // Returns a new OneofDef with all the same fields. The OneofDef will be owned
+ // by the given owner.
+ OneofDef* Dup(const void* owner) const;
+
+ // Iteration over fields. The order is undefined.
+ class iterator : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+ public:
+ explicit iterator(OneofDef* md);
+ static iterator end(OneofDef* md);
+
+ void operator++();
+ FieldDef* operator*() const;
+ bool operator!=(const iterator& other) const;
+ bool operator==(const iterator& other) const;
+
+ private:
+ upb_oneof_iter iter_;
+ };
+
+ class const_iterator
+ : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+ public:
+ explicit const_iterator(const OneofDef* md);
+ static const_iterator end(const OneofDef* md);
+
+ void operator++();
+ const FieldDef* operator*() const;
+ bool operator!=(const const_iterator& other) const;
+ bool operator==(const const_iterator& other) const;
+
+ private:
+ upb_oneof_iter iter_;
+ };
+
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ private:
+ UPB_DISALLOW_POD_OPS(OneofDef, upb::OneofDef);
+),
+UPB_DEFINE_STRUCT(upb_oneofdef, upb_def,
+ upb_strtable ntof;
+ upb_inttable itof;
+ const upb_msgdef *parent;
+));
+
+#define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \
+ { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntof, itof }
+
+UPB_BEGIN_EXTERN_C // {
+
+// Native C API.
+upb_oneofdef *upb_oneofdef_new(const void *owner);
+upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner);
+
+// From upb_refcounted.
+void upb_oneofdef_unref(const upb_oneofdef *o, const void *owner);
+bool upb_oneofdef_isfrozen(const upb_oneofdef *e);
+void upb_oneofdef_ref(const upb_oneofdef *o, const void *owner);
+void upb_oneofdef_donateref(const upb_oneofdef *m, const void *from,
+ const void *to);
+void upb_oneofdef_checkref(const upb_oneofdef *o, const void *owner);
+
+const char *upb_oneofdef_name(const upb_oneofdef *o);
+bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s);
+
+const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o);
+int upb_oneofdef_numfields(const upb_oneofdef *o);
+bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
+ const void *ref_donor,
+ upb_status *s);
+
+// Oneof lookups:
+// - ntof: look up a field by name.
+// - ntofz: look up a field by name (as a null-terminated string).
+// - itof: look up a field by number.
+const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
+ const char *name, size_t length);
+UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o,
+ const char *name) {
+ return upb_oneofdef_ntof(o, name, strlen(name));
+}
+const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num);
+
+// upb_oneof_iter i;
+// for(upb_oneof_begin(&i, e); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+// // ...
+// }
+void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o);
+void upb_oneof_next(upb_oneof_iter *iter);
+bool upb_oneof_done(upb_oneof_iter *iter);
+upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter);
+void upb_oneof_iter_setdone(upb_oneof_iter *iter);
+
+UPB_END_EXTERN_C // }
+
+#ifdef __cplusplus
+
+UPB_INLINE const char* upb_safecstr(const std::string& str) {
+ assert(str.size() == std::strlen(str.c_str()));
+ return str.c_str();
+}
+
+// Inline C++ wrappers.
+namespace upb {
+
+inline Def* Def::Dup(const void* owner) const {
+ return upb_def_dup(this, owner);
+}
+inline bool Def::IsFrozen() const { return upb_def_isfrozen(this); }
+inline void Def::Ref(const void* owner) const { upb_def_ref(this, owner); }
+inline void Def::Unref(const void* owner) const { upb_def_unref(this, owner); }
+inline void Def::DonateRef(const void* from, const void* to) const {
+ upb_def_donateref(this, from, to);
+}
+inline void Def::CheckRef(const void* owner) const {
+ upb_def_checkref(this, owner);
+}
+inline Def::Type Def::def_type() const { return upb_def_type(this); }
+inline const char* Def::full_name() const { return upb_def_fullname(this); }
+inline bool Def::set_full_name(const char* fullname, Status* s) {
+ return upb_def_setfullname(this, fullname, s);
+}
+inline bool Def::set_full_name(const std::string& fullname, Status* s) {
+ return upb_def_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool Def::Freeze(Def* const* defs, int n, Status* status) {
+ return upb_def_freeze(defs, n, status);
+}
+inline bool Def::Freeze(const std::vector<Def*>& defs, Status* status) {
+ return upb_def_freeze((Def* const*)&defs[0], defs.size(), status);
+}
+
+inline bool FieldDef::CheckType(int32_t val) {
+ return upb_fielddef_checktype(val);
+}
+inline bool FieldDef::CheckLabel(int32_t val) {
+ return upb_fielddef_checklabel(val);
+}
+inline bool FieldDef::CheckDescriptorType(int32_t val) {
+ return upb_fielddef_checkdescriptortype(val);
+}
+inline bool FieldDef::CheckIntegerFormat(int32_t val) {
+ return upb_fielddef_checkintfmt(val);
+}
+inline FieldDef::Type FieldDef::ConvertType(int32_t val) {
+ assert(CheckType(val));
+ return static_cast<FieldDef::Type>(val);
+}
+inline FieldDef::Label FieldDef::ConvertLabel(int32_t val) {
+ assert(CheckLabel(val));
+ return static_cast<FieldDef::Label>(val);
+}
+inline FieldDef::DescriptorType FieldDef::ConvertDescriptorType(int32_t val) {
+ assert(CheckDescriptorType(val));
+ return static_cast<FieldDef::DescriptorType>(val);
+}
+inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) {
+ assert(CheckIntegerFormat(val));
+ return static_cast<FieldDef::IntegerFormat>(val);
+}
+
+inline reffed_ptr<FieldDef> FieldDef::New() {
+ upb_fielddef *f = upb_fielddef_new(&f);
+ return reffed_ptr<FieldDef>(f, &f);
+}
+inline FieldDef* FieldDef::Dup(const void* owner) const {
+ return upb_fielddef_dup(this, owner);
+}
+inline bool FieldDef::IsFrozen() const { return upb_fielddef_isfrozen(this); }
+inline void FieldDef::Ref(const void* owner) const {
+ upb_fielddef_ref(this, owner);
+}
+inline void FieldDef::Unref(const void* owner) const {
+ upb_fielddef_unref(this, owner);
+}
+inline void FieldDef::DonateRef(const void* from, const void* to) const {
+ upb_fielddef_donateref(this, from, to);
+}
+inline void FieldDef::CheckRef(const void* owner) const {
+ upb_fielddef_checkref(this, owner);
+}
+inline const char* FieldDef::full_name() const {
+ return upb_fielddef_fullname(this);
+}
+inline bool FieldDef::set_full_name(const char* fullname, Status* s) {
+ return upb_fielddef_setfullname(this, fullname, s);
+}
+inline bool FieldDef::set_full_name(const std::string& fullname, Status* s) {
+ return upb_fielddef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool FieldDef::type_is_set() const {
+ return upb_fielddef_typeisset(this);
+}
+inline FieldDef::Type FieldDef::type() const { return upb_fielddef_type(this); }
+inline FieldDef::DescriptorType FieldDef::descriptor_type() const {
+ return upb_fielddef_descriptortype(this);
+}
+inline FieldDef::Label FieldDef::label() const {
+ return upb_fielddef_label(this);
+}
+inline uint32_t FieldDef::number() const { return upb_fielddef_number(this); }
+inline const char* FieldDef::name() const { return upb_fielddef_name(this); }
+inline bool FieldDef::is_extension() const {
+ return upb_fielddef_isextension(this);
+}
+inline bool FieldDef::lazy() const {
+ return upb_fielddef_lazy(this);
+}
+inline void FieldDef::set_lazy(bool lazy) {
+ upb_fielddef_setlazy(this, lazy);
+}
+inline bool FieldDef::packed() const {
+ return upb_fielddef_packed(this);
+}
+inline void FieldDef::set_packed(bool packed) {
+ upb_fielddef_setpacked(this, packed);
+}
+inline const MessageDef* FieldDef::containing_type() const {
+ return upb_fielddef_containingtype(this);
+}
+inline const OneofDef* FieldDef::containing_oneof() const {
+ return upb_fielddef_containingoneof(this);
+}
+inline const char* FieldDef::containing_type_name() {
+ return upb_fielddef_containingtypename(this);
+}
+inline bool FieldDef::set_number(uint32_t number, Status* s) {
+ return upb_fielddef_setnumber(this, number, s);
+}
+inline bool FieldDef::set_name(const char *name, Status* s) {
+ return upb_fielddef_setname(this, name, s);
+}
+inline bool FieldDef::set_name(const std::string& name, Status* s) {
+ return upb_fielddef_setname(this, upb_safecstr(name), s);
+}
+inline bool FieldDef::set_containing_type_name(const char *name, Status* s) {
+ return upb_fielddef_setcontainingtypename(this, name, s);
+}
+inline bool FieldDef::set_containing_type_name(const std::string &name,
+ Status *s) {
+ return upb_fielddef_setcontainingtypename(this, upb_safecstr(name), s);
+}
+inline void FieldDef::set_type(upb_fieldtype_t type) {
+ upb_fielddef_settype(this, type);
+}
+inline void FieldDef::set_is_extension(bool is_extension) {
+ upb_fielddef_setisextension(this, is_extension);
+}
+inline void FieldDef::set_descriptor_type(FieldDef::DescriptorType type) {
+ upb_fielddef_setdescriptortype(this, type);
+}
+inline void FieldDef::set_label(upb_label_t label) {
+ upb_fielddef_setlabel(this, label);
+}
+inline bool FieldDef::IsSubMessage() const {
+ return upb_fielddef_issubmsg(this);
+}
+inline bool FieldDef::IsString() const { return upb_fielddef_isstring(this); }
+inline bool FieldDef::IsSequence() const { return upb_fielddef_isseq(this); }
+inline bool FieldDef::IsMap() const { return upb_fielddef_ismap(this); }
+inline int64_t FieldDef::default_int64() const {
+ return upb_fielddef_defaultint64(this);
+}
+inline int32_t FieldDef::default_int32() const {
+ return upb_fielddef_defaultint32(this);
+}
+inline uint64_t FieldDef::default_uint64() const {
+ return upb_fielddef_defaultuint64(this);
+}
+inline uint32_t FieldDef::default_uint32() const {
+ return upb_fielddef_defaultuint32(this);
+}
+inline bool FieldDef::default_bool() const {
+ return upb_fielddef_defaultbool(this);
+}
+inline float FieldDef::default_float() const {
+ return upb_fielddef_defaultfloat(this);
+}
+inline double FieldDef::default_double() const {
+ return upb_fielddef_defaultdouble(this);
+}
+inline const char* FieldDef::default_string(size_t* len) const {
+ return upb_fielddef_defaultstr(this, len);
+}
+inline void FieldDef::set_default_int64(int64_t value) {
+ upb_fielddef_setdefaultint64(this, value);
+}
+inline void FieldDef::set_default_int32(int32_t value) {
+ upb_fielddef_setdefaultint32(this, value);
+}
+inline void FieldDef::set_default_uint64(uint64_t value) {
+ upb_fielddef_setdefaultuint64(this, value);
+}
+inline void FieldDef::set_default_uint32(uint32_t value) {
+ upb_fielddef_setdefaultuint32(this, value);
+}
+inline void FieldDef::set_default_bool(bool value) {
+ upb_fielddef_setdefaultbool(this, value);
+}
+inline void FieldDef::set_default_float(float value) {
+ upb_fielddef_setdefaultfloat(this, value);
+}
+inline void FieldDef::set_default_double(double value) {
+ upb_fielddef_setdefaultdouble(this, value);
+}
+inline bool FieldDef::set_default_string(const void *str, size_t len,
+ Status *s) {
+ return upb_fielddef_setdefaultstr(this, str, len, s);
+}
+inline bool FieldDef::set_default_string(const std::string& str, Status* s) {
+ return upb_fielddef_setdefaultstr(this, str.c_str(), str.size(), s);
+}
+inline void FieldDef::set_default_cstr(const char* str, Status* s) {
+ return upb_fielddef_setdefaultcstr(this, str, s);
+}
+inline bool FieldDef::HasSubDef() const { return upb_fielddef_hassubdef(this); }
+inline const Def* FieldDef::subdef() const { return upb_fielddef_subdef(this); }
+inline const MessageDef *FieldDef::message_subdef() const {
+ return upb_fielddef_msgsubdef(this);
+}
+inline const EnumDef *FieldDef::enum_subdef() const {
+ return upb_fielddef_enumsubdef(this);
+}
+inline const char* FieldDef::subdef_name() const {
+ return upb_fielddef_subdefname(this);
+}
+inline bool FieldDef::set_subdef(const Def* subdef, Status* s) {
+ return upb_fielddef_setsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_enum_subdef(const EnumDef* subdef, Status* s) {
+ return upb_fielddef_setenumsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_message_subdef(const MessageDef* subdef, Status* s) {
+ return upb_fielddef_setmsgsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_subdef_name(const char* name, Status* s) {
+ return upb_fielddef_setsubdefname(this, name, s);
+}
+inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) {
+ return upb_fielddef_setsubdefname(this, upb_safecstr(name), s);
+}
+
+inline reffed_ptr<MessageDef> MessageDef::New() {
+ upb_msgdef *m = upb_msgdef_new(&m);
+ return reffed_ptr<MessageDef>(m, &m);
+}
+inline bool MessageDef::IsFrozen() const { return upb_msgdef_isfrozen(this); }
+inline void MessageDef::Ref(const void* owner) const {
+ return upb_msgdef_ref(this, owner);
+}
+inline void MessageDef::Unref(const void* owner) const {
+ return upb_msgdef_unref(this, owner);
+}
+inline void MessageDef::DonateRef(const void* from, const void* to) const {
+ return upb_msgdef_donateref(this, from, to);
+}
+inline void MessageDef::CheckRef(const void* owner) const {
+ return upb_msgdef_checkref(this, owner);
+}
+inline const char *MessageDef::full_name() const {
+ return upb_msgdef_fullname(this);
+}
+inline bool MessageDef::set_full_name(const char* fullname, Status* s) {
+ return upb_msgdef_setfullname(this, fullname, s);
+}
+inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) {
+ return upb_msgdef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool MessageDef::Freeze(Status* status) {
+ return upb_msgdef_freeze(this, status);
+}
+inline int MessageDef::field_count() const {
+ return upb_msgdef_numfields(this);
+}
+inline int MessageDef::oneof_count() const {
+ return upb_msgdef_numoneofs(this);
+}
+inline bool MessageDef::AddField(upb_fielddef* f, Status* s) {
+ return upb_msgdef_addfield(this, f, NULL, s);
+}
+inline bool MessageDef::AddField(const reffed_ptr<FieldDef>& f, Status* s) {
+ return upb_msgdef_addfield(this, f.get(), NULL, s);
+}
+inline bool MessageDef::AddOneof(upb_oneofdef* o, Status* s) {
+ return upb_msgdef_addoneof(this, o, NULL, s);
+}
+inline bool MessageDef::AddOneof(const reffed_ptr<OneofDef>& o, Status* s) {
+ return upb_msgdef_addoneof(this, o.get(), NULL, s);
+}
+inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) {
+ return upb_msgdef_itof_mutable(this, number);
+}
+inline FieldDef* MessageDef::FindFieldByName(const char* name, size_t len) {
+ return upb_msgdef_ntof_mutable(this, name, len);
+}
+inline const FieldDef* MessageDef::FindFieldByNumber(uint32_t number) const {
+ return upb_msgdef_itof(this, number);
+}
+inline const FieldDef *MessageDef::FindFieldByName(const char *name,
+ size_t len) const {
+ return upb_msgdef_ntof(this, name, len);
+}
+inline OneofDef* MessageDef::FindOneofByName(const char* name, size_t len) {
+ return upb_msgdef_ntoo_mutable(this, name, len);
+}
+inline const OneofDef* MessageDef::FindOneofByName(const char* name,
+ size_t len) const {
+ return upb_msgdef_ntoo(this, name, len);
+}
+inline MessageDef* MessageDef::Dup(const void *owner) const {
+ return upb_msgdef_dup(this, owner);
+}
+inline void MessageDef::setmapentry(bool map_entry) {
+ upb_msgdef_setmapentry(this, map_entry);
+}
+inline bool MessageDef::mapentry() const {
+ return upb_msgdef_mapentry(this);
+}
+inline MessageDef::field_iterator MessageDef::field_begin() {
+ return field_iterator(this);
+}
+inline MessageDef::field_iterator MessageDef::field_end() {
+ return field_iterator::end(this);
+}
+inline MessageDef::const_field_iterator MessageDef::field_begin() const {
+ return const_field_iterator(this);
+}
+inline MessageDef::const_field_iterator MessageDef::field_end() const {
+ return const_field_iterator::end(this);
+}
+
+inline MessageDef::oneof_iterator MessageDef::oneof_begin() {
+ return oneof_iterator(this);
+}
+inline MessageDef::oneof_iterator MessageDef::oneof_end() {
+ return oneof_iterator::end(this);
+}
+inline MessageDef::const_oneof_iterator MessageDef::oneof_begin() const {
+ return const_oneof_iterator(this);
+}
+inline MessageDef::const_oneof_iterator MessageDef::oneof_end() const {
+ return const_oneof_iterator::end(this);
+}
+
+inline MessageDef::field_iterator::field_iterator(MessageDef* md) {
+ upb_msg_field_begin(&iter_, md);
+}
+inline MessageDef::field_iterator MessageDef::field_iterator::end(
+ MessageDef* md) {
+ MessageDef::field_iterator iter(md);
+ upb_msg_field_iter_setdone(&iter.iter_);
+ return iter;
+}
+inline FieldDef* MessageDef::field_iterator::operator*() const {
+ return upb_msg_iter_field(&iter_);
+}
+inline void MessageDef::field_iterator::operator++() {
+ return upb_msg_field_next(&iter_);
+}
+inline bool MessageDef::field_iterator::operator==(
+ const field_iterator &other) const {
+ return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::field_iterator::operator!=(
+ const field_iterator &other) const {
+ return !(*this == other);
+}
+
+inline MessageDef::const_field_iterator::const_field_iterator(
+ const MessageDef* md) {
+ upb_msg_field_begin(&iter_, md);
+}
+inline MessageDef::const_field_iterator MessageDef::const_field_iterator::end(
+ const MessageDef *md) {
+ MessageDef::const_field_iterator iter(md);
+ upb_msg_field_iter_setdone(&iter.iter_);
+ return iter;
+}
+inline const FieldDef* MessageDef::const_field_iterator::operator*() const {
+ return upb_msg_iter_field(&iter_);
+}
+inline void MessageDef::const_field_iterator::operator++() {
+ return upb_msg_field_next(&iter_);
+}
+inline bool MessageDef::const_field_iterator::operator==(
+ const const_field_iterator &other) const {
+ return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::const_field_iterator::operator!=(
+ const const_field_iterator &other) const {
+ return !(*this == other);
+}
+
+inline MessageDef::oneof_iterator::oneof_iterator(MessageDef* md) {
+ upb_msg_oneof_begin(&iter_, md);
+}
+inline MessageDef::oneof_iterator MessageDef::oneof_iterator::end(
+ MessageDef* md) {
+ MessageDef::oneof_iterator iter(md);
+ upb_msg_oneof_iter_setdone(&iter.iter_);
+ return iter;
+}
+inline OneofDef* MessageDef::oneof_iterator::operator*() const {
+ return upb_msg_iter_oneof(&iter_);
+}
+inline void MessageDef::oneof_iterator::operator++() {
+ return upb_msg_oneof_next(&iter_);
+}
+inline bool MessageDef::oneof_iterator::operator==(
+ const oneof_iterator &other) const {
+ return upb_strtable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::oneof_iterator::operator!=(
+ const oneof_iterator &other) const {
+ return !(*this == other);
+}
+
+inline MessageDef::const_oneof_iterator::const_oneof_iterator(
+ const MessageDef* md) {
+ upb_msg_oneof_begin(&iter_, md);
+}
+inline MessageDef::const_oneof_iterator MessageDef::const_oneof_iterator::end(
+ const MessageDef *md) {
+ MessageDef::const_oneof_iterator iter(md);
+ upb_msg_oneof_iter_setdone(&iter.iter_);
+ return iter;
+}
+inline const OneofDef* MessageDef::const_oneof_iterator::operator*() const {
+ return upb_msg_iter_oneof(&iter_);
+}
+inline void MessageDef::const_oneof_iterator::operator++() {
+ return upb_msg_oneof_next(&iter_);
+}
+inline bool MessageDef::const_oneof_iterator::operator==(
+ const const_oneof_iterator &other) const {
+ return upb_strtable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::const_oneof_iterator::operator!=(
+ const const_oneof_iterator &other) const {
+ return !(*this == other);
+}
+
+inline reffed_ptr<EnumDef> EnumDef::New() {
+ upb_enumdef *e = upb_enumdef_new(&e);
+ return reffed_ptr<EnumDef>(e, &e);
+}
+inline bool EnumDef::IsFrozen() const { return upb_enumdef_isfrozen(this); }
+inline void EnumDef::Ref(const void* owner) const {
+ return upb_enumdef_ref(this, owner);
+}
+inline void EnumDef::Unref(const void* owner) const {
+ return upb_enumdef_unref(this, owner);
+}
+inline void EnumDef::DonateRef(const void* from, const void* to) const {
+ return upb_enumdef_donateref(this, from, to);
+}
+inline void EnumDef::CheckRef(const void* owner) const {
+ return upb_enumdef_checkref(this, owner);
+}
+inline const char* EnumDef::full_name() const {
+ return upb_enumdef_fullname(this);
+}
+inline bool EnumDef::set_full_name(const char* fullname, Status* s) {
+ return upb_enumdef_setfullname(this, fullname, s);
+}
+inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) {
+ return upb_enumdef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool EnumDef::Freeze(Status* status) {
+ return upb_enumdef_freeze(this, status);
+}
+inline int32_t EnumDef::default_value() const {
+ return upb_enumdef_default(this);
+}
+inline bool EnumDef::set_default_value(int32_t val, Status* status) {
+ return upb_enumdef_setdefault(this, val, status);
+}
+inline int EnumDef::value_count() const { return upb_enumdef_numvals(this); }
+inline bool EnumDef::AddValue(const char* name, int32_t num, Status* status) {
+ return upb_enumdef_addval(this, name, num, status);
+}
+inline bool EnumDef::AddValue(const std::string& name, int32_t num,
+ Status* status) {
+ return upb_enumdef_addval(this, upb_safecstr(name), num, status);
+}
+inline bool EnumDef::FindValueByName(const char* name, int32_t *num) const {
+ return upb_enumdef_ntoiz(this, name, num);
+}
+inline const char* EnumDef::FindValueByNumber(int32_t num) const {
+ return upb_enumdef_iton(this, num);
+}
+inline EnumDef* EnumDef::Dup(const void* owner) const {
+ return upb_enumdef_dup(this, owner);
+}
+
+inline EnumDef::Iterator::Iterator(const EnumDef* e) {
+ upb_enum_begin(&iter_, e);
+}
+inline int32_t EnumDef::Iterator::number() {
+ return upb_enum_iter_number(&iter_);
+}
+inline const char* EnumDef::Iterator::name() {
+ return upb_enum_iter_name(&iter_);
+}
+inline bool EnumDef::Iterator::Done() { return upb_enum_done(&iter_); }
+inline void EnumDef::Iterator::Next() { return upb_enum_next(&iter_); }
+
+inline reffed_ptr<OneofDef> OneofDef::New() {
+ upb_oneofdef *o = upb_oneofdef_new(&o);
+ return reffed_ptr<OneofDef>(o, &o);
+}
+inline bool OneofDef::IsFrozen() const { return upb_oneofdef_isfrozen(this); }
+inline void OneofDef::Ref(const void* owner) const {
+ return upb_oneofdef_ref(this, owner);
+}
+inline void OneofDef::Unref(const void* owner) const {
+ return upb_oneofdef_unref(this, owner);
+}
+inline void OneofDef::DonateRef(const void* from, const void* to) const {
+ return upb_oneofdef_donateref(this, from, to);
+}
+inline void OneofDef::CheckRef(const void* owner) const {
+ return upb_oneofdef_checkref(this, owner);
+}
+inline const char* OneofDef::full_name() const {
+ return upb_oneofdef_name(this);
+}
+
+inline const MessageDef* OneofDef::containing_type() const {
+ return upb_oneofdef_containingtype(this);
+}
+inline const char* OneofDef::name() const {
+ return upb_oneofdef_name(this);
+}
+inline bool OneofDef::set_name(const char* name, Status* s) {
+ return upb_oneofdef_setname(this, name, s);
+}
+inline int OneofDef::field_count() const {
+ return upb_oneofdef_numfields(this);
+}
+inline bool OneofDef::AddField(FieldDef* field, Status* s) {
+ return upb_oneofdef_addfield(this, field, NULL, s);
+}
+inline bool OneofDef::AddField(const reffed_ptr<FieldDef>& field, Status* s) {
+ return upb_oneofdef_addfield(this, field.get(), NULL, s);
+}
+inline const FieldDef* OneofDef::FindFieldByName(const char* name,
+ size_t len) const {
+ return upb_oneofdef_ntof(this, name, len);
+}
+inline const FieldDef* OneofDef::FindFieldByNumber(uint32_t num) const {
+ return upb_oneofdef_itof(this, num);
+}
+inline OneofDef::iterator OneofDef::begin() { return iterator(this); }
+inline OneofDef::iterator OneofDef::end() { return iterator::end(this); }
+inline OneofDef::const_iterator OneofDef::begin() const {
+ return const_iterator(this);
+}
+inline OneofDef::const_iterator OneofDef::end() const {
+ return const_iterator::end(this);
+}
+
+inline OneofDef::iterator::iterator(OneofDef* o) {
+ upb_oneof_begin(&iter_, o);
+}
+inline OneofDef::iterator OneofDef::iterator::end(OneofDef* o) {
+ OneofDef::iterator iter(o);
+ upb_oneof_iter_setdone(&iter.iter_);
+ return iter;
+}
+inline FieldDef* OneofDef::iterator::operator*() const {
+ return upb_oneof_iter_field(&iter_);
+}
+inline void OneofDef::iterator::operator++() { return upb_oneof_next(&iter_); }
+inline bool OneofDef::iterator::operator==(const iterator &other) const {
+ return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool OneofDef::iterator::operator!=(const iterator &other) const {
+ return !(*this == other);
+}
+
+inline OneofDef::const_iterator::const_iterator(const OneofDef* md) {
+ upb_oneof_begin(&iter_, md);
+}
+inline OneofDef::const_iterator OneofDef::const_iterator::end(
+ const OneofDef *md) {
+ OneofDef::const_iterator iter(md);
+ upb_oneof_iter_setdone(&iter.iter_);
+ return iter;
+}
+inline const FieldDef* OneofDef::const_iterator::operator*() const {
+ return upb_msg_iter_field(&iter_);
+}
+inline void OneofDef::const_iterator::operator++() {
+ return upb_oneof_next(&iter_);
+}
+inline bool OneofDef::const_iterator::operator==(
+ const const_iterator &other) const {
+ return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool OneofDef::const_iterator::operator!=(
+ const const_iterator &other) const {
+ return !(*this == other);
+}
+
+} // namespace upb
+#endif
+
+#undef UPB_DEFINE_DEF
+#undef UPB_DEF_CASTS
+#undef UPB_CPP_CASTS
+
+#endif /* UPB_DEF_H_ */
+// This file contains accessors for a set of compiled-in defs.
+// Note that unlike Google's protobuf, it does *not* define
+// generated classes or any other kind of data structure for
+// actually storing protobufs. It only contains *defs* which
+// let you reflect over a protobuf *schema*.
+//
+// This file was generated by upbc (the upb compiler).
+// Do not edit -- your changes will be discarded when the file is
+// regenerated.
+
+#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_
+#define GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_
+
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * A symtab (symbol table) stores a name->def map of upb_defs. Clients could
+ * always create such tables themselves, but upb_symtab has logic for resolving
+ * symbolic references, and in particular, for keeping a whole set of consistent
+ * defs when replacing some subset of those defs. This logic is nontrivial.
+ *
+ * This is a mixed C/C++ interface that offers a full API to both languages.
+ * See the top-level README for more information.
+ */
+
+#ifndef UPB_SYMTAB_H_
+#define UPB_SYMTAB_H_
+
+
+#ifdef __cplusplus
+#include <vector>
+namespace upb { class SymbolTable; }
+#endif
+
+UPB_DECLARE_TYPE(upb::SymbolTable, upb_symtab);
+
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+ upb_strtable_iter iter;
+ upb_deftype_t type;
+} upb_symtab_iter;
+
+// Non-const methods in upb::SymbolTable are NOT thread-safe.
+UPB_DEFINE_CLASS1(upb::SymbolTable, upb::RefCounted,
+ public:
+ // Returns a new symbol table with a single ref owned by "owner."
+ // Returns NULL if memory allocation failed.
+ static reffed_ptr<SymbolTable> New();
+
+ // Functionality from upb::RefCounted.
+ bool IsFrozen() const;
+ void Ref(const void* owner) const;
+ void Unref(const void* owner) const;
+ void DonateRef(const void *from, const void *to) const;
+ void CheckRef(const void *owner) const;
+
+ // For all lookup functions, the returned pointer is not owned by the
+ // caller; it may be invalidated by any non-const call or unref of the
+ // SymbolTable! To protect against this, take a ref if desired.
+
+ // Freezes the symbol table: prevents further modification of it.
+ // After the Freeze() operation is successful, the SymbolTable must only be
+ // accessed via a const pointer.
+ //
+ // Unlike with upb::MessageDef/upb::EnumDef/etc, freezing a SymbolTable is not
+ // a necessary step in using a SymbolTable. If you have no need for it to be
+ // immutable, there is no need to freeze it ever. However sometimes it is
+ // useful, and SymbolTables that are statically compiled into the binary are
+ // always frozen by nature.
+ void Freeze();
+
+ // Resolves the given symbol using the rules described in descriptor.proto,
+ // namely:
+ //
+ // If the name starts with a '.', it is fully-qualified. Otherwise,
+ // C++-like scoping rules are used to find the type (i.e. first the nested
+ // types within this message are searched, then within the parent, on up
+ // to the root namespace).
+ //
+ // If not found, returns NULL.
+ const Def* Resolve(const char* base, const char* sym) const;
+
+ // Finds an entry in the symbol table with this exact name. If not found,
+ // returns NULL.
+ const Def* Lookup(const char *sym) const;
+ const MessageDef* LookupMessage(const char *sym) const;
+ const EnumDef* LookupEnum(const char *sym) const;
+
+ // TODO: introduce a C++ iterator, but make it nice and templated so that if
+ // you ask for an iterator of MessageDef the iterated elements are strongly
+ // typed as MessageDef*.
+
+ // Adds the given mutable defs to the symtab, resolving all symbols
+ // (including enum default values) and finalizing the defs. Only one def per
+ // name may be in the list, but defs can replace existing defs in the symtab.
+ // All defs must have a name -- anonymous defs are not allowed. Anonymous
+ // defs can still be frozen by calling upb_def_freeze() directly.
+ //
+ // Any existing defs that can reach defs that are being replaced will
+ // themselves be replaced also, so that the resulting set of defs is fully
+ // consistent.
+ //
+ // This logic implemented in this method is a convenience; ultimately it
+ // calls some combination of upb_fielddef_setsubdef(), upb_def_dup(), and
+ // upb_freeze(), any of which the client could call themself. However, since
+ // the logic for doing so is nontrivial, we provide it here.
+ //
+ // The entire operation either succeeds or fails. If the operation fails,
+ // the symtab is unchanged, false is returned, and status indicates the
+ // error. The caller passes a ref on all defs to the symtab (even if the
+ // operation fails).
+ //
+ // TODO(haberman): currently failure will leave the symtab unchanged, but may
+ // leave the defs themselves partially resolved. Does this matter? If so we
+ // could do a prepass that ensures that all symbols are resolvable and bail
+ // if not, so we don't mutate anything until we know the operation will
+ // succeed.
+ //
+ // TODO(haberman): since the defs must be mutable, refining a frozen def
+ // requires making mutable copies of the entire tree. This is wasteful if
+ // only a few messages are changing. We may want to add a way of adding a
+ // tree of frozen defs to the symtab (perhaps an alternate constructor where
+ // you pass the root of the tree?)
+ bool Add(Def*const* defs, int n, void* ref_donor, upb_status* status);
+
+ bool Add(const std::vector<Def*>& defs, void *owner, Status* status) {
+ return Add((Def*const*)&defs[0], defs.size(), owner, status);
+ }
+
+ private:
+ UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable);
+,
+UPB_DEFINE_STRUCT(upb_symtab, upb_refcounted,
+ upb_strtable symtab;
+));
+
+#define UPB_SYMTAB_INIT(symtab, refs, ref2s) \
+ { UPB_REFCOUNT_INIT(refs, ref2s), symtab }
+
+UPB_BEGIN_EXTERN_C // {
+
+// Native C API.
+// From upb_refcounted.
+bool upb_symtab_isfrozen(const upb_symtab *s);
+void upb_symtab_ref(const upb_symtab *s, const void *owner);
+void upb_symtab_unref(const upb_symtab *s, const void *owner);
+void upb_symtab_donateref(
+ const upb_symtab *s, const void *from, const void *to);
+void upb_symtab_checkref(const upb_symtab *s, const void *owner);
+
+upb_symtab *upb_symtab_new(const void *owner);
+void upb_symtab_freeze(upb_symtab *s);
+const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base,
+ const char *sym);
+const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym);
+const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym);
+const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym);
+bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
+ upb_status *status);
+
+// upb_symtab_iter i;
+// for(upb_symtab_begin(&i, s, type); !upb_symtab_done(&i);
+// upb_symtab_next(&i)) {
+// const upb_def *def = upb_symtab_iter_def(&i);
+// // ...
+// }
+//
+// For C we don't have separate iterators for const and non-const.
+// It is the caller's responsibility to cast the upb_fielddef* to
+// const if the upb_msgdef* is const.
+void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s,
+ upb_deftype_t type);
+void upb_symtab_next(upb_symtab_iter *iter);
+bool upb_symtab_done(const upb_symtab_iter *iter);
+const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter);
+
+UPB_END_EXTERN_C // }
+
+#ifdef __cplusplus
+// C++ inline wrappers.
+namespace upb {
+inline reffed_ptr<SymbolTable> SymbolTable::New() {
+ upb_symtab *s = upb_symtab_new(&s);
+ return reffed_ptr<SymbolTable>(s, &s);
+}
+
+inline bool SymbolTable::IsFrozen() const {
+ return upb_symtab_isfrozen(this);
+}
+inline void SymbolTable::Ref(const void *owner) const {
+ upb_symtab_ref(this, owner);
+}
+inline void SymbolTable::Unref(const void *owner) const {
+ upb_symtab_unref(this, owner);
+}
+inline void SymbolTable::DonateRef(const void *from, const void *to) const {
+ upb_symtab_donateref(this, from, to);
+}
+inline void SymbolTable::CheckRef(const void *owner) const {
+ upb_symtab_checkref(this, owner);
+}
+
+inline void SymbolTable::Freeze() {
+ return upb_symtab_freeze(this);
+}
+inline const Def *SymbolTable::Resolve(const char *base,
+ const char *sym) const {
+ return upb_symtab_resolve(this, base, sym);
+}
+inline const Def* SymbolTable::Lookup(const char *sym) const {
+ return upb_symtab_lookup(this, sym);
+}
+inline const MessageDef *SymbolTable::LookupMessage(const char *sym) const {
+ return upb_symtab_lookupmsg(this, sym);
+}
+inline bool SymbolTable::Add(
+ Def*const* defs, int n, void* ref_donor, upb_status* status) {
+ return upb_symtab_add(this, (upb_def*const*)defs, n, ref_donor, status);
+}
+} // namespace upb
+#endif
+
+#endif /* UPB_SYMTAB_H_ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Enums
+
+typedef enum {
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_OPTIONAL = 1,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED = 2,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REPEATED = 3,
+} google_protobuf_FieldDescriptorProto_Label;
+
+typedef enum {
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_DOUBLE = 1,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FLOAT = 2,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT64 = 3,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT64 = 4,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 = 5,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED64 = 6,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED32 = 7,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BOOL = 8,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_STRING = 9,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_GROUP = 10,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_MESSAGE = 11,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BYTES = 12,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT32 = 13,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ENUM = 14,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED32 = 15,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED64 = 16,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT32 = 17,
+ GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT64 = 18,
+} google_protobuf_FieldDescriptorProto_Type;
+
+typedef enum {
+ GOOGLE_PROTOBUF_FIELDOPTIONS_STRING = 0,
+ GOOGLE_PROTOBUF_FIELDOPTIONS_CORD = 1,
+ GOOGLE_PROTOBUF_FIELDOPTIONS_STRING_PIECE = 2,
+} google_protobuf_FieldOptions_CType;
+
+typedef enum {
+ GOOGLE_PROTOBUF_FILEOPTIONS_SPEED = 1,
+ GOOGLE_PROTOBUF_FILEOPTIONS_CODE_SIZE = 2,
+ GOOGLE_PROTOBUF_FILEOPTIONS_LITE_RUNTIME = 3,
+} google_protobuf_FileOptions_OptimizeMode;
+
+// Selectors
+
+// google.protobuf.DescriptorProto
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 4
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 6
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 7
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 8
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 9
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 10
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 11
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 12
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSUBMSG 13
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 14
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 15
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 16
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 17
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 18
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 19
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 20
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 21
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 22
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 23
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 24
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 25
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 26
+
+// google.protobuf.DescriptorProto.ExtensionRange
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START_INT32 2
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END_INT32 3
+
+// google.protobuf.EnumDescriptorProto
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 4
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 5
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 6
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 8
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 9
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 10
+
+// google.protobuf.EnumOptions
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_ALLOW_ALIAS_BOOL 6
+
+// google.protobuf.EnumValueDescriptorProto
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 4
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 5
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 6
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 7
+
+// google.protobuf.EnumValueOptions
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+
+// google.protobuf.FieldDescriptorProto
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 4
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 5
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 6
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 7
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 8
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 9
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 10
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 11
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 12
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 13
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 14
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 15
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 16
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 17
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 18
+
+// google.protobuf.FieldOptions
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 6
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 7
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 8
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_LAZY_BOOL 9
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 10
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 11
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 12
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_WEAK_BOOL 13
+
+// google.protobuf.FileDescriptorProto
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 4
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 7
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 8
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 9
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 10
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 11
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 12
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 13
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 14
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 15
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 16
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 17
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 18
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 19
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 20
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 21
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 22
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 23
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 24
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 25
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 26
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 27
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 28
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 29
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 30
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 31
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 32
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_STARTSEQ 33
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_ENDSEQ 34
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_INT32 35
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_STARTSEQ 36
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_ENDSEQ 37
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_INT32 38
+
+// google.protobuf.FileDescriptorSet
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSUBMSG 5
+
+// google.protobuf.FileOptions
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 6
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 7
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 8
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 9
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 10
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 11
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 12
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 13
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_STRING 14
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_STARTSTR 15
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_ENDSTR 16
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 17
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 18
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 19
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 20
+
+// google.protobuf.MessageOptions
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 6
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 7
+
+// google.protobuf.MethodDescriptorProto
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 4
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 5
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 6
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 7
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 8
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 9
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 10
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 11
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 12
+
+// google.protobuf.MethodOptions
+#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+
+// google.protobuf.ServiceDescriptorProto
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 4
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 5
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 6
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 8
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 9
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 10
+
+// google.protobuf.ServiceOptions
+#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+
+// google.protobuf.SourceCodeInfo
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSUBMSG 5
+
+// google.protobuf.SourceCodeInfo.Location
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_STARTSEQ 2
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_ENDSEQ 3
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_INT32 4
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_STARTSEQ 5
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_ENDSEQ 6
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_INT32 7
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_STRING 8
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_STARTSTR 9
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_ENDSTR 10
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_STRING 11
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_STARTSTR 12
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_ENDSTR 13
+
+// google.protobuf.UninterpretedOption
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 6
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 7
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 8
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 9
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 10
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 11
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 12
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 13
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 14
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 15
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 16
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 17
+
+// google.protobuf.UninterpretedOption.NamePart
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STRING 2
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STARTSTR 3
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_ENDSTR 4
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION_BOOL 5
+
+const upb_symtab *upbdefs_google_protobuf_descriptor(const void *owner);
+
+// MessageDefs
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_DescriptorProto(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto.ExtensionRange");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumDescriptorProto");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumOptions(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumOptions");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumValueDescriptorProto");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumValueOptions");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FieldDescriptorProto");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FieldOptions(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FieldOptions");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorProto");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorSet");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileOptions(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileOptions");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MessageOptions(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MessageOptions");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MethodDescriptorProto");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MethodOptions(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MethodOptions");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.ServiceDescriptorProto");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_ServiceOptions(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.ServiceOptions");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo.Location");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption");
+ assert(m);
+ return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart(const upb_symtab *s) {
+ const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption.NamePart");
+ assert(m);
+ return m;
+}
+
+
+// EnumDefs
+UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label(const upb_symtab *s) {
+ const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldDescriptorProto.Label");
+ assert(e);
+ return e;
+}
+UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type(const upb_symtab *s) {
+ const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldDescriptorProto.Type");
+ assert(e);
+ return e;
+}
+UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType(const upb_symtab *s) {
+ const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldOptions.CType");
+ assert(e);
+ return e;
+}
+UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode(const upb_symtab *s) {
+ const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FileOptions.OptimizeMode");
+ assert(e);
+ return e;
+}
+
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_end(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ExtensionRange(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_start(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ExtensionRange(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_enum_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_extension_range(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_field(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_nested_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_allow_alias(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumOptions(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_number(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_default_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_extendee(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_label(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_number(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_type_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_ctype(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_experimental_map_key(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_lazy(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_packed(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_weak(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_enum_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_message_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_public_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_service(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_source_code_info(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_weak_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 11); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorSet_file(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorSet(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_cc_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 16); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_go_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 11); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_generate_equals_and_hash(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 20); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 17); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_multiple_files(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_outer_classname(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_optimize_for(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_py_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 18); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_message_set_wire_format(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_no_standard_descriptor_accessor(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_input_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_output_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_method(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_leading_comments(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_path(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_span(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_trailing_comments(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_location(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_is_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption_NamePart(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_name_part(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption_NamePart(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_aggregate_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_double_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_identifier_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_negative_int_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_positive_int_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_string_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 7); }
+
+#ifdef __cplusplus
+}; // extern "C"
+#endif
+
+#ifdef __cplusplus
+
+namespace upbdefs {
+namespace google {
+namespace protobuf {
+namespace descriptor {
+inline upb::reffed_ptr<const upb::SymbolTable> SymbolTable() {
+ const upb::SymbolTable* s = upbdefs_google_protobuf_descriptor(&s);
+ return upb::reffed_ptr<const upb::SymbolTable>(s, &s);
+}
+} // namespace descriptor
+} // namespace protobuf
+} // namespace google
+
+#define RETURN_REFFED(type, func) \
+ const type* obj = func(upbdefs::google::protobuf::descriptor::SymbolTable().get()); \
+ return upb::reffed_ptr<const type>(obj);
+
+namespace google {
+namespace protobuf {
+namespace DescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_DescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> enum_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_enum_type) }
+inline upb::reffed_ptr<const upb::FieldDef> extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_extension) }
+inline upb::reffed_ptr<const upb::FieldDef> extension_range() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_extension_range) }
+inline upb::reffed_ptr<const upb::FieldDef> field() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_field) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> nested_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_nested_type) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_options) }
+} // namespace DescriptorProto
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace DescriptorProto {
+namespace ExtensionRange {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange) }
+inline upb::reffed_ptr<const upb::FieldDef> end() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange_end) }
+inline upb::reffed_ptr<const upb::FieldDef> start() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange_start) }
+} // namespace ExtensionRange
+} // namespace DescriptorProto
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace EnumDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_options) }
+inline upb::reffed_ptr<const upb::FieldDef> value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_value) }
+} // namespace EnumDescriptorProto
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace EnumOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> allow_alias() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumOptions_allow_alias) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumOptions_uninterpreted_option) }
+} // namespace EnumOptions
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace EnumValueDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumValueDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> number() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_number) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_options) }
+} // namespace EnumValueDescriptorProto
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace EnumValueOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumValueOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueOptions_uninterpreted_option) }
+} // namespace EnumValueOptions
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace FieldDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FieldDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> default_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_default_value) }
+inline upb::reffed_ptr<const upb::FieldDef> extendee() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_extendee) }
+inline upb::reffed_ptr<const upb::FieldDef> label() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_label) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> number() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_number) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_options) }
+inline upb::reffed_ptr<const upb::FieldDef> type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_type) }
+inline upb::reffed_ptr<const upb::FieldDef> type_name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_type_name) }
+inline upb::reffed_ptr<const upb::EnumDef> Label() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldDescriptorProto_Label) }
+inline upb::reffed_ptr<const upb::EnumDef> Type() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldDescriptorProto_Type) }
+} // namespace FieldDescriptorProto
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace FieldOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FieldOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> ctype() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_ctype) }
+inline upb::reffed_ptr<const upb::FieldDef> deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_deprecated) }
+inline upb::reffed_ptr<const upb::FieldDef> experimental_map_key() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_experimental_map_key) }
+inline upb::reffed_ptr<const upb::FieldDef> lazy() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_lazy) }
+inline upb::reffed_ptr<const upb::FieldDef> packed() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_packed) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_uninterpreted_option) }
+inline upb::reffed_ptr<const upb::FieldDef> weak() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_weak) }
+inline upb::reffed_ptr<const upb::EnumDef> CType() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldOptions_CType) }
+} // namespace FieldOptions
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace FileDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_dependency) }
+inline upb::reffed_ptr<const upb::FieldDef> enum_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_enum_type) }
+inline upb::reffed_ptr<const upb::FieldDef> extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_extension) }
+inline upb::reffed_ptr<const upb::FieldDef> message_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_message_type) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_options) }
+inline upb::reffed_ptr<const upb::FieldDef> package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_package) }
+inline upb::reffed_ptr<const upb::FieldDef> public_dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_public_dependency) }
+inline upb::reffed_ptr<const upb::FieldDef> service() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_service) }
+inline upb::reffed_ptr<const upb::FieldDef> source_code_info() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_source_code_info) }
+inline upb::reffed_ptr<const upb::FieldDef> weak_dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_weak_dependency) }
+} // namespace FileDescriptorProto
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace FileDescriptorSet {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileDescriptorSet) }
+inline upb::reffed_ptr<const upb::FieldDef> file() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorSet_file) }
+} // namespace FileDescriptorSet
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace FileOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> cc_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_cc_generic_services) }
+inline upb::reffed_ptr<const upb::FieldDef> go_package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_go_package) }
+inline upb::reffed_ptr<const upb::FieldDef> java_generate_equals_and_hash() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_generate_equals_and_hash) }
+inline upb::reffed_ptr<const upb::FieldDef> java_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_generic_services) }
+inline upb::reffed_ptr<const upb::FieldDef> java_multiple_files() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_multiple_files) }
+inline upb::reffed_ptr<const upb::FieldDef> java_outer_classname() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_outer_classname) }
+inline upb::reffed_ptr<const upb::FieldDef> java_package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_package) }
+inline upb::reffed_ptr<const upb::FieldDef> optimize_for() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_optimize_for) }
+inline upb::reffed_ptr<const upb::FieldDef> py_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_py_generic_services) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_uninterpreted_option) }
+inline upb::reffed_ptr<const upb::EnumDef> OptimizeMode() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FileOptions_OptimizeMode) }
+} // namespace FileOptions
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace MessageOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MessageOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> message_set_wire_format() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_message_set_wire_format) }
+inline upb::reffed_ptr<const upb::FieldDef> no_standard_descriptor_accessor() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_no_standard_descriptor_accessor) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_uninterpreted_option) }
+} // namespace MessageOptions
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace MethodDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MethodDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> input_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_input_type) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_options) }
+inline upb::reffed_ptr<const upb::FieldDef> output_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_output_type) }
+} // namespace MethodDescriptorProto
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace MethodOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MethodOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodOptions_uninterpreted_option) }
+} // namespace MethodOptions
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace ServiceDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_ServiceDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> method() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_method) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_options) }
+} // namespace ServiceDescriptorProto
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace ServiceOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_ServiceOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceOptions_uninterpreted_option) }
+} // namespace ServiceOptions
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace SourceCodeInfo {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_SourceCodeInfo) }
+inline upb::reffed_ptr<const upb::FieldDef> location() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_location) }
+} // namespace SourceCodeInfo
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace SourceCodeInfo {
+namespace Location {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_SourceCodeInfo_Location) }
+inline upb::reffed_ptr<const upb::FieldDef> leading_comments() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_leading_comments) }
+inline upb::reffed_ptr<const upb::FieldDef> path() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_path) }
+inline upb::reffed_ptr<const upb::FieldDef> span() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_span) }
+inline upb::reffed_ptr<const upb::FieldDef> trailing_comments() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_trailing_comments) }
+} // namespace Location
+} // namespace SourceCodeInfo
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace UninterpretedOption {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_UninterpretedOption) }
+inline upb::reffed_ptr<const upb::FieldDef> aggregate_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_aggregate_value) }
+inline upb::reffed_ptr<const upb::FieldDef> double_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_double_value) }
+inline upb::reffed_ptr<const upb::FieldDef> identifier_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_identifier_value) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_name) }
+inline upb::reffed_ptr<const upb::FieldDef> negative_int_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_negative_int_value) }
+inline upb::reffed_ptr<const upb::FieldDef> positive_int_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_positive_int_value) }
+inline upb::reffed_ptr<const upb::FieldDef> string_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_string_value) }
+} // namespace UninterpretedOption
+} // namespace protobuf
+} // namespace google
+
+namespace google {
+namespace protobuf {
+namespace UninterpretedOption {
+namespace NamePart {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_UninterpretedOption_NamePart) }
+inline upb::reffed_ptr<const upb::FieldDef> is_extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_NamePart_is_extension) }
+inline upb::reffed_ptr<const upb::FieldDef> name_part() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_NamePart_name_part) }
+} // namespace NamePart
+} // namespace UninterpretedOption
+} // namespace protobuf
+} // namespace google
+
+} // namespace upbdefs
+
+
+#undef RETURN_REFFED
+#endif // __cplusplus
+
+#endif // GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2010-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * A upb_handlers is like a virtual table for a upb_msgdef. Each field of the
+ * message can have associated functions that will be called when we are
+ * parsing or visiting a stream of data. This is similar to how handlers work
+ * in SAX (the Simple API for XML).
+ *
+ * The handlers have no idea where the data is coming from, so a single set of
+ * handlers could be used with two completely different data sources (for
+ * example, a parser and a visitor over in-memory objects). This decoupling is
+ * the most important feature of upb, because it allows parsers and serializers
+ * to be highly reusable.
+ *
+ * This is a mixed C/C++ interface that offers a full API to both languages.
+ * See the top-level README for more information.
+ */
+
+#ifndef UPB_HANDLERS_H
+#define UPB_HANDLERS_H
+
+
+#ifdef __cplusplus
+namespace upb {
+class BufferHandle;
+class BytesHandler;
+class HandlerAttributes;
+class Handlers;
+template <class T> class Handler;
+template <class T> struct CanonicalType;
+} // namespace upb
+#endif
+
+UPB_DECLARE_TYPE(upb::BufferHandle, upb_bufhandle);
+UPB_DECLARE_TYPE(upb::BytesHandler, upb_byteshandler);
+UPB_DECLARE_TYPE(upb::HandlerAttributes, upb_handlerattr);
+UPB_DECLARE_TYPE(upb::Handlers, upb_handlers);
+
+// The maximum depth that the handler graph can have. This is a resource limit
+// for the C stack since we sometimes need to recursively traverse the graph.
+// Cycles are ok; the traversal will stop when it detects a cycle, but we must
+// hit the cycle before the maximum depth is reached.
+//
+// If having a single static limit is too inflexible, we can add another variant
+// of Handlers::Freeze that allows specifying this as a parameter.
+#define UPB_MAX_HANDLER_DEPTH 64
+
+// All the different types of handlers that can be registered.
+// Only needed for the advanced functions in upb::Handlers.
+typedef enum {
+ UPB_HANDLER_INT32,
+ UPB_HANDLER_INT64,
+ UPB_HANDLER_UINT32,
+ UPB_HANDLER_UINT64,
+ UPB_HANDLER_FLOAT,
+ UPB_HANDLER_DOUBLE,
+ UPB_HANDLER_BOOL,
+ UPB_HANDLER_STARTSTR,
+ UPB_HANDLER_STRING,
+ UPB_HANDLER_ENDSTR,
+ UPB_HANDLER_STARTSUBMSG,
+ UPB_HANDLER_ENDSUBMSG,
+ UPB_HANDLER_STARTSEQ,
+ UPB_HANDLER_ENDSEQ,
+} upb_handlertype_t;
+
+#define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1)
+
+#define UPB_BREAK NULL
+
+// A convenient definition for when no closure is needed.
+extern char _upb_noclosure;
+#define UPB_NO_CLOSURE &_upb_noclosure
+
+// A selector refers to a specific field handler in the Handlers object
+// (for example: the STARTSUBMSG handler for field "field15").
+typedef int32_t upb_selector_t;
+
+UPB_BEGIN_EXTERN_C
+
+// Forward-declares for C inline accessors. We need to declare these here
+// so we can "friend" them in the class declarations in C++.
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+ upb_selector_t s);
+UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr);
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+ upb_selector_t s);
+
+UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h);
+UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj,
+ const void *type);
+UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf,
+ size_t ofs);
+UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h);
+UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h);
+UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h);
+
+UPB_END_EXTERN_C
+
+
+// Static selectors for upb::Handlers.
+#define UPB_STARTMSG_SELECTOR 0
+#define UPB_ENDMSG_SELECTOR 1
+#define UPB_STATIC_SELECTOR_COUNT 2
+
+// Static selectors for upb::BytesHandler.
+#define UPB_STARTSTR_SELECTOR 0
+#define UPB_STRING_SELECTOR 1
+#define UPB_ENDSTR_SELECTOR 2
+
+typedef void upb_handlerfree(void *d);
+
+// A set of attributes that accompanies a handler's function pointer.
+UPB_DEFINE_CLASS0(upb::HandlerAttributes,
+ public:
+ HandlerAttributes();
+ ~HandlerAttributes();
+
+ // Sets the handler data that will be passed as the second parameter of the
+ // handler. To free this pointer when the handlers are freed, call
+ // Handlers::AddCleanup().
+ bool SetHandlerData(const void *handler_data);
+ const void* handler_data() const;
+
+ // Use this to specify the type of the closure. This will be checked against
+ // all other closure types for handler that use the same closure.
+ // Registration will fail if this does not match all other non-NULL closure
+ // types.
+ bool SetClosureType(const void *closure_type);
+ const void* closure_type() const;
+
+ // Use this to specify the type of the returned closure. Only used for
+ // Start*{String,SubMessage,Sequence} handlers. This must match the closure
+ // type of any handlers that use it (for example, the StringBuf handler must
+ // match the closure returned from StartString).
+ bool SetReturnClosureType(const void *return_closure_type);
+ const void* return_closure_type() const;
+
+ // Set to indicate that the handler always returns "ok" (either "true" or a
+ // non-NULL closure). This is a hint that can allow code generators to
+ // generate more efficient code.
+ bool SetAlwaysOk(bool always_ok);
+ bool always_ok() const;
+
+ private:
+ friend UPB_INLINE const void * ::upb_handlerattr_handlerdata(
+ const upb_handlerattr *attr);
+,
+UPB_DEFINE_STRUCT0(upb_handlerattr,
+ const void *handler_data_;
+ const void *closure_type_;
+ const void *return_closure_type_;
+ bool alwaysok_;
+));
+
+#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL, NULL, false}
+
+typedef struct {
+ upb_func *func;
+ // It is wasteful to include the entire attributes here:
+ //
+ // * Some of the information is redundant (like storing the closure type
+ // separately for each handler that must match).
+ // * Some of the info is only needed prior to freeze() (like closure types).
+ // * alignment padding wastes a lot of space for alwaysok_.
+ //
+ // If/when the size and locality of handlers is an issue, we can optimize this
+ // not to store the entire attr like this. We do not expose the table's
+ // layout to allow this optimization in the future.
+ upb_handlerattr attr;
+} upb_handlers_tabent;
+
+// Extra information about a buffer that is passed to a StringBuf handler.
+// TODO(haberman): allow the handle to be pinned so that it will outlive
+// the handler invocation.
+UPB_DEFINE_CLASS0(upb::BufferHandle,
+ public:
+ BufferHandle();
+ ~BufferHandle();
+
+ // The beginning of the buffer. This may be different than the pointer
+ // passed to a StringBuf handler because the handler may receive data
+ // that is from the middle or end of a larger buffer.
+ const char* buffer() const;
+
+ // The offset within the attached object where this buffer begins. Only
+ // meaningful if there is an attached object.
+ size_t object_offset() const;
+
+ // Note that object_offset is the offset of "buf" within the attached object.
+ void SetBuffer(const char* buf, size_t object_offset);
+
+ // The BufferHandle can have an "attached object", which can be used to
+ // tunnel through a pointer to the buffer's underlying representation.
+ template <class T>
+ void SetAttachedObject(const T* obj);
+
+ // Returns NULL if the attached object is not of this type.
+ template <class T>
+ const T* GetAttachedObject() const;
+
+ private:
+ friend UPB_INLINE void ::upb_bufhandle_init(upb_bufhandle *h);
+ friend UPB_INLINE void ::upb_bufhandle_setobj(upb_bufhandle *h,
+ const void *obj,
+ const void *type);
+ friend UPB_INLINE void ::upb_bufhandle_setbuf(upb_bufhandle *h,
+ const char *buf, size_t ofs);
+ friend UPB_INLINE const void* ::upb_bufhandle_obj(const upb_bufhandle *h);
+ friend UPB_INLINE const void* ::upb_bufhandle_objtype(
+ const upb_bufhandle *h);
+ friend UPB_INLINE const char* ::upb_bufhandle_buf(const upb_bufhandle *h);
+,
+UPB_DEFINE_STRUCT0(upb_bufhandle,
+ const char *buf_;
+ const void *obj_;
+ const void *objtype_;
+ size_t objofs_;
+));
+
+// A upb::Handlers object represents the set of handlers associated with a
+// message in the graph of messages. You can think of it as a big virtual
+// table with functions corresponding to all the events that can fire while
+// parsing or visiting a message of a specific type.
+//
+// Any handlers that are not set behave as if they had successfully consumed
+// the value. Any unset Start* handlers will propagate their closure to the
+// inner frame.
+//
+// The easiest way to create the *Handler objects needed by the Set* methods is
+// with the UpbBind() and UpbMakeHandler() macros; see below.
+UPB_DEFINE_CLASS1(upb::Handlers, upb::RefCounted,
+ public:
+ typedef upb_selector_t Selector;
+ typedef upb_handlertype_t Type;
+
+ typedef Handler<void *(*)(void *, const void *)> StartFieldHandler;
+ typedef Handler<bool (*)(void *, const void *)> EndFieldHandler;
+ typedef Handler<bool (*)(void *, const void *)> StartMessageHandler;
+ typedef Handler<bool (*)(void *, const void *, Status*)> EndMessageHandler;
+ typedef Handler<void *(*)(void *, const void *, size_t)> StartStringHandler;
+ typedef Handler<size_t (*)(void *, const void *, const char *, size_t,
+ const BufferHandle *)> StringHandler;
+
+ template <class T> struct ValueHandler {
+ typedef Handler<bool(*)(void *, const void *, T)> H;
+ };
+
+ typedef ValueHandler<int32_t>::H Int32Handler;
+ typedef ValueHandler<int64_t>::H Int64Handler;
+ typedef ValueHandler<uint32_t>::H UInt32Handler;
+ typedef ValueHandler<uint64_t>::H UInt64Handler;
+ typedef ValueHandler<float>::H FloatHandler;
+ typedef ValueHandler<double>::H DoubleHandler;
+ typedef ValueHandler<bool>::H BoolHandler;
+
+ // Any function pointer can be converted to this and converted back to its
+ // correct type.
+ typedef void GenericFunction();
+
+ typedef void HandlersCallback(const void *closure, upb_handlers *h);
+
+ // Returns a new handlers object for the given frozen msgdef.
+ // Returns NULL if memory allocation failed.
+ static reffed_ptr<Handlers> New(const MessageDef *m);
+
+ // Convenience function for registering a graph of handlers that mirrors the
+ // graph of msgdefs for some message. For "m" and all its children a new set
+ // of handlers will be created and the given callback will be invoked,
+ // allowing the client to register handlers for this message. Note that any
+ // subhandlers set by the callback will be overwritten.
+ static reffed_ptr<const Handlers> NewFrozen(const MessageDef *m,
+ HandlersCallback *callback,
+ const void *closure);
+
+ // Functionality from upb::RefCounted.
+ bool IsFrozen() const;
+ void Ref(const void* owner) const;
+ void Unref(const void* owner) const;
+ void DonateRef(const void *from, const void *to) const;
+ void CheckRef(const void *owner) const;
+
+ // All handler registration functions return bool to indicate success or
+ // failure; details about failures are stored in this status object. If a
+ // failure does occur, it must be cleared before the Handlers are frozen,
+ // otherwise the freeze() operation will fail. The functions may *only* be
+ // used while the Handlers are mutable.
+ const Status* status();
+ void ClearError();
+
+ // Call to freeze these Handlers. Requires that any SubHandlers are already
+ // frozen. For cycles, you must use the static version below and freeze the
+ // whole graph at once.
+ bool Freeze(Status* s);
+
+ // Freezes the given set of handlers. You may not freeze a handler without
+ // also freezing any handlers they point to.
+ static bool Freeze(Handlers*const* handlers, int n, Status* s);
+ static bool Freeze(const std::vector<Handlers*>& handlers, Status* s);
+
+ // Returns the msgdef associated with this handlers object.
+ const MessageDef* message_def() const;
+
+ // Adds the given pointer and function to the list of cleanup functions that
+ // will be run when these handlers are freed. If this pointer has previously
+ // been registered, the function returns false and does nothing.
+ bool AddCleanup(void *ptr, upb_handlerfree *cleanup);
+
+ // Sets the startmsg handler for the message, which is defined as follows:
+ //
+ // bool startmsg(MyType* closure) {
+ // // Called when the message begins. Returns true if processing should
+ // // continue.
+ // return true;
+ // }
+ bool SetStartMessageHandler(const StartMessageHandler& handler);
+
+ // Sets the endmsg handler for the message, which is defined as follows:
+ //
+ // bool endmsg(MyType* closure, upb_status *status) {
+ // // Called when processing of this message ends, whether in success or
+ // // failure. "status" indicates the final status of processing, and
+ // // can also be modified in-place to update the final status.
+ // }
+ bool SetEndMessageHandler(const EndMessageHandler& handler);
+
+ // Sets the value handler for the given field, which is defined as follows
+ // (this is for an int32 field; other field types will pass their native
+ // C/C++ type for "val"):
+ //
+ // bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) {
+ // // Called when the field's value is encountered. "d" contains
+ // // whatever data was bound to this field when it was registered.
+ // // Returns true if processing should continue.
+ // return true;
+ // }
+ //
+ // handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...)));
+ //
+ // The value type must exactly match f->type().
+ // For example, a handler that takes an int32_t parameter may only be used for
+ // fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM.
+ //
+ // Returns false if the handler failed to register; in this case the cleanup
+ // handler (if any) will be called immediately.
+ bool SetInt32Handler (const FieldDef* f, const Int32Handler& h);
+ bool SetInt64Handler (const FieldDef* f, const Int64Handler& h);
+ bool SetUInt32Handler(const FieldDef* f, const UInt32Handler& h);
+ bool SetUInt64Handler(const FieldDef* f, const UInt64Handler& h);
+ bool SetFloatHandler (const FieldDef* f, const FloatHandler& h);
+ bool SetDoubleHandler(const FieldDef* f, const DoubleHandler& h);
+ bool SetBoolHandler (const FieldDef* f, const BoolHandler& h);
+
+ // Like the previous, but templated on the type on the value (ie. int32).
+ // This is mostly useful to call from other templates. To call this you must
+ // specify the template parameter explicitly, ie:
+ // h->SetValueHandler<T>(f, UpbBind(MyHandler<T>, MyData));
+ template <class T>
+ bool SetValueHandler(
+ const FieldDef *f,
+ const typename ValueHandler<typename CanonicalType<T>::Type>::H& handler);
+
+ // Sets handlers for a string field, which are defined as follows:
+ //
+ // MySubClosure* startstr(MyClosure* c, const MyHandlerData* d,
+ // size_t size_hint) {
+ // // Called when a string value begins. The return value indicates the
+ // // closure for the string. "size_hint" indicates the size of the
+ // // string if it is known, however if the string is length-delimited
+ // // and the end-of-string is not available size_hint will be zero.
+ // // This case is indistinguishable from the case where the size is
+ // // known to be zero.
+ // //
+ // // TODO(haberman): is it important to distinguish these cases?
+ // // If we had ssize_t as a type we could make -1 "unknown", but
+ // // ssize_t is POSIX (not ANSI) and therefore less portable.
+ // // In practice I suspect it won't be important to distinguish.
+ // return closure;
+ // }
+ //
+ // size_t str(MyClosure* closure, const MyHandlerData* d,
+ // const char *str, size_t len) {
+ // // Called for each buffer of string data; the multiple physical buffers
+ // // are all part of the same logical string. The return value indicates
+ // // how many bytes were consumed. If this number is less than "len",
+ // // this will also indicate that processing should be halted for now,
+ // // like returning false or UPB_BREAK from any other callback. If
+ // // number is greater than "len", the excess bytes will be skipped over
+ // // and not passed to the callback.
+ // return len;
+ // }
+ //
+ // bool endstr(MyClosure* c, const MyHandlerData* d) {
+ // // Called when a string value ends. Return value indicates whether
+ // // processing should continue.
+ // return true;
+ // }
+ bool SetStartStringHandler(const FieldDef* f, const StartStringHandler& h);
+ bool SetStringHandler(const FieldDef* f, const StringHandler& h);
+ bool SetEndStringHandler(const FieldDef* f, const EndFieldHandler& h);
+
+ // Sets the startseq handler, which is defined as follows:
+ //
+ // MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) {
+ // // Called when a sequence (repeated field) begins. The returned
+ // // pointer indicates the closure for the sequence (or UPB_BREAK
+ // // to interrupt processing).
+ // return closure;
+ // }
+ //
+ // h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...)));
+ //
+ // Returns "false" if "f" does not belong to this message or is not a
+ // repeated field.
+ bool SetStartSequenceHandler(const FieldDef* f, const StartFieldHandler& h);
+
+ // Sets the startsubmsg handler for the given field, which is defined as
+ // follows:
+ //
+ // MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) {
+ // // Called when a submessage begins. The returned pointer indicates the
+ // // closure for the sequence (or UPB_BREAK to interrupt processing).
+ // return closure;
+ // }
+ //
+ // h->SetStartSubMessageHandler(f, UpbBind(startsubmsg,
+ // new MyHandlerData(...)));
+ //
+ // Returns "false" if "f" does not belong to this message or is not a
+ // submessage/group field.
+ bool SetStartSubMessageHandler(const FieldDef* f, const StartFieldHandler& h);
+
+ // Sets the endsubmsg handler for the given field, which is defined as
+ // follows:
+ //
+ // bool endsubmsg(MyClosure* c, const MyHandlerData* d) {
+ // // Called when a submessage ends. Returns true to continue processing.
+ // return true;
+ // }
+ //
+ // Returns "false" if "f" does not belong to this message or is not a
+ // submessage/group field.
+ bool SetEndSubMessageHandler(const FieldDef *f, const EndFieldHandler &h);
+
+ // Starts the endsubseq handler for the given field, which is defined as
+ // follows:
+ //
+ // bool endseq(MyClosure* c, const MyHandlerData* d) {
+ // // Called when a sequence ends. Returns true continue processing.
+ // return true;
+ // }
+ //
+ // Returns "false" if "f" does not belong to this message or is not a
+ // repeated field.
+ bool SetEndSequenceHandler(const FieldDef* f, const EndFieldHandler& h);
+
+ // Sets or gets the object that specifies handlers for the given field, which
+ // must be a submessage or group. Returns NULL if no handlers are set.
+ bool SetSubHandlers(const FieldDef* f, const Handlers* sub);
+ const Handlers* GetSubHandlers(const FieldDef* f) const;
+
+ // Equivalent to GetSubHandlers, but takes the STARTSUBMSG selector for the
+ // field.
+ const Handlers* GetSubHandlers(Selector startsubmsg) const;
+
+ // A selector refers to a specific field handler in the Handlers object
+ // (for example: the STARTSUBMSG handler for field "field15").
+ // On success, returns true and stores the selector in "s".
+ // If the FieldDef or Type are invalid, returns false.
+ // The returned selector is ONLY valid for Handlers whose MessageDef
+ // contains this FieldDef.
+ static bool GetSelector(const FieldDef* f, Type type, Selector* s);
+
+ // Given a START selector of any kind, returns the corresponding END selector.
+ static Selector GetEndSelector(Selector start_selector);
+
+ // Returns the function pointer for this handler. It is the client's
+ // responsibility to cast to the correct function type before calling it.
+ GenericFunction* GetHandler(Selector selector);
+
+ // Sets the given attributes to the attributes for this selector.
+ bool GetAttributes(Selector selector, HandlerAttributes* attr);
+
+ // Returns the handler data that was registered with this handler.
+ const void* GetHandlerData(Selector selector);
+
+ // Could add any of the following functions as-needed, with some minor
+ // implementation changes:
+ //
+ // const FieldDef* GetFieldDef(Selector selector);
+ // static bool IsSequence(Selector selector);
+
+ private:
+ UPB_DISALLOW_POD_OPS(Handlers, upb::Handlers);
+
+ friend UPB_INLINE GenericFunction *::upb_handlers_gethandler(
+ const upb_handlers *h, upb_selector_t s);
+ friend UPB_INLINE const void *::upb_handlers_gethandlerdata(
+ const upb_handlers *h, upb_selector_t s);
+
+,
+UPB_DEFINE_STRUCT(upb_handlers, upb_refcounted,
+ const upb_msgdef *msg;
+ const upb_handlers **sub;
+ const void *top_closure_type;
+ upb_inttable cleanup_;
+ upb_status status_; // Used only when mutable.
+ upb_handlers_tabent table[1]; // Dynamically-sized field handler array.
+));
+
+
+#ifdef __cplusplus
+
+namespace upb {
+
+// Convenience macros for creating a Handler object that is wrapped with a
+// type-safe wrapper function that converts the "void*" parameters/returns
+// of the underlying C API into nice C++ function.
+//
+// Sample usage:
+// void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) {
+// // do stuff ...
+// }
+//
+// // Handler that doesn't need any data bound to it.
+// void OnValue2(MyClosure* c, int32_t val) {
+// // do stuff ...
+// }
+//
+// // Handler that returns bool so it can return failure if necessary.
+// bool OnValue3(MyClosure* c, int32_t val) {
+// // do stuff ...
+// return ok;
+// }
+//
+// // Member function handler.
+// class MyClosure {
+// public:
+// void OnValue(int32_t val) {
+// // do stuff ...
+// }
+// };
+//
+// // Takes ownership of the MyHandlerData.
+// handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...)));
+// handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2));
+// handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3));
+// handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue));
+
+#ifdef UPB_CXX11
+
+// In C++11, the "template" disambiguator can appear even outside templates,
+// so all calls can safely use this pair of macros.
+
+#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc<f>()
+
+// We have to be careful to only evaluate "d" once.
+#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
+
+#else
+
+// Prior to C++11, the "template" disambiguator may only appear inside a
+// template, so the regular macro must not use "template"
+
+#define UpbMakeHandler(f) upb::MatchFunc(f).GetFunc<f>()
+
+#define UpbBind(f, d) upb::MatchFunc(f).GetFunc<f>((d))
+
+#endif // UPB_CXX11
+
+// This macro must be used in C++98 for calls from inside a template. But we
+// define this variant in all cases; code that wants to be compatible with both
+// C++98 and C++11 should always use this macro when calling from a template.
+#define UpbMakeHandlerT(f) upb::MatchFunc(f).template GetFunc<f>()
+
+// We have to be careful to only evaluate "d" once.
+#define UpbBindT(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
+
+// Handler: a struct that contains the (handler, data, deleter) tuple that is
+// used to register all handlers. Users can Make() these directly but it's
+// more convenient to use the UpbMakeHandler/UpbBind macros above.
+template <class T> class Handler {
+ public:
+ // The underlying, handler function signature that upb uses internally.
+ typedef T FuncPtr;
+
+ // Intentionally implicit.
+ template <class F> Handler(F func);
+ ~Handler();
+
+ private:
+ void AddCleanup(Handlers* h) const {
+ if (cleanup_func_) {
+ bool ok = h->AddCleanup(cleanup_data_, cleanup_func_);
+ UPB_ASSERT_VAR(ok, ok);
+ }
+ }
+
+ UPB_DISALLOW_COPY_AND_ASSIGN(Handler);
+ friend class Handlers;
+ FuncPtr handler_;
+ mutable HandlerAttributes attr_;
+ mutable bool registered_;
+ void *cleanup_data_;
+ upb_handlerfree *cleanup_func_;
+};
+
+} // namespace upb
+
+#endif // __cplusplus
+
+UPB_BEGIN_EXTERN_C
+
+// Native C API.
+
+// Handler function typedefs.
+typedef bool upb_startmsg_handlerfunc(void *c, const void*);
+typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status);
+typedef void* upb_startfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_endfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val);
+typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val);
+typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val);
+typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val);
+typedef bool upb_float_handlerfunc(void *c, const void *hd, float val);
+typedef bool upb_double_handlerfunc(void *c, const void *hd, double val);
+typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val);
+typedef void *upb_startstr_handlerfunc(void *c, const void *hd,
+ size_t size_hint);
+typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
+ size_t n, const upb_bufhandle* handle);
+
+// upb_bufhandle
+size_t upb_bufhandle_objofs(const upb_bufhandle *h);
+
+// upb_handlerattr
+void upb_handlerattr_init(upb_handlerattr *attr);
+void upb_handlerattr_uninit(upb_handlerattr *attr);
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd);
+bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type);
+const void *upb_handlerattr_closuretype(const upb_handlerattr *attr);
+bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr,
+ const void *type);
+const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr);
+bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok);
+bool upb_handlerattr_alwaysok(const upb_handlerattr *attr);
+
+UPB_INLINE const void *upb_handlerattr_handlerdata(
+ const upb_handlerattr *attr) {
+ return attr->handler_data_;
+}
+
+// upb_handlers
+typedef void upb_handlers_callback(const void *closure, upb_handlers *h);
+upb_handlers *upb_handlers_new(const upb_msgdef *m,
+ const void *owner);
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+ const void *owner,
+ upb_handlers_callback *callback,
+ const void *closure);
+bool upb_handlers_isfrozen(const upb_handlers *h);
+void upb_handlers_ref(const upb_handlers *h, const void *owner);
+void upb_handlers_unref(const upb_handlers *h, const void *owner);
+void upb_handlers_donateref(const upb_handlers *h, const void *from,
+ const void *to);
+void upb_handlers_checkref(const upb_handlers *h, const void *owner);
+
+const upb_status *upb_handlers_status(upb_handlers *h);
+void upb_handlers_clearerr(upb_handlers *h);
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
+bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree);
+
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f,
+ upb_int32_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f,
+ upb_int64_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f,
+ upb_uint32_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f,
+ upb_uint64_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f,
+ upb_float_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f,
+ upb_double_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f,
+ upb_bool_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f,
+ upb_startstr_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f,
+ upb_string_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f,
+ upb_endfield_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f,
+ upb_startfield_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f,
+ upb_startfield_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f,
+ upb_endfield_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f,
+ upb_endfield_handlerfunc *func,
+ upb_handlerattr *attr);
+
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+ const upb_handlers *sub);
+const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
+ const upb_fielddef *f);
+const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
+ upb_selector_t sel);
+
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+ upb_selector_t s) {
+ return (upb_func *)h->table[s].func;
+}
+
+bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s,
+ upb_handlerattr *attr);
+
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+ upb_selector_t s) {
+ return upb_handlerattr_handlerdata(&h->table[s].attr);
+}
+
+// Handler types for single fields.
+// Right now we only have one for TYPE_BYTES but ones for other types
+// should follow.
+//
+// These follow the same handlers protocol for fields of a message.
+UPB_DEFINE_CLASS0(upb::BytesHandler,
+ public:
+ BytesHandler();
+ ~BytesHandler();
+,
+UPB_DEFINE_STRUCT0(upb_byteshandler,
+ upb_handlers_tabent table[3];
+));
+
+void upb_byteshandler_init(upb_byteshandler *h);
+void upb_byteshandler_uninit(upb_byteshandler *h);
+
+// Caller must ensure that "d" outlives the handlers.
+// TODO(haberman): support handlerfree function for the data.
+// TODO(haberman): should this have a "freeze" operation? It's not necessary
+// for memory management, but could be useful to force immutability and provide
+// a convenient moment to verify that all registration succeeded.
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+ upb_startstr_handlerfunc *func, void *d);
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+ upb_string_handlerfunc *func, void *d);
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+ upb_endfield_handlerfunc *func, void *d);
+
+// "Static" methods
+bool upb_handlers_freeze(upb_handlers *const *handlers, int n, upb_status *s);
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f);
+bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
+ upb_selector_t *s);
+UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) {
+ return start + 1;
+}
+
+// Internal-only.
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f);
+uint32_t upb_handlers_selectorcount(const upb_fielddef *f);
+
+UPB_END_EXTERN_C
+
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * Inline definitions for handlers.h, which are particularly long and a bit
+ * tricky.
+ */
+
+#ifndef UPB_HANDLERS_INL_H_
+#define UPB_HANDLERS_INL_H_
+
+#include <limits.h>
+
+// Type detection and typedefs for integer types.
+// For platforms where there are multiple 32-bit or 64-bit types, we need to be
+// able to enumerate them so we can properly create overloads for all variants.
+//
+// If any platform existed where there were three integer types with the same
+// size, this would have to become more complicated. For example, short, int,
+// and long could all be 32-bits. Even more diabolically, short, int, long,
+// and long long could all be 64 bits and still be standard-compliant.
+// However, few platforms are this strange, and it's unlikely that upb will be
+// used on the strangest ones.
+
+// Can't count on stdint.h limits like INT32_MAX, because in C++ these are
+// only defined when __STDC_LIMIT_MACROS are defined before the *first* include
+// of stdint.h. We can't guarantee that someone else didn't include these first
+// without defining __STDC_LIMIT_MACROS.
+#define UPB_INT32_MAX 0x7fffffffLL
+#define UPB_INT32_MIN (-UPB_INT32_MAX - 1)
+#define UPB_INT64_MAX 0x7fffffffffffffffLL
+#define UPB_INT64_MIN (-UPB_INT64_MAX - 1)
+
+#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN
+#define UPB_INT_IS_32BITS 1
+#endif
+
+#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN
+#define UPB_LONG_IS_32BITS 1
+#endif
+
+#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN
+#define UPB_LONG_IS_64BITS 1
+#endif
+
+#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN
+#define UPB_LLONG_IS_64BITS 1
+#endif
+
+// We use macros instead of typedefs so we can undefine them later and avoid
+// leaking them outside this header file.
+#if UPB_INT_IS_32BITS
+#define UPB_INT32_T int
+#define UPB_UINT32_T unsigned int
+
+#if UPB_LONG_IS_32BITS
+#define UPB_TWO_32BIT_TYPES 1
+#define UPB_INT32ALT_T long
+#define UPB_UINT32ALT_T unsigned long
+#endif // UPB_LONG_IS_32BITS
+
+#elif UPB_LONG_IS_32BITS // && !UPB_INT_IS_32BITS
+#define UPB_INT32_T long
+#define UPB_UINT32_T unsigned long
+#endif // UPB_INT_IS_32BITS
+
+
+#if UPB_LONG_IS_64BITS
+#define UPB_INT64_T long
+#define UPB_UINT64_T unsigned long
+
+#if UPB_LLONG_IS_64BITS
+#define UPB_TWO_64BIT_TYPES 1
+#define UPB_INT64ALT_T long long
+#define UPB_UINT64ALT_T unsigned long long
+#endif // UPB_LLONG_IS_64BITS
+
+#elif UPB_LLONG_IS_64BITS // && !UPB_LONG_IS_64BITS
+#define UPB_INT64_T long long
+#define UPB_UINT64_T unsigned long long
+#endif // UPB_LONG_IS_64BITS
+
+#undef UPB_INT32_MAX
+#undef UPB_INT32_MIN
+#undef UPB_INT64_MAX
+#undef UPB_INT64_MIN
+#undef UPB_INT_IS_32BITS
+#undef UPB_LONG_IS_32BITS
+#undef UPB_LONG_IS_64BITS
+#undef UPB_LLONG_IS_64BITS
+
+// C inline methods.
+
+// upb_bufhandle
+UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h) {
+ h->obj_ = NULL;
+ h->objtype_ = NULL;
+ h->buf_ = NULL;
+ h->objofs_ = 0;
+}
+UPB_INLINE void upb_bufhandle_uninit(upb_bufhandle *h) {
+ UPB_UNUSED(h);
+}
+UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj,
+ const void *type) {
+ h->obj_ = obj;
+ h->objtype_ = type;
+}
+UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf,
+ size_t ofs) {
+ h->buf_ = buf;
+ h->objofs_ = ofs;
+}
+UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h) {
+ return h->obj_;
+}
+UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h) {
+ return h->objtype_;
+}
+UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h) {
+ return h->buf_;
+}
+
+
+#ifdef __cplusplus
+
+namespace upb {
+
+typedef void CleanupFunc(void *ptr);
+
+// Template to remove "const" from "const T*" and just return "T*".
+//
+// We define a nonsense default because otherwise it will fail to instantiate as
+// a function parameter type even in cases where we don't expect any caller to
+// actually match the overload.
+class CouldntRemoveConst {};
+template <class T> struct remove_constptr { typedef CouldntRemoveConst type; };
+template <class T> struct remove_constptr<const T *> { typedef T *type; };
+
+// Template that we use below to remove a template specialization from
+// consideration if it matches a specific type.
+template <class T, class U> struct disable_if_same { typedef void Type; };
+template <class T> struct disable_if_same<T, T> {};
+
+template <class T> void DeletePointer(void *p) { delete static_cast<T>(p); }
+
+template <class T1, class T2>
+struct FirstUnlessVoid {
+ typedef T1 value;
+};
+
+template <class T2>
+struct FirstUnlessVoid<void, T2> {
+ typedef T2 value;
+};
+
+template<class T, class U>
+struct is_same {
+ static bool value;
+};
+
+template<class T>
+struct is_same<T, T> {
+ static bool value;
+};
+
+template<class T, class U>
+bool is_same<T, U>::value = false;
+
+template<class T>
+bool is_same<T, T>::value = true;
+
+// FuncInfo ////////////////////////////////////////////////////////////////////
+
+// Info about the user's original, pre-wrapped function.
+template <class C, class R = void>
+struct FuncInfo {
+ // The type of the closure that the function takes (its first param).
+ typedef C Closure;
+
+ // The return type.
+ typedef R Return;
+};
+
+// Func ////////////////////////////////////////////////////////////////////////
+
+// Func1, Func2, Func3: Template classes representing a function and its
+// signature.
+//
+// Since the function is a template parameter, calling the function can be
+// inlined at compile-time and does not require a function pointer at runtime.
+// These functions are not bound to a handler data so have no data or cleanup
+// handler.
+struct UnboundFunc {
+ CleanupFunc *GetCleanup() { return NULL; }
+ void *GetData() { return NULL; }
+};
+
+template <class R, class P1, R F(P1), class I>
+struct Func1 : public UnboundFunc {
+ typedef R Return;
+ typedef I FuncInfo;
+ static R Call(P1 p1) { return F(p1); }
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I>
+struct Func2 : public UnboundFunc {
+ typedef R Return;
+ typedef I FuncInfo;
+ static R Call(P1 p1, P2 p2) { return F(p1, p2); }
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
+struct Func3 : public UnboundFunc {
+ typedef R Return;
+ typedef I FuncInfo;
+ static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); }
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+ class I>
+struct Func4 : public UnboundFunc {
+ typedef R Return;
+ typedef I FuncInfo;
+ static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); }
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+ R F(P1, P2, P3, P4, P5), class I>
+struct Func5 : public UnboundFunc {
+ typedef R Return;
+ typedef I FuncInfo;
+ static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+ return F(p1, p2, p3, p4, p5);
+ }
+};
+
+// BoundFunc ///////////////////////////////////////////////////////////////////
+
+// BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that
+// shall be bound to the function's second parameter.
+//
+// Note that the second parameter is a const pointer, but our stored bound value
+// is non-const so we can free it when the handlers are destroyed.
+template <class T>
+struct BoundFunc {
+ typedef typename remove_constptr<T>::type MutableP2;
+ explicit BoundFunc(MutableP2 data_) : data(data_) {}
+ CleanupFunc *GetCleanup() { return &DeletePointer<MutableP2>; }
+ MutableP2 GetData() { return data; }
+ MutableP2 data;
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I>
+struct BoundFunc2 : public BoundFunc<P2> {
+ typedef BoundFunc<P2> Base;
+ typedef I FuncInfo;
+ explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
+struct BoundFunc3 : public BoundFunc<P2> {
+ typedef BoundFunc<P2> Base;
+ typedef I FuncInfo;
+ explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+ class I>
+struct BoundFunc4 : public BoundFunc<P2> {
+ typedef BoundFunc<P2> Base;
+ typedef I FuncInfo;
+ explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+ R F(P1, P2, P3, P4, P5), class I>
+struct BoundFunc5 : public BoundFunc<P2> {
+ typedef BoundFunc<P2> Base;
+ typedef I FuncInfo;
+ explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+// FuncSig /////////////////////////////////////////////////////////////////////
+
+// FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function
+// *signature*, but without a specific function attached.
+//
+// These classes contain member functions that can be invoked with a
+// specific function to return a Func/BoundFunc class.
+template <class R, class P1>
+struct FuncSig1 {
+ template <R F(P1)>
+ Func1<R, P1, F, FuncInfo<P1, R> > GetFunc() {
+ return Func1<R, P1, F, FuncInfo<P1, R> >();
+ }
+};
+
+template <class R, class P1, class P2>
+struct FuncSig2 {
+ template <R F(P1, P2)>
+ Func2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc() {
+ return Func2<R, P1, P2, F, FuncInfo<P1, R> >();
+ }
+
+ template <R F(P1, P2)>
+ BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc(
+ typename remove_constptr<P2>::type param2) {
+ return BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> >(param2);
+ }
+};
+
+template <class R, class P1, class P2, class P3>
+struct FuncSig3 {
+ template <R F(P1, P2, P3)>
+ Func3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc() {
+ return Func3<R, P1, P2, P3, F, FuncInfo<P1, R> >();
+ }
+
+ template <R F(P1, P2, P3)>
+ BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc(
+ typename remove_constptr<P2>::type param2) {
+ return BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> >(param2);
+ }
+};
+
+template <class R, class P1, class P2, class P3, class P4>
+struct FuncSig4 {
+ template <R F(P1, P2, P3, P4)>
+ Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc() {
+ return Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >();
+ }
+
+ template <R F(P1, P2, P3, P4)>
+ BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc(
+ typename remove_constptr<P2>::type param2) {
+ return BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(param2);
+ }
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+struct FuncSig5 {
+ template <R F(P1, P2, P3, P4, P5)>
+ Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc() {
+ return Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >();
+ }
+
+ template <R F(P1, P2, P3, P4, P5)>
+ BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc(
+ typename remove_constptr<P2>::type param2) {
+ return BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(param2);
+ }
+};
+
+// Overloaded template function that can construct the appropriate FuncSig*
+// class given a function pointer by deducing the template parameters.
+template <class R, class P1>
+inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return FuncSig1<R, P1>();
+}
+
+template <class R, class P1, class P2>
+inline FuncSig2<R, P1, P2> MatchFunc(R (*f)(P1, P2)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return FuncSig2<R, P1, P2>();
+}
+
+template <class R, class P1, class P2, class P3>
+inline FuncSig3<R, P1, P2, P3> MatchFunc(R (*f)(P1, P2, P3)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return FuncSig3<R, P1, P2, P3>();
+}
+
+template <class R, class P1, class P2, class P3, class P4>
+inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return FuncSig4<R, P1, P2, P3, P4>();
+}
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+inline FuncSig5<R, P1, P2, P3, P4, P5> MatchFunc(R (*f)(P1, P2, P3, P4, P5)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return FuncSig5<R, P1, P2, P3, P4, P5>();
+}
+
+// MethodSig ///////////////////////////////////////////////////////////////////
+
+// CallMethod*: a function template that calls a given method.
+template <class R, class C, R (C::*F)()>
+R CallMethod0(C *obj) {
+ return ((*obj).*F)();
+}
+
+template <class R, class C, class P1, R (C::*F)(P1)>
+R CallMethod1(C *obj, P1 arg1) {
+ return ((*obj).*F)(arg1);
+}
+
+template <class R, class C, class P1, class P2, R (C::*F)(P1, P2)>
+R CallMethod2(C *obj, P1 arg1, P2 arg2) {
+ return ((*obj).*F)(arg1, arg2);
+}
+
+template <class R, class C, class P1, class P2, class P3, R (C::*F)(P1, P2, P3)>
+R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) {
+ return ((*obj).*F)(arg1, arg2, arg3);
+}
+
+template <class R, class C, class P1, class P2, class P3, class P4,
+ R (C::*F)(P1, P2, P3, P4)>
+R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) {
+ return ((*obj).*F)(arg1, arg2, arg3, arg4);
+}
+
+// MethodSig: like FuncSig, but for member functions.
+//
+// GetFunc() returns a normal FuncN object, so after calling GetFunc() no
+// more logic is required to special-case methods.
+template <class R, class C>
+struct MethodSig0 {
+ template <R (C::*F)()>
+ Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> > GetFunc() {
+ return Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> >();
+ }
+};
+
+template <class R, class C, class P1>
+struct MethodSig1 {
+ template <R (C::*F)(P1)>
+ Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc() {
+ return Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >();
+ }
+
+ template <R (C::*F)(P1)>
+ BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc(
+ typename remove_constptr<P1>::type param1) {
+ return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >(
+ param1);
+ }
+};
+
+template <class R, class C, class P1, class P2>
+struct MethodSig2 {
+ template <R (C::*F)(P1, P2)>
+ Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
+ GetFunc() {
+ return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
+ FuncInfo<C *, R> >();
+ }
+
+ template <R (C::*F)(P1, P2)>
+ BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
+ GetFunc(typename remove_constptr<P1>::type param1) {
+ return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
+ FuncInfo<C *, R> >(param1);
+ }
+};
+
+template <class R, class C, class P1, class P2, class P3>
+struct MethodSig3 {
+ template <R (C::*F)(P1, P2, P3)>
+ Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, FuncInfo<C *, R> >
+ GetFunc() {
+ return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+ FuncInfo<C *, R> >();
+ }
+
+ template <R (C::*F)(P1, P2, P3)>
+ BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+ FuncInfo<C *, R> >
+ GetFunc(typename remove_constptr<P1>::type param1) {
+ return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+ FuncInfo<C *, R> >(param1);
+ }
+};
+
+template <class R, class C, class P1, class P2, class P3, class P4>
+struct MethodSig4 {
+ template <R (C::*F)(P1, P2, P3, P4)>
+ Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+ FuncInfo<C *, R> >
+ GetFunc() {
+ return Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+ FuncInfo<C *, R> >();
+ }
+
+ template <R (C::*F)(P1, P2, P3, P4)>
+ BoundFunc5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+ FuncInfo<C *, R> >
+ GetFunc(typename remove_constptr<P1>::type param1) {
+ return BoundFunc5<R, C *, P1, P2, P3, P4,
+ CallMethod4<R, C, P1, P2, P3, P4, F>, FuncInfo<C *, R> >(
+ param1);
+ }
+};
+
+template <class R, class C>
+inline MethodSig0<R, C> MatchFunc(R (C::*f)()) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return MethodSig0<R, C>();
+}
+
+template <class R, class C, class P1>
+inline MethodSig1<R, C, P1> MatchFunc(R (C::*f)(P1)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return MethodSig1<R, C, P1>();
+}
+
+template <class R, class C, class P1, class P2>
+inline MethodSig2<R, C, P1, P2> MatchFunc(R (C::*f)(P1, P2)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return MethodSig2<R, C, P1, P2>();
+}
+
+template <class R, class C, class P1, class P2, class P3>
+inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return MethodSig3<R, C, P1, P2, P3>();
+}
+
+template <class R, class C, class P1, class P2, class P3, class P4>
+inline MethodSig4<R, C, P1, P2, P3, P4> MatchFunc(R (C::*f)(P1, P2, P3, P4)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return MethodSig4<R, C, P1, P2, P3, P4>();
+}
+
+// MaybeWrapReturn /////////////////////////////////////////////////////////////
+
+// Template class that attempts to wrap the return value of the function so it
+// matches the expected type. There are two main adjustments it may make:
+//
+// 1. If the function returns void, make it return the expected type and with
+// a value that always indicates success.
+// 2. If the function is expected to return void* but doesn't, wrap it so it
+// does (either by returning the closure param if the wrapped function
+// returns void or by casting a different pointer type to void* for
+// return).
+
+// Template parameters are FuncN type and desired return type.
+template <class F, class R, class Enable = void>
+struct MaybeWrapReturn;
+
+// If the return type matches, return the given function unwrapped.
+template <class F>
+struct MaybeWrapReturn<F, typename F::Return> {
+ typedef F Func;
+};
+
+// Function wrapper that munges the return value from void to (bool)true.
+template <class P1, class P2, void F(P1, P2)>
+bool ReturnTrue2(P1 p1, P2 p2) {
+ F(p1, p2);
+ return true;
+}
+
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+bool ReturnTrue3(P1 p1, P2 p2, P3 p3) {
+ F(p1, p2, p3);
+ return true;
+}
+
+// Function wrapper that munges the return value from void to (void*)arg1
+template <class P1, class P2, void F(P1, P2)>
+void *ReturnClosure2(P1 p1, P2 p2) {
+ F(p1, p2);
+ return p1;
+}
+
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+void *ReturnClosure3(P1 p1, P2 p2, P3 p3) {
+ F(p1, p2, p3);
+ return p1;
+}
+
+// Function wrapper that munges the return value from R to void*.
+template <class R, class P1, class P2, R F(P1, P2)>
+void *CastReturnToVoidPtr2(P1 p1, P2 p2) {
+ return F(p1, p2);
+}
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) {
+ return F(p1, p2, p3);
+}
+
+// Function wrapper that munges the return value from bool to void*.
+template <class P1, class P2, bool F(P1, P2)>
+void *ReturnClosureOrBreak2(P1 p1, P2 p2) {
+ return F(p1, p2) ? p1 : UPB_BREAK;
+}
+
+template <class P1, class P2, class P3, bool F(P1, P2, P3)>
+void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) {
+ return F(p1, p2, p3) ? p1 : UPB_BREAK;
+}
+
+// For the string callback, which takes five params, returns the size param.
+template <class P1, class P2,
+ void F(P1, P2, const char *, size_t, const BufferHandle *)>
+size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4,
+ const BufferHandle *p5) {
+ F(p1, p2, p3, p4, p5);
+ return p4;
+}
+
+// For the string callback, which takes five params, returns the size param or
+// zero.
+template <class P1, class P2,
+ bool F(P1, P2, const char *, size_t, const BufferHandle *)>
+size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4,
+ const BufferHandle *p5) {
+ return F(p1, p2, p3, p4, p5) ? p4 : 0;
+}
+
+// If we have a function returning void but want a function returning bool, wrap
+// it in a function that returns true.
+template <class P1, class P2, void F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, bool> {
+ typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, bool> {
+ typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F>, I> Func;
+};
+
+// If our function returns void but we want one returning void*, wrap it in a
+// function that returns the first argument.
+template <class P1, class P2, void F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, void *> {
+ typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, void *> {
+ typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F>, I> Func;
+};
+
+// If our function returns R* but we want one returning void*, wrap it in a
+// function that casts to void*.
+template <class R, class P1, class P2, R *F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<R *, P1, P2, F, I>, void *,
+ typename disable_if_same<R *, void *>::Type> {
+ typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F>, I> Func;
+};
+
+template <class R, class P1, class P2, class P3, R *F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F, I>, void *,
+ typename disable_if_same<R *, void *>::Type> {
+ typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F>, I>
+ Func;
+};
+
+// If our function returns bool but we want one returning void*, wrap it in a
+// function that returns either the first param or UPB_BREAK.
+template <class P1, class P2, bool F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<bool, P1, P2, F, I>, void *> {
+ typedef Func2<void *, P1, P2, ReturnClosureOrBreak2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, bool F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<bool, P1, P2, P3, F, I>, void *> {
+ typedef Func3<void *, P1, P2, P3, ReturnClosureOrBreak3<P1, P2, P3, F>, I>
+ Func;
+};
+
+// If our function returns void but we want one returning size_t, wrap it in a
+// function that returns the size argument.
+template <class P1, class P2,
+ void F(P1, P2, const char *, size_t, const BufferHandle *), class I>
+struct MaybeWrapReturn<
+ Func5<void, P1, P2, const char *, size_t, const BufferHandle *, F, I>,
+ size_t> {
+ typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *,
+ ReturnStringLen<P1, P2, F>, I> Func;
+};
+
+// If our function returns bool but we want one returning size_t, wrap it in a
+// function that returns either 0 or the buf size.
+template <class P1, class P2,
+ bool F(P1, P2, const char *, size_t, const BufferHandle *), class I>
+struct MaybeWrapReturn<
+ Func5<bool, P1, P2, const char *, size_t, const BufferHandle *, F, I>,
+ size_t> {
+ typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *,
+ ReturnNOr0<P1, P2, F>, I> Func;
+};
+
+// ConvertParams ///////////////////////////////////////////////////////////////
+
+// Template class that converts the function parameters if necessary, and
+// ignores the HandlerData parameter if appropriate.
+//
+// Template parameter is the are FuncN function type.
+template <class F, class T>
+struct ConvertParams;
+
+// Function that discards the handler data parameter.
+template <class R, class P1, R F(P1)>
+R IgnoreHandlerData2(void *p1, const void *hd) {
+ UPB_UNUSED(hd);
+ return F(static_cast<P1>(p1));
+}
+
+template <class R, class P1, class P2Wrapper, class P2Wrapped,
+ R F(P1, P2Wrapped)>
+R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) {
+ UPB_UNUSED(hd);
+ return F(static_cast<P1>(p1), p2);
+}
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) {
+ UPB_UNUSED(hd);
+ return F(static_cast<P1>(p1), p2, p3);
+}
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
+R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) {
+ UPB_UNUSED(hd);
+ return F(static_cast<P1>(p1), p2, p3, p4);
+}
+
+template <class R, class P1, R F(P1, const char*, size_t)>
+R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2,
+ size_t p3, const BufferHandle *handle) {
+ UPB_UNUSED(hd);
+ UPB_UNUSED(handle);
+ return F(static_cast<P1>(p1), p2, p3);
+}
+
+// Function that casts the handler data parameter.
+template <class R, class P1, class P2, R F(P1, P2)>
+R CastHandlerData2(void *c, const void *hd) {
+ return F(static_cast<P1>(c), static_cast<P2>(hd));
+}
+
+template <class R, class P1, class P2, class P3Wrapper, class P3Wrapped,
+ R F(P1, P2, P3Wrapped)>
+R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) {
+ return F(static_cast<P1>(c), static_cast<P2>(hd), p3);
+}
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+ R F(P1, P2, P3, P4, P5)>
+R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) {
+ return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4, p5);
+}
+
+template <class R, class P1, class P2, R F(P1, P2, const char *, size_t)>
+R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3,
+ size_t p4, const BufferHandle *handle) {
+ UPB_UNUSED(handle);
+ return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4);
+}
+
+// For unbound functions, ignore the handler data.
+template <class R, class P1, R F(P1), class I, class T>
+struct ConvertParams<Func1<R, P1, F, I>, T> {
+ typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F>, I> Func;
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I,
+ class R2, class P1_2, class P2_2, class P3_2>
+struct ConvertParams<Func2<R, P1, P2, F, I>,
+ R2 (*)(P1_2, P2_2, P3_2)> {
+ typedef Func3<R, void *, const void *, P3_2,
+ IgnoreHandlerData3<R, P1, P3_2, P2, F>, I> Func;
+};
+
+// For StringBuffer only; this ignores both the handler data and the
+// BufferHandle.
+template <class R, class P1, R F(P1, const char *, size_t), class I, class T>
+struct ConvertParams<Func3<R, P1, const char *, size_t, F, I>, T> {
+ typedef Func5<R, void *, const void *, const char *, size_t,
+ const BufferHandle *, IgnoreHandlerDataIgnoreHandle<R, P1, F>,
+ I> Func;
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+ class I, class T>
+struct ConvertParams<Func4<R, P1, P2, P3, P4, F, I>, T> {
+ typedef Func5<R, void *, const void *, P2, P3, P4,
+ IgnoreHandlerData5<R, P1, P2, P3, P4, F>, I> Func;
+};
+
+// For bound functions, cast the handler data.
+template <class R, class P1, class P2, R F(P1, P2), class I, class T>
+struct ConvertParams<BoundFunc2<R, P1, P2, F, I>, T> {
+ typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F>, I>
+ Func;
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I,
+ class R2, class P1_2, class P2_2, class P3_2>
+struct ConvertParams<BoundFunc3<R, P1, P2, P3, F, I>,
+ R2 (*)(P1_2, P2_2, P3_2)> {
+ typedef Func3<R, void *, const void *, P3_2,
+ CastHandlerData3<R, P1, P2, P3_2, P3, F>, I> Func;
+};
+
+// For StringBuffer only; this ignores the BufferHandle.
+template <class R, class P1, class P2, R F(P1, P2, const char *, size_t),
+ class I, class T>
+struct ConvertParams<BoundFunc4<R, P1, P2, const char *, size_t, F, I>, T> {
+ typedef Func5<R, void *, const void *, const char *, size_t,
+ const BufferHandle *, CastHandlerDataIgnoreHandle<R, P1, P2, F>,
+ I> Func;
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+ R F(P1, P2, P3, P4, P5), class I, class T>
+struct ConvertParams<BoundFunc5<R, P1, P2, P3, P4, P5, F, I>, T> {
+ typedef Func5<R, void *, const void *, P3, P4, P5,
+ CastHandlerData5<R, P1, P2, P3, P4, P5, F>, I> Func;
+};
+
+// utype/ltype are upper/lower-case, ctype is canonical C type, vtype is
+// variant C type.
+#define TYPE_METHODS(utype, ltype, ctype, vtype) \
+ template <> struct CanonicalType<vtype> { \
+ typedef ctype Type; \
+ }; \
+ template <> \
+ inline bool Handlers::SetValueHandler<vtype>( \
+ const FieldDef *f, \
+ const Handlers::utype ## Handler& handler) { \
+ assert(!handler.registered_); \
+ handler.AddCleanup(this); \
+ handler.registered_ = true; \
+ return upb_handlers_set##ltype(this, f, handler.handler_, &handler.attr_); \
+ } \
+
+TYPE_METHODS(Double, double, double, double);
+TYPE_METHODS(Float, float, float, float);
+TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T);
+TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T);
+TYPE_METHODS(Int64, int64, int64_t, UPB_INT64_T);
+TYPE_METHODS(Int32, int32, int32_t, UPB_INT32_T);
+TYPE_METHODS(Bool, bool, bool, bool);
+
+#ifdef UPB_TWO_32BIT_TYPES
+TYPE_METHODS(Int32, int32, int32_t, UPB_INT32ALT_T);
+TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T);
+#endif
+
+#ifdef UPB_TWO_64BIT_TYPES
+TYPE_METHODS(Int64, int64, int64_t, UPB_INT64ALT_T);
+TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T);
+#endif
+#undef TYPE_METHODS
+
+template <> struct CanonicalType<Status*> {
+ typedef Status* Type;
+};
+
+// Type methods that are only one-per-canonical-type and not one-per-cvariant.
+
+#define TYPE_METHODS(utype, ctype) \
+ inline bool Handlers::Set##utype##Handler(const FieldDef *f, \
+ const utype##Handler &h) { \
+ return SetValueHandler<ctype>(f, h); \
+ } \
+
+TYPE_METHODS(Double, double);
+TYPE_METHODS(Float, float);
+TYPE_METHODS(UInt64, uint64_t);
+TYPE_METHODS(UInt32, uint32_t);
+TYPE_METHODS(Int64, int64_t);
+TYPE_METHODS(Int32, int32_t);
+TYPE_METHODS(Bool, bool);
+#undef TYPE_METHODS
+
+template <class F> struct ReturnOf;
+
+template <class R, class P1, class P2>
+struct ReturnOf<R (*)(P1, P2)> {
+ typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3>
+struct ReturnOf<R (*)(P1, P2, P3)> {
+ typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3, class P4>
+struct ReturnOf<R (*)(P1, P2, P3, P4)> {
+ typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+struct ReturnOf<R (*)(P1, P2, P3, P4, P5)> {
+ typedef R Return;
+};
+
+template<class T> const void *UniquePtrForType() {
+ static const char ch = 0;
+ return &ch;
+}
+
+template <class T>
+template <class F>
+inline Handler<T>::Handler(F func)
+ : registered_(false),
+ cleanup_data_(func.GetData()),
+ cleanup_func_(func.GetCleanup()) {
+ upb_handlerattr_sethandlerdata(&attr_, func.GetData());
+ typedef typename ReturnOf<T>::Return Return;
+ typedef typename ConvertParams<F, T>::Func ConvertedParamsFunc;
+ typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func
+ ReturnWrappedFunc;
+ handler_ = ReturnWrappedFunc().Call;
+
+ // Set attributes based on what templates can statically tell us about the
+ // user's function.
+
+ // If the original function returns void, then we know that we wrapped it to
+ // always return ok.
+ bool always_ok = is_same<typename F::FuncInfo::Return, void>::value;
+ attr_.SetAlwaysOk(always_ok);
+
+ // Closure parameter and return type.
+ attr_.SetClosureType(UniquePtrForType<typename F::FuncInfo::Closure>());
+
+ // We use the closure type (from the first parameter) if the return type is
+ // void. This is all nonsense for non START* handlers, but it doesn't matter
+ // because in that case the value will be ignored.
+ typedef typename FirstUnlessVoid<typename F::FuncInfo::Return,
+ typename F::FuncInfo::Closure>::value
+ EffectiveReturn;
+ attr_.SetReturnClosureType(UniquePtrForType<EffectiveReturn>());
+}
+
+template <class T>
+inline Handler<T>::~Handler() {
+ assert(registered_);
+}
+
+inline HandlerAttributes::HandlerAttributes() { upb_handlerattr_init(this); }
+inline HandlerAttributes::~HandlerAttributes() { upb_handlerattr_uninit(this); }
+inline bool HandlerAttributes::SetHandlerData(const void *hd) {
+ return upb_handlerattr_sethandlerdata(this, hd);
+}
+inline const void* HandlerAttributes::handler_data() const {
+ return upb_handlerattr_handlerdata(this);
+}
+inline bool HandlerAttributes::SetClosureType(const void *type) {
+ return upb_handlerattr_setclosuretype(this, type);
+}
+inline const void* HandlerAttributes::closure_type() const {
+ return upb_handlerattr_closuretype(this);
+}
+inline bool HandlerAttributes::SetReturnClosureType(const void *type) {
+ return upb_handlerattr_setreturnclosuretype(this, type);
+}
+inline const void* HandlerAttributes::return_closure_type() const {
+ return upb_handlerattr_returnclosuretype(this);
+}
+inline bool HandlerAttributes::SetAlwaysOk(bool always_ok) {
+ return upb_handlerattr_setalwaysok(this, always_ok);
+}
+inline bool HandlerAttributes::always_ok() const {
+ return upb_handlerattr_alwaysok(this);
+}
+
+inline BufferHandle::BufferHandle() { upb_bufhandle_init(this); }
+inline BufferHandle::~BufferHandle() { upb_bufhandle_uninit(this); }
+inline const char* BufferHandle::buffer() const {
+ return upb_bufhandle_buf(this);
+}
+inline size_t BufferHandle::object_offset() const {
+ return upb_bufhandle_objofs(this);
+}
+inline void BufferHandle::SetBuffer(const char* buf, size_t ofs) {
+ upb_bufhandle_setbuf(this, buf, ofs);
+}
+template <class T>
+void BufferHandle::SetAttachedObject(const T* obj) {
+ upb_bufhandle_setobj(this, obj, UniquePtrForType<T>());
+}
+template <class T>
+const T* BufferHandle::GetAttachedObject() const {
+ return upb_bufhandle_objtype(this) == UniquePtrForType<T>()
+ ? static_cast<const T *>(upb_bufhandle_obj(this))
+ : NULL;
+}
+
+inline reffed_ptr<Handlers> Handlers::New(const MessageDef *m) {
+ upb_handlers *h = upb_handlers_new(m, &h);
+ return reffed_ptr<Handlers>(h, &h);
+}
+inline reffed_ptr<const Handlers> Handlers::NewFrozen(
+ const MessageDef *m, upb_handlers_callback *callback,
+ const void *closure) {
+ const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure);
+ return reffed_ptr<const Handlers>(h, &h);
+}
+inline bool Handlers::IsFrozen() const { return upb_handlers_isfrozen(this); }
+inline void Handlers::Ref(const void *owner) const {
+ upb_handlers_ref(this, owner);
+}
+inline void Handlers::Unref(const void *owner) const {
+ upb_handlers_unref(this, owner);
+}
+inline void Handlers::DonateRef(const void *from, const void *to) const {
+ upb_handlers_donateref(this, from, to);
+}
+inline void Handlers::CheckRef(const void *owner) const {
+ upb_handlers_checkref(this, owner);
+}
+inline const Status* Handlers::status() {
+ return upb_handlers_status(this);
+}
+inline void Handlers::ClearError() {
+ return upb_handlers_clearerr(this);
+}
+inline bool Handlers::Freeze(Status *s) {
+ upb::Handlers* h = this;
+ return upb_handlers_freeze(&h, 1, s);
+}
+inline bool Handlers::Freeze(Handlers *const *handlers, int n, Status *s) {
+ return upb_handlers_freeze(handlers, n, s);
+}
+inline bool Handlers::Freeze(const std::vector<Handlers*>& h, Status* status) {
+ return upb_handlers_freeze((Handlers* const*)&h[0], h.size(), status);
+}
+inline const MessageDef *Handlers::message_def() const {
+ return upb_handlers_msgdef(this);
+}
+inline bool Handlers::AddCleanup(void *p, upb_handlerfree *func) {
+ return upb_handlers_addcleanup(this, p, func);
+}
+inline bool Handlers::SetStartMessageHandler(
+ const Handlers::StartMessageHandler &handler) {
+ assert(!handler.registered_);
+ handler.registered_ = true;
+ handler.AddCleanup(this);
+ return upb_handlers_setstartmsg(this, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndMessageHandler(
+ const Handlers::EndMessageHandler &handler) {
+ assert(!handler.registered_);
+ handler.registered_ = true;
+ handler.AddCleanup(this);
+ return upb_handlers_setendmsg(this, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartStringHandler(const FieldDef *f,
+ const StartStringHandler &handler) {
+ assert(!handler.registered_);
+ handler.registered_ = true;
+ handler.AddCleanup(this);
+ return upb_handlers_setstartstr(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndStringHandler(const FieldDef *f,
+ const EndFieldHandler &handler) {
+ assert(!handler.registered_);
+ handler.registered_ = true;
+ handler.AddCleanup(this);
+ return upb_handlers_setendstr(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStringHandler(const FieldDef *f,
+ const StringHandler& handler) {
+ assert(!handler.registered_);
+ handler.registered_ = true;
+ handler.AddCleanup(this);
+ return upb_handlers_setstring(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartSequenceHandler(
+ const FieldDef *f, const StartFieldHandler &handler) {
+ assert(!handler.registered_);
+ handler.registered_ = true;
+ handler.AddCleanup(this);
+ return upb_handlers_setstartseq(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartSubMessageHandler(
+ const FieldDef *f, const StartFieldHandler &handler) {
+ assert(!handler.registered_);
+ handler.registered_ = true;
+ handler.AddCleanup(this);
+ return upb_handlers_setstartsubmsg(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndSubMessageHandler(const FieldDef *f,
+ const EndFieldHandler &handler) {
+ assert(!handler.registered_);
+ handler.registered_ = true;
+ handler.AddCleanup(this);
+ return upb_handlers_setendsubmsg(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndSequenceHandler(const FieldDef *f,
+ const EndFieldHandler &handler) {
+ assert(!handler.registered_);
+ handler.registered_ = true;
+ handler.AddCleanup(this);
+ return upb_handlers_setendseq(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetSubHandlers(const FieldDef *f, const Handlers *sub) {
+ return upb_handlers_setsubhandlers(this, f, sub);
+}
+inline const Handlers *Handlers::GetSubHandlers(const FieldDef *f) const {
+ return upb_handlers_getsubhandlers(this, f);
+}
+inline const Handlers *Handlers::GetSubHandlers(Handlers::Selector sel) const {
+ return upb_handlers_getsubhandlers_sel(this, sel);
+}
+inline bool Handlers::GetSelector(const FieldDef *f, Handlers::Type type,
+ Handlers::Selector *s) {
+ return upb_handlers_getselector(f, type, s);
+}
+inline Handlers::Selector Handlers::GetEndSelector(Handlers::Selector start) {
+ return upb_handlers_getendselector(start);
+}
+inline Handlers::GenericFunction *Handlers::GetHandler(
+ Handlers::Selector selector) {
+ return upb_handlers_gethandler(this, selector);
+}
+inline const void *Handlers::GetHandlerData(Handlers::Selector selector) {
+ return upb_handlers_gethandlerdata(this, selector);
+}
+
+inline BytesHandler::BytesHandler() {
+ upb_byteshandler_init(this);
+}
+
+inline BytesHandler::~BytesHandler() {
+ upb_byteshandler_uninit(this);
+}
+
+} // namespace upb
+
+#endif // __cplusplus
+
+
+#undef UPB_TWO_32BIT_TYPES
+#undef UPB_TWO_64BIT_TYPES
+#undef UPB_INT32_T
+#undef UPB_UINT32_T
+#undef UPB_INT32ALT_T
+#undef UPB_UINT32ALT_T
+#undef UPB_INT64_T
+#undef UPB_UINT64_T
+#undef UPB_INT64ALT_T
+#undef UPB_UINT64ALT_T
+
+#endif // UPB_HANDLERS_INL_H_
+
+#endif // UPB_HANDLERS_H
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2010-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * A upb_sink is an object that binds a upb_handlers object to some runtime
+ * state. It is the object that can actually receive data via the upb_handlers
+ * interface.
+ *
+ * Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or
+ * thread-safe. You can create as many of them as you want, but each one may
+ * only be used in a single thread at a time.
+ *
+ * If we compare with class-based OOP, a you can think of a upb_def as an
+ * abstract base class, a upb_handlers as a concrete derived class, and a
+ * upb_sink as an object (class instance).
+ */
+
+#ifndef UPB_SINK_H
+#define UPB_SINK_H
+
+
+#ifdef __cplusplus
+namespace upb {
+class BufferSource;
+class BytesSink;
+class Sink;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::BufferSource, upb_bufsrc);
+UPB_DECLARE_TYPE(upb::BytesSink, upb_bytessink);
+UPB_DECLARE_TYPE(upb::Sink, upb_sink);
+
+// Internal-only struct for the sink.
+struct upb_sinkframe {
+ UPB_PRIVATE_FOR_CPP
+ const upb_handlers *h;
+ void *closure;
+
+ // For any frames besides the top, this is the END* callback that will run
+ // when the subframe is popped (for example, for a "sequence" frame the frame
+ // above it will be a UPB_HANDLER_ENDSEQ handler). But this is only
+ // necessary for assertion checking inside upb_sink and can be omitted if the
+ // sink has only one caller.
+ //
+ // TODO(haberman): have a mechanism for ensuring that a sink only has one
+ // caller.
+ upb_selector_t selector;
+};
+
+// The maximum nesting depth that upb::Sink will allow. Matches proto2's limit.
+// TODO: make this a runtime-settable property of Sink.
+#define UPB_SINK_MAX_NESTING 64
+
+// A upb::Sink is an object that binds a upb::Handlers object to some runtime
+// state. It represents an endpoint to which data can be sent.
+//
+// TODO(haberman): right now all of these functions take selectors. Should they
+// take selectorbase instead?
+//
+// ie. instead of calling:
+// sink->StartString(FOO_FIELD_START_STRING, ...)
+// a selector base would let you say:
+// sink->StartString(FOO_FIELD, ...)
+//
+// This would make call sites a little nicer and require emitting fewer selector
+// definitions in .h files.
+//
+// But the current scheme has the benefit that you can retrieve a function
+// pointer for any handler with handlers->GetHandler(selector), without having
+// to have a separate GetHandler() function for each handler type. The JIT
+// compiler uses this. To accommodate we'd have to expose a separate
+// GetHandler() for every handler type.
+//
+// Also to ponder: selectors right now are independent of a specific Handlers
+// instance. In other words, they allocate a number to every possible handler
+// that *could* be registered, without knowing anything about what handlers
+// *are* registered. That means that using selectors as table offsets prohibits
+// us from compacting the handler table at Freeze() time. If the table is very
+// sparse, this could be wasteful.
+//
+// Having another selector-like thing that is specific to a Handlers instance
+// would allow this compacting, but then it would be impossible to write code
+// ahead-of-time that can be bound to any Handlers instance at runtime. For
+// example, a .proto file parser written as straight C will not know what
+// Handlers it will be bound to, so when it calls sink->StartString() what
+// selector will it pass? It needs a selector like we have today, that is
+// independent of any particular upb::Handlers.
+//
+// Is there a way then to allow Handlers table compaction?
+UPB_DEFINE_CLASS0(upb::Sink,
+ public:
+ // Constructor with no initialization; must be Reset() before use.
+ Sink() {}
+
+ // Constructs a new sink for the given frozen handlers and closure.
+ //
+ // TODO: once the Handlers know the expected closure type, verify that T
+ // matches it.
+ template <class T> Sink(const Handlers* handlers, T* closure);
+
+ // Resets the value of the sink.
+ template <class T> void Reset(const Handlers* handlers, T* closure);
+
+ // Returns the top-level object that is bound to this sink.
+ //
+ // TODO: once the Handlers know the expected closure type, verify that T
+ // matches it.
+ template <class T> T* GetObject() const;
+
+ // Functions for pushing data into the sink.
+ //
+ // These return false if processing should stop (either due to error or just
+ // to suspend).
+ //
+ // These may not be called from within one of the same sink's handlers (in
+ // other words, handlers are not re-entrant).
+
+ // Should be called at the start and end of every message; both the top-level
+ // message and submessages. This means that submessages should use the
+ // following sequence:
+ // sink->StartSubMessage(startsubmsg_selector);
+ // sink->StartMessage();
+ // // ...
+ // sink->EndMessage(&status);
+ // sink->EndSubMessage(endsubmsg_selector);
+ bool StartMessage();
+ bool EndMessage(Status* status);
+
+ // Putting of individual values. These work for both repeated and
+ // non-repeated fields, but for repeated fields you must wrap them in
+ // calls to StartSequence()/EndSequence().
+ bool PutInt32(Handlers::Selector s, int32_t val);
+ bool PutInt64(Handlers::Selector s, int64_t val);
+ bool PutUInt32(Handlers::Selector s, uint32_t val);
+ bool PutUInt64(Handlers::Selector s, uint64_t val);
+ bool PutFloat(Handlers::Selector s, float val);
+ bool PutDouble(Handlers::Selector s, double val);
+ bool PutBool(Handlers::Selector s, bool val);
+
+ // Putting of string/bytes values. Each string can consist of zero or more
+ // non-contiguous buffers of data.
+ //
+ // For StartString(), the function will write a sink for the string to "sub."
+ // The sub-sink must be used for any/all PutStringBuffer() calls.
+ bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub);
+ size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len,
+ const BufferHandle *handle);
+ bool EndString(Handlers::Selector s);
+
+ // For submessage fields.
+ //
+ // For StartSubMessage(), the function will write a sink for the string to
+ // "sub." The sub-sink must be used for any/all handlers called within the
+ // submessage.
+ bool StartSubMessage(Handlers::Selector s, Sink* sub);
+ bool EndSubMessage(Handlers::Selector s);
+
+ // For repeated fields of any type, the sequence of values must be wrapped in
+ // these calls.
+ //
+ // For StartSequence(), the function will write a sink for the string to
+ // "sub." The sub-sink must be used for any/all handlers called within the
+ // sequence.
+ bool StartSequence(Handlers::Selector s, Sink* sub);
+ bool EndSequence(Handlers::Selector s);
+
+ // Copy and assign specifically allowed.
+ // We don't even bother making these members private because so many
+ // functions need them and this is mainly just a dumb data container anyway.
+,
+UPB_DEFINE_STRUCT0(upb_sink,
+ const upb_handlers *handlers;
+ void *closure;
+));
+
+UPB_DEFINE_CLASS0(upb::BytesSink,
+ public:
+ BytesSink() {}
+
+ // Constructs a new sink for the given frozen handlers and closure.
+ //
+ // TODO(haberman): once the Handlers know the expected closure type, verify
+ // that T matches it.
+ template <class T> BytesSink(const BytesHandler* handler, T* closure);
+
+ // Resets the value of the sink.
+ template <class T> void Reset(const BytesHandler* handler, T* closure);
+
+ bool Start(size_t size_hint, void **subc);
+ size_t PutBuffer(void *subc, const char *buf, size_t len,
+ const BufferHandle *handle);
+ bool End();
+,
+UPB_DEFINE_STRUCT0(upb_bytessink,
+ const upb_byteshandler *handler;
+ void *closure;
+));
+
+// A class for pushing a flat buffer of data to a BytesSink.
+// You can construct an instance of this to get a resumable source,
+// or just call the static PutBuffer() to do a non-resumable push all in one go.
+UPB_DEFINE_CLASS0(upb::BufferSource,
+ public:
+ BufferSource();
+ BufferSource(const char* buf, size_t len, BytesSink* sink);
+
+ // Returns true if the entire buffer was pushed successfully. Otherwise the
+ // next call to PutNext() will resume where the previous one left off.
+ // TODO(haberman): implement this.
+ bool PutNext();
+
+ // A static version; with this version is it not possible to resume in the
+ // case of failure or a partially-consumed buffer.
+ static bool PutBuffer(const char* buf, size_t len, BytesSink* sink);
+
+ template <class T> static bool PutBuffer(const T& str, BytesSink* sink) {
+ return PutBuffer(str.c_str(), str.size(), sink);
+ }
+,
+UPB_DEFINE_STRUCT0(upb_bufsrc,
+));
+
+UPB_BEGIN_EXTERN_C // {
+
+// Inline definitions.
+
+UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h,
+ void *closure) {
+ s->handler = h;
+ s->closure = closure;
+}
+
+UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint,
+ void **subc) {
+ *subc = s->closure;
+ if (!s->handler) return true;
+ upb_startstr_handlerfunc *start =
+ (upb_startstr_handlerfunc *)s->handler->table[UPB_STARTSTR_SELECTOR].func;
+
+ if (!start) return true;
+ *subc = start(s->closure, upb_handlerattr_handlerdata(
+ &s->handler->table[UPB_STARTSTR_SELECTOR].attr),
+ size_hint);
+ return *subc != NULL;
+}
+
+UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc,
+ const char *buf, size_t size,
+ const upb_bufhandle* handle) {
+ if (!s->handler) return true;
+ upb_string_handlerfunc *putbuf =
+ (upb_string_handlerfunc *)s->handler->table[UPB_STRING_SELECTOR].func;
+
+ if (!putbuf) return true;
+ return putbuf(subc, upb_handlerattr_handlerdata(
+ &s->handler->table[UPB_STRING_SELECTOR].attr),
+ buf, size, handle);
+}
+
+UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) {
+ if (!s->handler) return true;
+ upb_endfield_handlerfunc *end =
+ (upb_endfield_handlerfunc *)s->handler->table[UPB_ENDSTR_SELECTOR].func;
+
+ if (!end) return true;
+ return end(s->closure,
+ upb_handlerattr_handlerdata(
+ &s->handler->table[UPB_ENDSTR_SELECTOR].attr));
+}
+
+UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len,
+ upb_bytessink *sink) {
+ void *subc;
+ upb_bufhandle handle;
+ upb_bufhandle_init(&handle);
+ upb_bufhandle_setbuf(&handle, buf, 0);
+ bool ret = upb_bytessink_start(sink, len, &subc);
+ if (ret && len != 0) {
+ ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) == len);
+ }
+ if (ret) {
+ ret = upb_bytessink_end(sink);
+ }
+ upb_bufhandle_uninit(&handle);
+ return ret;
+}
+
+#define PUTVAL(type, ctype) \
+ UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel, \
+ ctype val) { \
+ if (!s->handlers) return true; \
+ upb_##type##_handlerfunc *func = \
+ (upb_##type##_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); \
+ if (!func) return true; \
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); \
+ return func(s->closure, hd, val); \
+ }
+
+PUTVAL(int32, int32_t);
+PUTVAL(int64, int64_t);
+PUTVAL(uint32, uint32_t);
+PUTVAL(uint64, uint64_t);
+PUTVAL(float, float);
+PUTVAL(double, double);
+PUTVAL(bool, bool);
+#undef PUTVAL
+
+UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) {
+ s->handlers = h;
+ s->closure = c;
+}
+
+UPB_INLINE size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel,
+ const char *buf, size_t n,
+ const upb_bufhandle *handle) {
+ if (!s->handlers) return n;
+ upb_string_handlerfunc *handler =
+ (upb_string_handlerfunc *)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!handler) return n;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ return handler(s->closure, hd, buf, n, handle);
+}
+
+UPB_INLINE bool upb_sink_startmsg(upb_sink *s) {
+ if (!s->handlers) return true;
+ upb_startmsg_handlerfunc *startmsg =
+ (upb_startmsg_handlerfunc *)upb_handlers_gethandler(s->handlers,
+ UPB_STARTMSG_SELECTOR);
+ if (!startmsg) return true;
+ const void *hd =
+ upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR);
+ return startmsg(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) {
+ if (!s->handlers) return true;
+ upb_endmsg_handlerfunc *endmsg =
+ (upb_endmsg_handlerfunc *)upb_handlers_gethandler(s->handlers,
+ UPB_ENDMSG_SELECTOR);
+
+ if (!endmsg) return true;
+ const void *hd =
+ upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR);
+ return endmsg(s->closure, hd, status);
+}
+
+UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel,
+ upb_sink *sub) {
+ sub->closure = s->closure;
+ sub->handlers = s->handlers;
+ if (!s->handlers) return true;
+ upb_startfield_handlerfunc *startseq =
+ (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!startseq) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ sub->closure = startseq(s->closure, hd);
+ return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
+ if (!s->handlers) return true;
+ upb_endfield_handlerfunc *endseq =
+ (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!endseq) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ return endseq(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel,
+ size_t size_hint, upb_sink *sub) {
+ sub->closure = s->closure;
+ sub->handlers = s->handlers;
+ if (!s->handlers) return true;
+ upb_startstr_handlerfunc *startstr =
+ (upb_startstr_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!startstr) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ sub->closure = startstr(s->closure, hd, size_hint);
+ return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
+ if (!s->handlers) return true;
+ upb_endfield_handlerfunc *endstr =
+ (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!endstr) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ return endstr(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel,
+ upb_sink *sub) {
+ sub->closure = s->closure;
+ if (!s->handlers) {
+ sub->handlers = NULL;
+ return true;
+ }
+ sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel);
+ upb_startfield_handlerfunc *startsubmsg =
+ (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!startsubmsg) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ sub->closure = startsubmsg(s->closure, hd);
+ return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
+ if (!s->handlers) return true;
+ upb_endfield_handlerfunc *endsubmsg =
+ (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!endsubmsg) return s->closure;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ return endsubmsg(s->closure, hd);
+}
+
+UPB_END_EXTERN_C // }
+
+#ifdef __cplusplus
+
+namespace upb {
+
+template <class T> Sink::Sink(const Handlers* handlers, T* closure) {
+ upb_sink_reset(this, handlers, closure);
+}
+template <class T>
+inline void Sink::Reset(const Handlers* handlers, T* closure) {
+ upb_sink_reset(this, handlers, closure);
+}
+inline bool Sink::StartMessage() {
+ return upb_sink_startmsg(this);
+}
+inline bool Sink::EndMessage(Status* status) {
+ return upb_sink_endmsg(this, status);
+}
+inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) {
+ return upb_sink_putint32(this, sel, val);
+}
+inline bool Sink::PutInt64(Handlers::Selector sel, int64_t val) {
+ return upb_sink_putint64(this, sel, val);
+}
+inline bool Sink::PutUInt32(Handlers::Selector sel, uint32_t val) {
+ return upb_sink_putuint32(this, sel, val);
+}
+inline bool Sink::PutUInt64(Handlers::Selector sel, uint64_t val) {
+ return upb_sink_putuint64(this, sel, val);
+}
+inline bool Sink::PutFloat(Handlers::Selector sel, float val) {
+ return upb_sink_putfloat(this, sel, val);
+}
+inline bool Sink::PutDouble(Handlers::Selector sel, double val) {
+ return upb_sink_putdouble(this, sel, val);
+}
+inline bool Sink::PutBool(Handlers::Selector sel, bool val) {
+ return upb_sink_putbool(this, sel, val);
+}
+inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint,
+ Sink *sub) {
+ return upb_sink_startstr(this, sel, size_hint, sub);
+}
+inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
+ size_t len, const BufferHandle* handle) {
+ return upb_sink_putstring(this, sel, buf, len, handle);
+}
+inline bool Sink::EndString(Handlers::Selector sel) {
+ return upb_sink_endstr(this, sel);
+}
+inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) {
+ return upb_sink_startsubmsg(this, sel, sub);
+}
+inline bool Sink::EndSubMessage(Handlers::Selector sel) {
+ return upb_sink_endsubmsg(this, sel);
+}
+inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) {
+ return upb_sink_startseq(this, sel, sub);
+}
+inline bool Sink::EndSequence(Handlers::Selector sel) {
+ return upb_sink_endseq(this, sel);
+}
+
+template <class T>
+BytesSink::BytesSink(const BytesHandler* handler, T* closure) {
+ Reset(handler, closure);
+}
+
+template <class T>
+void BytesSink::Reset(const BytesHandler *handler, T *closure) {
+ upb_bytessink_reset(this, handler, closure);
+}
+inline bool BytesSink::Start(size_t size_hint, void **subc) {
+ return upb_bytessink_start(this, size_hint, subc);
+}
+inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len,
+ const BufferHandle *handle) {
+ return upb_bytessink_putbuf(this, subc, buf, len, handle);
+}
+inline bool BytesSink::End() {
+ return upb_bytessink_end(this);
+}
+
+inline bool BufferSource::PutBuffer(const char *buf, size_t len,
+ BytesSink *sink) {
+ return upb_bufsrc_putbuf(buf, len, sink);
+}
+
+} // namespace upb
+#endif
+
+#endif
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2013 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * For handlers that do very tiny, very simple operations, the function call
+ * overhead of calling a handler can be significant. This file allows the
+ * user to define handlers that do something very simple like store the value
+ * to memory and/or set a hasbit. JIT compilers can then special-case these
+ * handlers and emit specialized code for them instead of actually calling the
+ * handler.
+ *
+ * The functionality is very simple/limited right now but may expand to be able
+ * to call another function.
+ */
+
+#ifndef UPB_SHIM_H
+#define UPB_SHIM_H
+
+
+typedef struct {
+ size_t offset;
+ int32_t hasbit;
+} upb_shim_data;
+
+#ifdef __cplusplus
+
+namespace upb {
+
+struct Shim {
+ typedef upb_shim_data Data;
+
+ // Sets a handler for the given field that writes the value to the given
+ // offset and, if hasbit >= 0, sets a bit at the given bit offset. Returns
+ // true if the handler was set successfully.
+ static bool Set(Handlers *h, const FieldDef *f, size_t ofs, int32_t hasbit);
+
+ // If this handler is a shim, returns the corresponding upb::Shim::Data and
+ // stores the type in "type". Otherwise returns NULL.
+ static const Data* GetData(const Handlers* h, Handlers::Selector s,
+ FieldDef::Type* type);
+};
+
+} // namespace upb
+
+#endif
+
+UPB_BEGIN_EXTERN_C // {
+
+// C API.
+bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
+ int32_t hasbit);
+const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
+ upb_fieldtype_t *type);
+
+UPB_END_EXTERN_C // }
+
+#ifdef __cplusplus
+// C++ Wrappers.
+namespace upb {
+inline bool Shim::Set(Handlers* h, const FieldDef* f, size_t ofs,
+ int32_t hasbit) {
+ return upb_shim_set(h, f, ofs, hasbit);
+}
+inline const Shim::Data* Shim::GetData(const Handlers* h, Handlers::Selector s,
+ FieldDef::Type* type) {
+ return upb_shim_getdata(h, s, type);
+}
+} // namespace upb
+#endif
+
+#endif // UPB_SHIM_H
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2011 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * upb::descriptor::Reader provides a way of building upb::Defs from
+ * data in descriptor.proto format.
+ */
+
+#ifndef UPB_DESCRIPTOR_H
+#define UPB_DESCRIPTOR_H
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace descriptor {
+class Reader;
+} // namespace descriptor
+} // namespace upb
+#endif
+
+UPB_DECLARE_TYPE(upb::descriptor::Reader, upb_descreader);
+
+// Internal-only structs used by Reader.
+
+// upb_deflist is an internal-only dynamic array for storing a growing list of
+// upb_defs.
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+ upb_def **defs;
+ size_t len;
+ size_t size;
+ bool owned;
+} upb_deflist;
+
+// We keep a stack of all the messages scopes we are currently in, as well as
+// the top-level file scope. This is necessary to correctly qualify the
+// definitions that are contained inside. "name" tracks the name of the
+// message or package (a bare name -- not qualified by any enclosing scopes).
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+ char *name;
+ // Index of the first def that is under this scope. For msgdefs, the
+ // msgdef itself is at start-1.
+ int start;
+} upb_descreader_frame;
+
+// The maximum number of nested declarations that are allowed, ie.
+// message Foo {
+// message Bar {
+// message Baz {
+// }
+// }
+// }
+//
+// This is a resource limit that affects how big our runtime stack can grow.
+// TODO: make this a runtime-settable property of the Reader instance.
+#define UPB_MAX_MESSAGE_NESTING 64
+
+// Class that receives descriptor data according to the descriptor.proto schema
+// and use it to build upb::Defs corresponding to that schema.
+UPB_DEFINE_CLASS0(upb::descriptor::Reader,
+ public:
+ // These handlers must have come from NewHandlers() and must outlive the
+ // Reader.
+ //
+ // TODO: generate the handlers statically (like we do with the
+ // descriptor.proto defs) so that there is no need to pass this parameter (or
+ // to build/memory-manage the handlers at runtime at all). Unfortunately this
+ // is a bit tricky to implement for Handlers, but necessary to simplify this
+ // interface.
+ Reader(const Handlers* handlers, Status* status);
+ ~Reader();
+
+ // Resets the reader's state and discards any defs it may have built.
+ void Reset();
+
+ // The reader's input; this is where descriptor.proto data should be sent.
+ Sink* input();
+
+ // Returns an array of all defs that have been parsed, and transfers ownership
+ // of them to "owner". The number of defs is stored in *n. Ownership of the
+ // returned array is retained and is invalidated by any other call into
+ // Reader.
+ //
+ // These defs are not frozen or resolved; they are ready to be added to a
+ // symtab.
+ upb::Def** GetDefs(void* owner, int* n);
+
+ // Builds and returns handlers for the reader, owned by "owner."
+ static Handlers* NewHandlers(const void* owner);
+,
+UPB_DEFINE_STRUCT0(upb_descreader,
+ upb_sink sink;
+ upb_deflist defs;
+ upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING];
+ int stack_len;
+
+ uint32_t number;
+ char *name;
+ bool saw_number;
+ bool saw_name;
+
+ char *default_string;
+
+ upb_fielddef *f;
+));
+
+UPB_BEGIN_EXTERN_C // {
+
+// C API.
+void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers,
+ upb_status *status);
+void upb_descreader_uninit(upb_descreader *r);
+void upb_descreader_reset(upb_descreader *r);
+upb_sink *upb_descreader_input(upb_descreader *r);
+upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n);
+const upb_handlers *upb_descreader_newhandlers(const void *owner);
+
+UPB_END_EXTERN_C // }
+
+#ifdef __cplusplus
+// C++ implementation details. /////////////////////////////////////////////////
+namespace upb {
+namespace descriptor {
+inline Reader::Reader(const Handlers *h, Status *s) {
+ upb_descreader_init(this, h, s);
+}
+inline Reader::~Reader() { upb_descreader_uninit(this); }
+inline void Reader::Reset() { upb_descreader_reset(this); }
+inline Sink* Reader::input() { return upb_descreader_input(this); }
+inline upb::Def** Reader::GetDefs(void* owner, int* n) {
+ return upb_descreader_getdefs(this, owner, n);
+}
+} // namespace descriptor
+} // namespace upb
+#endif
+
+#endif // UPB_DESCRIPTOR_H
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009-2014 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * Internal-only definitions for the decoder.
+ */
+
+#ifndef UPB_DECODER_INT_H_
+#define UPB_DECODER_INT_H_
+
+#include <stdlib.h>
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009-2014 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * upb::pb::Decoder implements a high performance, streaming, resumable decoder
+ * for the binary protobuf format.
+ *
+ * This interface works the same regardless of what decoder backend is being
+ * used. A client of this class does not need to know whether decoding is using
+ * a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder. By default,
+ * it will always use the fastest available decoder. However, you can call
+ * set_allow_jit(false) to disable any JIT decoder that might be available.
+ * This is primarily useful for testing purposes.
+ */
+
+#ifndef UPB_DECODER_H_
+#define UPB_DECODER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class CodeCache;
+class Decoder;
+class DecoderMethod;
+class DecoderMethodOptions;
+} // namespace pb
+} // namespace upb
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::CodeCache, upb_pbcodecache);
+UPB_DECLARE_TYPE(upb::pb::Decoder, upb_pbdecoder);
+UPB_DECLARE_TYPE(upb::pb::DecoderMethod, upb_pbdecodermethod);
+UPB_DECLARE_TYPE(upb::pb::DecoderMethodOptions, upb_pbdecodermethodopts);
+
+// The maximum that any submessages can be nested. Matches proto2's limit.
+// This specifies the size of the decoder's statically-sized array and therefore
+// setting it high will cause the upb::pb::Decoder object to be larger.
+//
+// If necessary we can add a runtime-settable property to Decoder that allow
+// this to be larger than the compile-time setting, but this would add
+// complexity, particularly since we would have to decide how/if to give users
+// the ability to set a custom memory allocation function.
+#define UPB_DECODER_MAX_NESTING 64
+
+// Internal-only struct used by the decoder.
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+ // Space optimization note: we store two pointers here that the JIT
+ // doesn't need at all; the upb_handlers* inside the sink and
+ // the dispatch table pointer. We can optimze so that the JIT uses
+ // smaller stack frames than the interpreter. The only thing we need
+ // to guarantee is that the fallback routines can find end_ofs.
+ upb_sink sink;
+
+ // The absolute stream offset of the end-of-frame delimiter.
+ // Non-delimited frames (groups and non-packed repeated fields) reuse the
+ // delimiter of their parent, even though the frame may not end there.
+ //
+ // NOTE: the JIT stores a slightly different value here for non-top frames.
+ // It stores the value relative to the end of the enclosed message. But the
+ // top frame is still stored the same way, which is important for ensuring
+ // that calls from the JIT into C work correctly.
+ uint64_t end_ofs;
+ const uint32_t *base;
+
+ // 0 indicates a length-delimited field.
+ // A positive number indicates a known group.
+ // A negative number indicates an unknown group.
+ int32_t groupnum;
+ upb_inttable *dispatch; // Not used by the JIT.
+} upb_pbdecoder_frame;
+
+// The parameters one uses to construct a DecoderMethod.
+// TODO(haberman): move allowjit here? Seems more convenient for users.
+UPB_DEFINE_CLASS0(upb::pb::DecoderMethodOptions,
+ public:
+ // Parameter represents the destination handlers that this method will push
+ // to.
+ explicit DecoderMethodOptions(const Handlers* dest_handlers);
+
+ // Should the decoder push submessages to lazy handlers for fields that have
+ // them? The caller should set this iff the lazy handlers expect data that is
+ // in protobuf binary format and the caller wishes to lazy parse it.
+ void set_lazy(bool lazy);
+,
+UPB_DEFINE_STRUCT0(upb_pbdecodermethodopts,
+ const upb_handlers *handlers;
+ bool lazy;
+));
+
+// Represents the code to parse a protobuf according to a destination Handlers.
+UPB_DEFINE_CLASS1(upb::pb::DecoderMethod, upb::RefCounted,
+ public:
+ // From upb::ReferenceCounted.
+ void Ref(const void* owner) const;
+ void Unref(const void* owner) const;
+ void DonateRef(const void* from, const void* to) const;
+ void CheckRef(const void* owner) const;
+
+ // The destination handlers that are statically bound to this method.
+ // This method is only capable of outputting to a sink that uses these
+ // handlers.
+ const Handlers* dest_handlers() const;
+
+ // The input handlers for this decoder method.
+ const BytesHandler* input_handler() const;
+
+ // Whether this method is native.
+ bool is_native() const;
+
+ // Convenience method for generating a DecoderMethod without explicitly
+ // creating a CodeCache.
+ static reffed_ptr<const DecoderMethod> New(const DecoderMethodOptions& opts);
+
+ private:
+ UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod);
+,
+UPB_DEFINE_STRUCT(upb_pbdecodermethod, upb_refcounted,
+ // While compiling, the base is relative in "ofs", after compiling it is
+ // absolute in "ptr".
+ union {
+ uint32_t ofs; // PC offset of method.
+ void *ptr; // Pointer to bytecode or machine code for this method.
+ } code_base;
+
+ // The decoder method group to which this method belongs. We own a ref.
+ // Owning a ref on the entire group is more coarse-grained than is strictly
+ // necessary; all we truly require is that methods we directly reference
+ // outlive us, while the group could contain many other messages we don't
+ // require. But the group represents the messages that were
+ // allocated+compiled together, so it makes the most sense to free them
+ // together also.
+ const upb_refcounted *group;
+
+ // Whether this method is native code or bytecode.
+ bool is_native_;
+
+ // The handler one calls to invoke this method.
+ upb_byteshandler input_handler_;
+
+ // The destination handlers this method is bound to. We own a ref.
+ const upb_handlers *dest_handlers_;
+
+ // Dispatch table -- used by both bytecode decoder and JIT when encountering a
+ // field number that wasn't the one we were expecting to see. See
+ // decoder.int.h for the layout of this table.
+ upb_inttable dispatch;
+));
+
+// A Decoder receives binary protobuf data on its input sink and pushes the
+// decoded data to its output sink.
+UPB_DEFINE_CLASS0(upb::pb::Decoder,
+ public:
+ // Constructs a decoder instance for the given method, which must outlive this
+ // decoder. Any errors during parsing will be set on the given status, which
+ // must also outlive this decoder.
+ Decoder(const DecoderMethod* method, Status* status);
+ ~Decoder();
+
+ // Returns the DecoderMethod this decoder is parsing from.
+ // TODO(haberman): Do users need to be able to rebind this?
+ const DecoderMethod* method() const;
+
+ // Resets the state of the decoder.
+ void Reset();
+
+ // Returns number of bytes successfully parsed.
+ //
+ // This can be useful for determining the stream position where an error
+ // occurred.
+ //
+ // This value may not be up-to-date when called from inside a parsing
+ // callback.
+ uint64_t BytesParsed() const;
+
+ // Resets the output sink of the Decoder.
+ // The given sink must match method()->dest_handlers().
+ //
+ // This must be called at least once before the decoder can be used. It may
+ // only be called with the decoder is in a state where it was just created or
+ // reset with pipeline.Reset(). The given sink must be from the same pipeline
+ // as this decoder.
+ bool ResetOutput(Sink* sink);
+
+ // The sink on which this decoder receives input.
+ BytesSink* input();
+
+ private:
+ UPB_DISALLOW_COPY_AND_ASSIGN(Decoder);
+,
+UPB_DEFINE_STRUCT0(upb_pbdecoder, UPB_QUOTE(
+ // Our input sink.
+ upb_bytessink input_;
+
+ // The decoder method we are parsing with (owned).
+ const upb_pbdecodermethod *method_;
+
+ size_t call_len;
+ const uint32_t *pc, *last;
+
+ // Current input buffer and its stream offset.
+ const char *buf, *ptr, *end, *checkpoint;
+
+ // End of the delimited region, relative to ptr, or NULL if not in this buf.
+ const char *delim_end;
+
+ // End of the delimited region, relative to ptr, or end if not in this buf.
+ const char *data_end;
+
+ // Overall stream offset of "buf."
+ uint64_t bufstart_ofs;
+
+ // Buffer for residual bytes not parsed from the previous buffer.
+ // The maximum number of residual bytes we require is 12; a five-byte
+ // unknown tag plus an eight-byte value, less one because the value
+ // is only a partial value.
+ char residual[12];
+ char *residual_end;
+
+ // Stores the user buffer passed to our decode function.
+ const char *buf_param;
+ size_t size_param;
+ const upb_bufhandle *handle;
+
+#ifdef UPB_USE_JIT_X64
+ // Used momentarily by the generated code to store a value while a user
+ // function is called.
+ uint32_t tmp_len;
+
+ const void *saved_rsp;
+#endif
+
+ upb_status *status;
+
+ // Our internal stack.
+ upb_pbdecoder_frame *top, *limit;
+ upb_pbdecoder_frame stack[UPB_DECODER_MAX_NESTING];
+#ifdef UPB_USE_JIT_X64
+ // Each native stack frame needs two pointers, plus we need a few frames for
+ // the enter/exit trampolines.
+ const uint32_t *callstack[(UPB_DECODER_MAX_NESTING * 2) + 10];
+#else
+ const uint32_t *callstack[UPB_DECODER_MAX_NESTING];
+#endif
+)));
+
+// A class for caching protobuf processing code, whether bytecode for the
+// interpreted decoder or machine code for the JIT.
+//
+// This class is not thread-safe.
+UPB_DEFINE_CLASS0(upb::pb::CodeCache,
+ public:
+ CodeCache();
+ ~CodeCache();
+
+ // Whether the cache is allowed to generate machine code. Defaults to true.
+ // There is no real reason to turn it off except for testing or if you are
+ // having a specific problem with the JIT.
+ //
+ // Note that allow_jit = true does not *guarantee* that the code will be JIT
+ // compiled. If this platform is not supported or the JIT was not compiled
+ // in, the code may still be interpreted.
+ bool allow_jit() const;
+
+ // This may only be called when the object is first constructed, and prior to
+ // any code generation, otherwise returns false and does nothing.
+ bool set_allow_jit(bool allow);
+
+ // Returns a DecoderMethod that can push data to the given handlers.
+ // If a suitable method already exists, it will be returned from the cache.
+ //
+ // Specifying the destination handlers here allows the DecoderMethod to be
+ // statically bound to the destination handlers if possible, which can allow
+ // more efficient decoding. However the returned method may or may not
+ // actually be statically bound. But in all cases, the returned method can
+ // push data to the given handlers.
+ const DecoderMethod *GetDecoderMethod(const DecoderMethodOptions& opts);
+
+ // If/when someone needs to explicitly create a dynamically-bound
+ // DecoderMethod*, we can add a method to get it here.
+
+ private:
+ UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache);
+,
+UPB_DEFINE_STRUCT0(upb_pbcodecache,
+ bool allow_jit_;
+
+ // Array of mgroups.
+ upb_inttable groups;
+));
+
+UPB_BEGIN_EXTERN_C // {
+
+void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *method,
+ upb_status *status);
+void upb_pbdecoder_uninit(upb_pbdecoder *d);
+void upb_pbdecoder_reset(upb_pbdecoder *d);
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d);
+bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink *sink);
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d);
+uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d);
+
+void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts,
+ const upb_handlers *h);
+void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy);
+
+void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner);
+void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m, const void *owner);
+void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m,
+ const void *from, const void *to);
+void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m,
+ const void *owner);
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+ const upb_pbdecodermethod *m);
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+ const upb_pbdecodermethod *m);
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m);
+const upb_pbdecodermethod *upb_pbdecodermethod_new(
+ const upb_pbdecodermethodopts *opts, const void *owner);
+
+void upb_pbcodecache_init(upb_pbcodecache *c);
+void upb_pbcodecache_uninit(upb_pbcodecache *c);
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c);
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow);
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
+ upb_pbcodecache *c, const upb_pbdecodermethodopts *opts);
+
+UPB_END_EXTERN_C // }
+
+#ifdef __cplusplus
+
+namespace upb {
+
+namespace pb {
+
+inline Decoder::Decoder(const DecoderMethod* m, Status* s) {
+ upb_pbdecoder_init(this, m, s);
+}
+inline Decoder::~Decoder() {
+ upb_pbdecoder_uninit(this);
+}
+inline const DecoderMethod* Decoder::method() const {
+ return upb_pbdecoder_method(this);
+}
+inline void Decoder::Reset() {
+ upb_pbdecoder_reset(this);
+}
+inline uint64_t Decoder::BytesParsed() const {
+ return upb_pbdecoder_bytesparsed(this);
+}
+inline bool Decoder::ResetOutput(Sink* sink) {
+ return upb_pbdecoder_resetoutput(this, sink);
+}
+inline BytesSink* Decoder::input() {
+ return upb_pbdecoder_input(this);
+}
+
+inline DecoderMethodOptions::DecoderMethodOptions(const Handlers* h) {
+ upb_pbdecodermethodopts_init(this, h);
+}
+inline void DecoderMethodOptions::set_lazy(bool lazy) {
+ upb_pbdecodermethodopts_setlazy(this, lazy);
+}
+
+inline void DecoderMethod::Ref(const void *owner) const {
+ upb_pbdecodermethod_ref(this, owner);
+}
+inline void DecoderMethod::Unref(const void *owner) const {
+ upb_pbdecodermethod_unref(this, owner);
+}
+inline void DecoderMethod::DonateRef(const void *from, const void *to) const {
+ upb_pbdecodermethod_donateref(this, from, to);
+}
+inline void DecoderMethod::CheckRef(const void *owner) const {
+ upb_pbdecodermethod_checkref(this, owner);
+}
+inline const Handlers* DecoderMethod::dest_handlers() const {
+ return upb_pbdecodermethod_desthandlers(this);
+}
+inline const BytesHandler* DecoderMethod::input_handler() const {
+ return upb_pbdecodermethod_inputhandler(this);
+}
+inline bool DecoderMethod::is_native() const {
+ return upb_pbdecodermethod_isnative(this);
+}
+// static
+inline reffed_ptr<const DecoderMethod> DecoderMethod::New(
+ const DecoderMethodOptions &opts) {
+ const upb_pbdecodermethod *m = upb_pbdecodermethod_new(&opts, &m);
+ return reffed_ptr<const DecoderMethod>(m, &m);
+}
+
+inline CodeCache::CodeCache() {
+ upb_pbcodecache_init(this);
+}
+inline CodeCache::~CodeCache() {
+ upb_pbcodecache_uninit(this);
+}
+inline bool CodeCache::allow_jit() const {
+ return upb_pbcodecache_allowjit(this);
+}
+inline bool CodeCache::set_allow_jit(bool allow) {
+ return upb_pbcodecache_setallowjit(this, allow);
+}
+inline const DecoderMethod *CodeCache::GetDecoderMethod(
+ const DecoderMethodOptions& opts) {
+ return upb_pbcodecache_getdecodermethod(this, &opts);
+}
+
+} // namespace pb
+} // namespace upb
+
+#endif // __cplusplus
+
+#endif /* UPB_DECODER_H_ */
+
+// Opcode definitions. The canonical meaning of each opcode is its
+// implementation in the interpreter (the JIT is written to match this).
+//
+// All instructions have the opcode in the low byte.
+// Instruction format for most instructions is:
+//
+// +-------------------+--------+
+// | arg (24) | op (8) |
+// +-------------------+--------+
+//
+// Exceptions are indicated below. A few opcodes are multi-word.
+typedef enum {
+ // Opcodes 1-8, 13, 15-18 parse their respective descriptor types.
+ // Arg for all of these is the upb selector for this field.
+#define T(type) OP_PARSE_ ## type = UPB_DESCRIPTOR_TYPE_ ## type
+ T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32),
+ T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64),
+#undef T
+ OP_STARTMSG = 9, // No arg.
+ OP_ENDMSG = 10, // No arg.
+ OP_STARTSEQ = 11,
+ OP_ENDSEQ = 12,
+ OP_STARTSUBMSG = 14,
+ OP_ENDSUBMSG = 19,
+ OP_STARTSTR = 20,
+ OP_STRING = 21,
+ OP_ENDSTR = 22,
+
+ OP_PUSHTAGDELIM = 23, // No arg.
+ OP_PUSHLENDELIM = 24, // No arg.
+ OP_POP = 25, // No arg.
+ OP_SETDELIM = 26, // No arg.
+ OP_SETBIGGROUPNUM = 27, // two words: | unused (24) | opc || groupnum (32) |
+ OP_CHECKDELIM = 28,
+ OP_CALL = 29,
+ OP_RET = 30,
+ OP_BRANCH = 31,
+
+ // Different opcodes depending on how many bytes expected.
+ OP_TAG1 = 32, // | expected tag (16) | jump target (8) | opc (8) |
+ OP_TAG2 = 33, // | expected tag (16) | jump target (8) | opc (8) |
+ OP_TAGN = 34, // three words:
+ // | unused (16) | jump target(8) | opc (8) |
+ // | expected tag 1 (32) |
+ // | expected tag 2 (32) |
+
+ OP_SETDISPATCH = 35, // N words:
+ // | unused (24) | opc |
+ // | upb_inttable* (32 or 64) |
+
+ OP_DISPATCH = 36, // No arg.
+
+ OP_HALT = 37, // No arg.
+} opcode;
+
+#define OP_MAX OP_HALT
+
+UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; }
+
+// Method group; represents a set of decoder methods that had their code
+// emitted together, and must therefore be freed together. Immutable once
+// created. It is possible we may want to expose this to users at some point.
+//
+// Overall ownership of Decoder objects looks like this:
+//
+// +----------+
+// | | <---> DecoderMethod
+// | method |
+// CodeCache ---> | group | <---> DecoderMethod
+// | |
+// | (mgroup) | <---> DecoderMethod
+// +----------+
+typedef struct {
+ upb_refcounted base;
+
+ // Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod. We own refs on the
+ // methods.
+ upb_inttable methods;
+
+ // When we add the ability to link to previously existing mgroups, we'll
+ // need an array of mgroups we reference here, and own refs on them.
+
+ // The bytecode for our methods, if any exists. Owned by us.
+ uint32_t *bytecode;
+ uint32_t *bytecode_end;
+
+#ifdef UPB_USE_JIT_X64
+ // JIT-generated machine code, if any.
+ upb_string_handlerfunc *jit_code;
+ // The size of the jit_code (required to munmap()).
+ size_t jit_size;
+ char *debug_info;
+ void *dl;
+#endif
+} mgroup;
+
+// Decoder entry points; used as handlers.
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint);
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint);
+size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
+ size_t size, const upb_bufhandle *handle);
+bool upb_pbdecoder_end(void *closure, const void *handler_data);
+
+// Decoder-internal functions that the JIT calls to handle fallback paths.
+int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
+ size_t size, const upb_bufhandle *handle);
+size_t upb_pbdecoder_suspend(upb_pbdecoder *d);
+int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum,
+ uint8_t wire_type);
+int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected);
+int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64);
+int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32);
+int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64);
+void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg);
+
+// Error messages that are shared between the bytecode and JIT decoders.
+extern const char *kPbDecoderStackOverflow;
+
+// Access to decoderplan members needed by the decoder.
+const char *upb_pbdecoder_getopname(unsigned int op);
+
+// JIT codegen entry point.
+void upb_pbdecoder_jit(mgroup *group);
+void upb_pbdecoder_freejit(mgroup *group);
+
+// A special label that means "do field dispatch for this message and branch to
+// wherever that takes you."
+#define LABEL_DISPATCH 0
+
+// A special slot in the dispatch table that stores the epilogue (ENDMSG and/or
+// RET) for branching to when we find an appropriate ENDGROUP tag.
+#define DISPATCH_ENDMSG 0
+
+// It's important to use this invalid wire type instead of 0 (which is a valid
+// wire type).
+#define NO_WIRE_TYPE 0xff
+
+// The dispatch table layout is:
+// [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ]
+//
+// If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup
+// (UPB_MAX_FIELDNUMBER + fieldnum) and jump there.
+//
+// We need two wire types because of packed/non-packed compatibility. A
+// primitive repeated field can use either wire type and be valid. While we
+// could key the table on fieldnum+wiretype, the table would be 8x sparser.
+//
+// Storing two wire types in the primary value allows us to quickly rule out
+// the second wire type without needing to do a separate lookup (this case is
+// less common than an unknown field).
+UPB_INLINE uint64_t upb_pbdecoder_packdispatch(uint64_t ofs, uint8_t wt1,
+ uint8_t wt2) {
+ return (ofs << 16) | (wt2 << 8) | wt1;
+}
+
+UPB_INLINE void upb_pbdecoder_unpackdispatch(uint64_t dispatch, uint64_t *ofs,
+ uint8_t *wt1, uint8_t *wt2) {
+ *wt1 = (uint8_t)dispatch;
+ *wt2 = (uint8_t)(dispatch >> 8);
+ *ofs = dispatch >> 16;
+}
+
+// All of the functions in decoder.c that return int32_t return values according
+// to the following scheme:
+// 1. negative values indicate a return code from the following list.
+// 2. positive values indicate that error or end of buffer was hit, and
+// that the decode function should immediately return the given value
+// (the decoder state has already been suspended and is ready to be
+// resumed).
+#define DECODE_OK -1
+#define DECODE_MISMATCH -2 // Used only from checktag_slow().
+#define DECODE_ENDGROUP -3 // Used only from checkunknown().
+
+#define CHECK_RETURN(x) { int32_t ret = x; if (ret >= 0) return ret; }
+
+#endif // UPB_DECODER_INT_H_
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2011 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * A number of routines for varint manipulation (we keep them all around to
+ * have multiple approaches available for benchmarking).
+ */
+
+#ifndef UPB_VARINT_DECODER_H_
+#define UPB_VARINT_DECODER_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// A list of types as they are encoded on-the-wire.
+typedef enum {
+ UPB_WIRE_TYPE_VARINT = 0,
+ UPB_WIRE_TYPE_64BIT = 1,
+ UPB_WIRE_TYPE_DELIMITED = 2,
+ UPB_WIRE_TYPE_START_GROUP = 3,
+ UPB_WIRE_TYPE_END_GROUP = 4,
+ UPB_WIRE_TYPE_32BIT = 5,
+} upb_wiretype_t;
+
+#define UPB_MAX_WIRE_TYPE 5
+
+// The maximum number of bytes that it takes to encode a 64-bit varint.
+// Note that with a better encoding this could be 9 (TODO: write up a
+// wiki document about this).
+#define UPB_PB_VARINT_MAX_LEN 10
+
+// Array of the "native" (ie. non-packed-repeated) wire type for the given a
+// descriptor type (upb_descriptortype_t).
+extern const uint8_t upb_pb_native_wire_types[];
+
+/* Zig-zag encoding/decoding **************************************************/
+
+UPB_INLINE int32_t upb_zzdec_32(uint32_t n) {
+ return (n >> 1) ^ -(int32_t)(n & 1);
+}
+UPB_INLINE int64_t upb_zzdec_64(uint64_t n) {
+ return (n >> 1) ^ -(int64_t)(n & 1);
+}
+UPB_INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
+UPB_INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
+
+/* Decoding *******************************************************************/
+
+// All decoding functions return this struct by value.
+typedef struct {
+ const char *p; // NULL if the varint was unterminated.
+ uint64_t val;
+} upb_decoderet;
+
+// Four functions for decoding a varint of at most eight bytes. They are all
+// functionally identical, but are implemented in different ways and likely have
+// different performance profiles. We keep them around for performance testing.
+//
+// Note that these functions may not read byte-by-byte, so they must not be used
+// unless there are at least eight bytes left in the buffer!
+upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_wright(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r);
+
+// Template for a function that checks the first two bytes with branching
+// and dispatches 2-10 bytes with a separate function. Note that this may read
+// up to 10 bytes, so it must not be used unless there are at least ten bytes
+// left in the buffer!
+#define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function) \
+UPB_INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) { \
+ uint8_t *p = (uint8_t*)_p; \
+ if ((*p & 0x80) == 0) { upb_decoderet r = {_p + 1, *p & 0x7fU}; return r; } \
+ upb_decoderet r = {_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7)}; \
+ if ((*(p + 1) & 0x80) == 0) return r; \
+ return decode_max8_function(r); \
+}
+
+UPB_VARINT_DECODER_CHECK2(branch32, upb_vdecode_max8_branch32);
+UPB_VARINT_DECODER_CHECK2(branch64, upb_vdecode_max8_branch64);
+UPB_VARINT_DECODER_CHECK2(wright, upb_vdecode_max8_wright);
+UPB_VARINT_DECODER_CHECK2(massimino, upb_vdecode_max8_massimino);
+#undef UPB_VARINT_DECODER_CHECK2
+
+// Our canonical functions for decoding varints, based on the currently
+// favored best-performing implementations.
+UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) {
+ if (sizeof(long) == 8)
+ return upb_vdecode_check2_branch64(p);
+ else
+ return upb_vdecode_check2_branch32(p);
+}
+
+UPB_INLINE upb_decoderet upb_vdecode_max8_fast(upb_decoderet r) {
+ return upb_vdecode_max8_massimino(r);
+}
+
+
+/* Encoding *******************************************************************/
+
+UPB_INLINE int upb_value_size(uint64_t val) {
+#ifdef __GNUC__
+ int high_bit = 63 - __builtin_clzll(val); // 0-based, undef if val == 0.
+#else
+ int high_bit = 0;
+ uint64_t tmp = val;
+ while(tmp >>= 1) high_bit++;
+#endif
+ return val == 0 ? 1 : high_bit / 8 + 1;
+}
+
+// Encodes a 64-bit varint into buf (which must be >=UPB_PB_VARINT_MAX_LEN
+// bytes long), returning how many bytes were used.
+//
+// TODO: benchmark and optimize if necessary.
+UPB_INLINE size_t upb_vencode64(uint64_t val, char *buf) {
+ if (val == 0) { buf[0] = 0; return 1; }
+ size_t i = 0;
+ while (val) {
+ uint8_t byte = val & 0x7fU;
+ val >>= 7;
+ if (val) byte |= 0x80U;
+ buf[i++] = byte;
+ }
+ return i;
+}
+
+UPB_INLINE size_t upb_varint_size(uint64_t val) {
+ char buf[UPB_PB_VARINT_MAX_LEN];
+ return upb_vencode64(val, buf);
+}
+
+// Encodes a 32-bit varint, *not* sign-extended.
+UPB_INLINE uint64_t upb_vencode32(uint32_t val) {
+ char buf[UPB_PB_VARINT_MAX_LEN];
+ size_t bytes = upb_vencode64(val, buf);
+ uint64_t ret = 0;
+ assert(bytes <= 5);
+ memcpy(&ret, buf, bytes);
+ assert(ret <= 0xffffffffffU);
+ return ret;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* UPB_VARINT_DECODER_H_ */
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009-2010 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * Implements a set of upb_handlers that write protobuf data to the binary wire
+ * format.
+ *
+ * This encoder implementation does not have any access to any out-of-band or
+ * precomputed lengths for submessages, so it must buffer submessages internally
+ * before it can emit the first byte.
+ */
+
+#ifndef UPB_ENCODER_H_
+#define UPB_ENCODER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class Encoder;
+} // namespace pb
+} // namespace upb
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::Encoder, upb_pb_encoder);
+
+#define UPB_PBENCODER_MAX_NESTING 100
+
+/* upb::pb::Encoder ***********************************************************/
+
+// The output buffer is divided into segments; a segment is a string of data
+// that is "ready to go" -- it does not need any varint lengths inserted into
+// the middle. The seams between segments are where varints will be inserted
+// once they are known.
+//
+// We also use the concept of a "run", which is a range of encoded bytes that
+// occur at a single submessage level. Every segment contains one or more runs.
+//
+// A segment can span messages. Consider:
+//
+// .--Submessage lengths---------.
+// | | |
+// | V V
+// V | |--------------- | |-----------------
+// Submessages: | |-----------------------------------------------
+// Top-level msg: ------------------------------------------------------------
+//
+// Segments: ----- ------------------- -----------------
+// Runs: *---- *--------------*--- *----------------
+// (* marks the start)
+//
+// Note that the top-level menssage is not in any segment because it does not
+// have any length preceding it.
+//
+// A segment is only interrupted when another length needs to be inserted. So
+// observe how the second segment spans both the inner submessage and part of
+// the next enclosing message.
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+ uint32_t msglen; // The length to varint-encode before this segment.
+ uint32_t seglen; // Length of the segment.
+} upb_pb_encoder_segment;
+
+UPB_DEFINE_CLASS0(upb::pb::Encoder,
+ public:
+ Encoder(const upb::Handlers* handlers);
+ ~Encoder();
+
+ static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* msg);
+
+ // Resets the state of the printer, so that it will expect to begin a new
+ // document.
+ void Reset();
+
+ // Resets the output pointer which will serve as our closure.
+ void ResetOutput(BytesSink* output);
+
+ // The input to the encoder.
+ Sink* input();
+
+ private:
+ UPB_DISALLOW_COPY_AND_ASSIGN(Encoder);
+,
+UPB_DEFINE_STRUCT0(upb_pb_encoder, UPB_QUOTE(
+ // Our input and output.
+ upb_sink input_;
+ upb_bytessink *output_;
+
+ // The "subclosure" -- used as the inner closure as part of the bytessink
+ // protocol.
+ void *subc;
+
+ // The output buffer and limit, and our current write position. "buf"
+ // initially points to "initbuf", but is dynamically allocated if we need to
+ // grow beyond the initial size.
+ char *buf, *ptr, *limit;
+
+ // The beginning of the current run, or undefined if we are at the top level.
+ char *runbegin;
+
+ // The list of segments we are accumulating.
+ upb_pb_encoder_segment *segbuf, *segptr, *seglimit;
+
+ // The stack of enclosing submessages. Each entry in the stack points to the
+ // segment where this submessage's length is being accumulated.
+ int stack[UPB_PBENCODER_MAX_NESTING], *top, *stacklimit;
+
+ // Depth of startmsg/endmsg calls.
+ int depth;
+
+ // Initial buffers for the output buffer and segment buffer. If we outgrow
+ // these we will dynamically allocate bigger ones.
+ char initbuf[256];
+ upb_pb_encoder_segment seginitbuf[32];
+)));
+
+UPB_BEGIN_EXTERN_C
+
+const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
+ const void *owner);
+void upb_pb_encoder_reset(upb_pb_encoder *e);
+upb_sink *upb_pb_encoder_input(upb_pb_encoder *p);
+void upb_pb_encoder_init(upb_pb_encoder *e, const upb_handlers *h);
+void upb_pb_encoder_resetoutput(upb_pb_encoder *e, upb_bytessink *output);
+void upb_pb_encoder_uninit(upb_pb_encoder *e);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace pb {
+inline Encoder::Encoder(const upb::Handlers* handlers) {
+ upb_pb_encoder_init(this, handlers);
+}
+inline Encoder::~Encoder() {
+ upb_pb_encoder_uninit(this);
+}
+inline void Encoder::Reset() {
+ upb_pb_encoder_reset(this);
+}
+inline void Encoder::ResetOutput(BytesSink* output) {
+ upb_pb_encoder_resetoutput(this, output);
+}
+inline Sink* Encoder::input() {
+ return upb_pb_encoder_input(this);
+}
+inline reffed_ptr<const Handlers> Encoder::NewHandlers(
+ const upb::MessageDef *md) {
+ const Handlers* h = upb_pb_encoder_newhandlers(md, &h);
+ return reffed_ptr<const Handlers>(h, &h);
+}
+} // namespace pb
+} // namespace upb
+
+#endif
+
+#endif /* UPB_ENCODER_H_ */
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * upb's core components like upb_decoder and upb_msg are carefully designed to
+ * avoid depending on each other for maximum orthogonality. In other words,
+ * you can use a upb_decoder to decode into *any* kind of structure; upb_msg is
+ * just one such structure. A upb_msg can be serialized/deserialized into any
+ * format, protobuf binary format is just one such format.
+ *
+ * However, for convenience we provide functions here for doing common
+ * operations like deserializing protobuf binary format into a upb_msg. The
+ * compromise is that this file drags in almost all of upb as a dependency,
+ * which could be undesirable if you're trying to use a trimmed-down build of
+ * upb.
+ *
+ * While these routines are convenient, they do not reuse any encoding/decoding
+ * state. For example, if a decoder is JIT-based, it will be re-JITted every
+ * time these functions are called. For this reason, if you are parsing lots
+ * of data and efficiency is an issue, these may not be the best functions to
+ * use (though they are useful for prototyping, before optimizing).
+ */
+
+#ifndef UPB_GLUE_H
+#define UPB_GLUE_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Loads all defs from the given protobuf binary descriptor, setting default
+// accessors and a default layout on all messages. The caller owns the
+// returned array of defs, which will be of length *n. On error NULL is
+// returned and status is set (if non-NULL).
+upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n,
+ void *owner, upb_status *status);
+
+// Like the previous but also adds the loaded defs to the given symtab.
+bool upb_load_descriptor_into_symtab(upb_symtab *symtab, const char *str,
+ size_t len, upb_status *status);
+
+// Like the previous but also reads the descriptor from the given filename.
+bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname,
+ upb_status *status);
+
+// Reads the given filename into a character string, returning NULL if there
+// was an error.
+char *upb_readfile(const char *filename, size_t *len);
+
+#ifdef __cplusplus
+} /* extern "C" */
+
+namespace upb {
+
+// All routines that load descriptors expect the descriptor to be a
+// FileDescriptorSet.
+inline bool LoadDescriptorFileIntoSymtab(SymbolTable* s, const char *fname,
+ Status* status) {
+ return upb_load_descriptor_file_into_symtab(s, fname, status);
+}
+
+inline bool LoadDescriptorIntoSymtab(SymbolTable* s, const char* str,
+ size_t len, Status* status) {
+ return upb_load_descriptor_into_symtab(s, str, len, status);
+}
+
+// Templated so it can accept both string and std::string.
+template <typename T>
+bool LoadDescriptorIntoSymtab(SymbolTable* s, const T& desc, Status* status) {
+ return upb_load_descriptor_into_symtab(s, desc.c_str(), desc.size(), status);
+}
+
+} // namespace upb
+
+#endif
+
+#endif
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+#ifndef UPB_TEXT_H_
+#define UPB_TEXT_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class TextPrinter;
+} // namespace pb
+} // namespace upb
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::TextPrinter, upb_textprinter);
+
+UPB_DEFINE_CLASS0(upb::pb::TextPrinter,
+ public:
+ // The given handlers must have come from NewHandlers(). It must outlive the
+ // TextPrinter.
+ explicit TextPrinter(const upb::Handlers* handlers);
+
+ void SetSingleLineMode(bool single_line);
+
+ bool ResetOutput(BytesSink* output);
+ Sink* input();
+
+ // If handler caching becomes a requirement we can add a code cache as in
+ // decoder.h
+ static reffed_ptr<const Handlers> NewHandlers(const MessageDef* md);
+
+ private:
+,
+UPB_DEFINE_STRUCT0(upb_textprinter,
+ upb_sink input_;
+ upb_bytessink *output_;
+ int indent_depth_;
+ bool single_line_;
+ void *subc;
+));
+
+UPB_BEGIN_EXTERN_C // {
+
+// C API.
+void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h);
+void upb_textprinter_uninit(upb_textprinter *p);
+bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output);
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line);
+upb_sink *upb_textprinter_input(upb_textprinter *p);
+
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+ const void *owner);
+
+UPB_END_EXTERN_C // }
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace pb {
+inline TextPrinter::TextPrinter(const upb::Handlers* handlers) {
+ upb_textprinter_init(this, handlers);
+}
+inline void TextPrinter::SetSingleLineMode(bool single_line) {
+ upb_textprinter_setsingleline(this, single_line);
+}
+inline bool TextPrinter::ResetOutput(BytesSink* output) {
+ return upb_textprinter_resetoutput(this, output);
+}
+inline Sink* TextPrinter::input() {
+ return upb_textprinter_input(this);
+}
+inline reffed_ptr<const Handlers> TextPrinter::NewHandlers(
+ const MessageDef *md) {
+ const Handlers* h = upb_textprinter_newhandlers(md, &h);
+ return reffed_ptr<const Handlers>(h, &h);
+}
+} // namespace pb
+} // namespace upb
+
+#endif
+
+#endif /* UPB_TEXT_H_ */
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2014 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * upb::json::Parser can parse JSON according to a specific schema.
+ * Support for parsing arbitrary JSON (schema-less) will be added later.
+ */
+
+#ifndef UPB_JSON_PARSER_H_
+#define UPB_JSON_PARSER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace json {
+class Parser;
+} // namespace json
+} // namespace upb
+#endif
+
+UPB_DECLARE_TYPE(upb::json::Parser, upb_json_parser);
+
+// Internal-only struct used by the parser. A parser frame corresponds
+// one-to-one with a handler (sink) frame.
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+ upb_sink sink;
+ // The current message in which we're parsing, and the field whose value we're
+ // expecting next.
+ const upb_msgdef *m;
+ const upb_fielddef *f;
+
+ // We are in a repeated-field context, ready to emit mapentries as
+ // submessages. This flag alters the start-of-object (open-brace) behavior to
+ // begin a sequence of mapentry messages rather than a single submessage.
+ bool is_map;
+ // We are in a map-entry message context. This flag is set when parsing the
+ // value field of a single map entry and indicates to all value-field parsers
+ // (subobjects, strings, numbers, and bools) that the map-entry submessage
+ // should end as soon as the value is parsed.
+ bool is_mapentry;
+ // If |is_map| or |is_mapentry| is true, |mapfield| refers to the parent
+ // message's map field that we're currently parsing. This differs from |f|
+ // because |f| is the field in the *current* message (i.e., the map-entry
+ // message itself), not the parent's field that leads to this map.
+ const upb_fielddef *mapfield;
+} upb_jsonparser_frame;
+
+
+/* upb::json::Parser **********************************************************/
+
+#define UPB_JSON_MAX_DEPTH 64
+
+// Parses an incoming BytesStream, pushing the results to the destination sink.
+UPB_DEFINE_CLASS0(upb::json::Parser,
+ public:
+ Parser(Status* status);
+ ~Parser();
+
+ // Resets the state of the printer, so that it will expect to begin a new
+ // document.
+ void Reset();
+
+ // Resets the output pointer which will serve as our closure. Implies
+ // Reset().
+ void ResetOutput(Sink* output);
+
+ // The input to the printer.
+ BytesSink* input();
+,
+UPB_DEFINE_STRUCT0(upb_json_parser,
+ upb_byteshandler input_handler_;
+ upb_bytessink input_;
+
+ // Stack to track the JSON scopes we are in.
+ upb_jsonparser_frame stack[UPB_JSON_MAX_DEPTH];
+ upb_jsonparser_frame *top;
+ upb_jsonparser_frame *limit;
+
+ upb_status *status;
+
+ // Ragel's internal parsing stack for the parsing state machine.
+ int current_state;
+ int parser_stack[UPB_JSON_MAX_DEPTH];
+ int parser_top;
+
+ // The handle for the current buffer.
+ const upb_bufhandle *handle;
+
+ // Accumulate buffer. See details in parser.rl.
+ const char *accumulated;
+ size_t accumulated_len;
+ char *accumulate_buf;
+ size_t accumulate_buf_size;
+
+ // Multi-part text data. See details in parser.rl.
+ int multipart_state;
+ upb_selector_t string_selector;
+
+ // Input capture. See details in parser.rl.
+ const char *capture;
+
+ // Intermediate result of parsing a unicode escape sequence.
+ uint32_t digit;
+));
+
+UPB_BEGIN_EXTERN_C
+
+void upb_json_parser_init(upb_json_parser *p, upb_status *status);
+void upb_json_parser_uninit(upb_json_parser *p);
+void upb_json_parser_reset(upb_json_parser *p);
+void upb_json_parser_resetoutput(upb_json_parser *p, upb_sink *output);
+upb_bytessink *upb_json_parser_input(upb_json_parser *p);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace json {
+inline Parser::Parser(Status* status) { upb_json_parser_init(this, status); }
+inline Parser::~Parser() { upb_json_parser_uninit(this); }
+inline void Parser::Reset() { upb_json_parser_reset(this); }
+inline void Parser::ResetOutput(Sink* output) {
+ upb_json_parser_resetoutput(this, output);
+}
+inline BytesSink* Parser::input() {
+ return upb_json_parser_input(this);
+}
+} // namespace json
+} // namespace upb
+
+#endif
+
+
+#endif // UPB_JSON_PARSER_H_
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2014 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * upb::json::Printer allows you to create handlers that emit JSON
+ * according to a specific protobuf schema.
+ */
+
+#ifndef UPB_JSON_TYPED_PRINTER_H_
+#define UPB_JSON_TYPED_PRINTER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace json {
+class Printer;
+} // namespace json
+} // namespace upb
+#endif
+
+UPB_DECLARE_TYPE(upb::json::Printer, upb_json_printer);
+
+
+/* upb::json::Printer *********************************************************/
+
+// Prints an incoming stream of data to a BytesSink in JSON format.
+UPB_DEFINE_CLASS0(upb::json::Printer,
+ public:
+ Printer(const upb::Handlers* handlers);
+ ~Printer();
+
+ // Resets the state of the printer, so that it will expect to begin a new
+ // document.
+ void Reset();
+
+ // Resets the output pointer which will serve as our closure. Implies
+ // Reset().
+ void ResetOutput(BytesSink* output);
+
+ // The input to the printer.
+ Sink* input();
+
+ // Returns handlers for printing according to the specified schema.
+ static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* md);
+,
+UPB_DEFINE_STRUCT0(upb_json_printer,
+ upb_sink input_;
+ // BytesSink closure.
+ void *subc_;
+ upb_bytessink *output_;
+
+ // We track the depth so that we know when to emit startstr/endstr on the
+ // output.
+ int depth_;
+ // Have we emitted the first element? This state is necessary to emit commas
+ // without leaving a trailing comma in arrays/maps. We keep this state per
+ // frame depth.
+ //
+ // Why max_depth * 2? UPB_MAX_HANDLER_DEPTH counts depth as nested messages.
+ // We count frames (contexts in which we separate elements by commas) as both
+ // repeated fields and messages (maps), and the worst case is a
+ // message->repeated field->submessage->repeated field->... nesting.
+ bool first_elem_[UPB_MAX_HANDLER_DEPTH * 2];
+));
+
+UPB_BEGIN_EXTERN_C // {
+
+// Native C API.
+
+void upb_json_printer_init(upb_json_printer *p, const upb_handlers *h);
+void upb_json_printer_uninit(upb_json_printer *p);
+void upb_json_printer_reset(upb_json_printer *p);
+void upb_json_printer_resetoutput(upb_json_printer *p, upb_bytessink *output);
+upb_sink *upb_json_printer_input(upb_json_printer *p);
+const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+ const void *owner);
+
+UPB_END_EXTERN_C // }
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace json {
+inline Printer::Printer(const upb::Handlers* handlers) {
+ upb_json_printer_init(this, handlers);
+}
+inline Printer::~Printer() { upb_json_printer_uninit(this); }
+inline void Printer::Reset() { upb_json_printer_reset(this); }
+inline void Printer::ResetOutput(BytesSink* output) {
+ upb_json_printer_resetoutput(this, output);
+}
+inline Sink* Printer::input() { return upb_json_printer_input(this); }
+inline reffed_ptr<const Handlers> Printer::NewHandlers(
+ const upb::MessageDef *md) {
+ const Handlers* h = upb_json_printer_newhandlers(md, &h);
+ return reffed_ptr<const Handlers>(h, &h);
+}
+} // namespace json
+} // namespace upb
+
+#endif
+
+#endif // UPB_JSON_TYPED_PRINTER_H_
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
new file mode 100644
index 00000000..4c9449d2
--- /dev/null
+++ b/ruby/google-protobuf.gemspec
@@ -0,0 +1,23 @@
+Gem::Specification.new do |s|
+ s.name = "google-protobuf"
+ s.version = "3.0.0.alpha.3.0.pre"
+ s.licenses = ["BSD"]
+ s.summary = "Protocol Buffers"
+ s.description = "Protocol Buffers are Google's data interchange format."
+ s.authors = ["Protobuf Authors"]
+ s.email = "protobuf@googlegroups.com"
+ s.require_paths = ["lib"]
+ s.files = ["lib/google/protobuf.rb"]
+ unless RUBY_PLATFORM == "java"
+ s.files += `git ls-files "*.c" "*.h" extconf.rb Makefile`.split
+ s.extensions= ["ext/google/protobuf_c/extconf.rb"]
+ else
+ s.files += ["lib/google/protobuf_java.jar"]
+ end
+ s.test_files = ["tests/basic.rb",
+ "tests/stress.rb",
+ "tests/generated_code_test.rb"]
+ s.add_development_dependency "rake-compiler"
+ s.add_development_dependency "test-unit"
+ s.add_development_dependency "rubygems-tasks"
+end
diff --git a/ruby/lib/google/protobuf.rb b/ruby/lib/google/protobuf.rb
new file mode 100644
index 00000000..75869dd8
--- /dev/null
+++ b/ruby/lib/google/protobuf.rb
@@ -0,0 +1,36 @@
+# 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.
+
+if RUBY_PLATFORM == "java"
+ require 'json'
+ require 'google/protobuf_java'
+else
+ require 'google/protobuf_c'
+end
diff --git a/ruby/pom.xml b/ruby/pom.xml
new file mode 100644
index 00000000..1630fe84
--- /dev/null
+++ b/ruby/pom.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google</groupId>
+ <artifactId>google</artifactId>
+ <version>1</version>
+ </parent>
+
+ <groupId>com.google.protobuf.jruby</groupId>
+ <artifactId>protobuf-jruby</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <name>Protocol Buffer JRuby native extension</name>
+ <description>
+ Protocol Buffers are a way of encoding structured data in an efficient yet
+ extensible format.
+ </description>
+ <inceptionYear>2014</inceptionYear>
+ <url>https://developers.google.com/protocol-buffers/</url>
+ <licenses>
+ <license>
+ <name>New BSD license</name>
+ <url>http://www.opensource.org/licenses/bsd-license.php</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <url>https://github.com/google/protobuf</url>
+ <connection>
+ scm:git:https://github.com/google/protobuf.git
+ </connection>
+ </scm>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <ruby.sources>lib/google</ruby.sources>
+ <jar.finalName>protobuf_java</jar.finalName>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <finalName>${jar.finalName}</finalName>
+ <outputDirectory>${ruby.sources}</outputDirectory>
+ <appendAssemblyId>false</appendAssemblyId>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>2.4.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jruby</groupId>
+ <artifactId>jruby-complete</artifactId>
+ <version>1.7.13</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java</artifactId>
+ <version>3.0.0-pre</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java
new file mode 100644
index 00000000..5addae58
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.*;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "Builder")
+public class RubyBuilder extends RubyObject {
+ public static void createRubyBuilder(Ruby runtime) {
+ RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cBuilder = protobuf.defineClassUnder("Builder", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+ return new RubyBuilder(runtime, klazz);
+ }
+ });
+ cBuilder.defineAnnotatedMethods(RubyBuilder.class);
+ }
+
+ public RubyBuilder(Ruby runtime, RubyClass metaClass) {
+ super(runtime, metaClass);
+ this.cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor");
+ this.cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor");
+ this.cMessageBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::MessageBuilderContext");
+ this.cEnumBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumBuilderContext");
+ }
+
+ /*
+ * call-seq:
+ * Builder.new => builder
+ *
+ * Creates a new Builder. A Builder can accumulate a set of new message and enum
+ * descriptors and atomically register them into a pool in a way that allows for
+ * (co)recursive type references.
+ */
+ @JRubyMethod
+ public IRubyObject initialize(ThreadContext context) {
+ Ruby runtime = context.runtime;
+ this.pendingList = runtime.newArray();
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * Builder.add_message(name, &block)
+ *
+ * Creates a new, empty descriptor with the given name, and invokes the block in
+ * the context of a MessageBuilderContext on that descriptor. The block can then
+ * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
+ * methods to define the message fields.
+ *
+ * This is the recommended, idiomatic way to build message definitions.
+ */
+ @JRubyMethod(name = "add_message")
+ public IRubyObject addMessage(ThreadContext context, IRubyObject name, Block block) {
+ RubyDescriptor msgdef = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK);
+ IRubyObject ctx = cMessageBuilderContext.newInstance(context, msgdef, this, Block.NULL_BLOCK);
+ msgdef.setName(context, name);
+ if (block.isGiven()) {
+ if (block.arity() == Arity.ONE_ARGUMENT) {
+ block.yield(context, ctx);
+ } else {
+ Binding binding = block.getBinding();
+ binding.setSelf(ctx);
+ block.yieldSpecific(context);
+ }
+ }
+ this.pendingList.add(msgdef);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Builder.add_enum(name, &block)
+ *
+ * Creates a new, empty enum descriptor with the given name, and invokes the block in
+ * the context of an EnumBuilderContext on that descriptor. The block can then
+ * call EnumBuilderContext#add_value to define the enum values.
+ *
+ * This is the recommended, idiomatic way to build enum definitions.
+ */
+ @JRubyMethod(name = "add_enum")
+ public IRubyObject addEnum(ThreadContext context, IRubyObject name, Block block) {
+ RubyEnumDescriptor enumDef = (RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK);
+ IRubyObject ctx = cEnumBuilderContext.newInstance(context, enumDef, Block.NULL_BLOCK);
+ enumDef.setName(context, name);
+
+ if (block.isGiven()) {
+ if (block.arity() == Arity.ONE_ARGUMENT) {
+ block.yield(context, ctx);
+ } else {
+ Binding binding = block.getBinding();
+ binding.setSelf(ctx);
+ block.yieldSpecific(context);
+ }
+ }
+
+ this.pendingList.add(enumDef);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Builder.finalize_to_pool(pool)
+ *
+ * Adds all accumulated message and enum descriptors created in this builder
+ * context to the given pool. The operation occurs atomically, and all
+ * descriptors can refer to each other (including in cycles). This is the only
+ * way to build (co)recursive message definitions.
+ *
+ * This method is usually called automatically by DescriptorPool#build after it
+ * invokes the given user block in the context of the builder. The user should
+ * not normally need to call this manually because a Builder is not normally
+ * created manually.
+ */
+ @JRubyMethod(name = "finalize_to_pool")
+ public IRubyObject finalizeToPool(ThreadContext context, IRubyObject rbPool) {
+ RubyDescriptorPool pool = (RubyDescriptorPool) rbPool;
+ for (int i = 0; i < this.pendingList.size(); i++) {
+ IRubyObject defRb = this.pendingList.entry(i);
+ if (defRb instanceof RubyDescriptor) {
+ pool.addToSymtab(context, (RubyDescriptor) defRb);
+ } else {
+ pool.addToSymtab(context, (RubyEnumDescriptor) defRb);
+ }
+ }
+ this.pendingList = context.runtime.newArray();
+ return context.runtime.getNil();
+ }
+
+ protected RubyArray pendingList;
+ private RubyClass cDescriptor, cEnumDescriptor, cMessageBuilderContext, cEnumBuilderContext;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java
new file mode 100644
index 00000000..51c50be8
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java
@@ -0,0 +1,267 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+@JRubyClass(name = "Descriptor", include = "Enumerable")
+public class RubyDescriptor extends RubyObject {
+ public static void createRubyDescriptor(Ruby runtime) {
+ RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cDescriptor = protobuf.defineClassUnder("Descriptor", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+ return new RubyDescriptor(runtime, klazz);
+ }
+ });
+ cDescriptor.includeModule(runtime.getEnumerable());
+ cDescriptor.defineAnnotatedMethods(RubyDescriptor.class);
+ }
+
+ public RubyDescriptor(Ruby runtime, RubyClass klazz) {
+ super(runtime, klazz);
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.new => descriptor
+ *
+ * Creates a new, empty, message type descriptor. At a minimum, its name must be
+ * set before it is added to a pool. It cannot be used to create messages until
+ * it is added to a pool, after which it becomes immutable (as part of a
+ * finalization process).
+ */
+ @JRubyMethod
+ public IRubyObject initialize(ThreadContext context) {
+ this.builder = DescriptorProtos.DescriptorProto.newBuilder();
+ this.fieldDefMap = new HashMap<String, RubyFieldDescriptor>();
+ this.oneofDefs = new HashMap<IRubyObject, RubyOneofDescriptor>();
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.name => name
+ *
+ * Returns the name of this message type as a fully-qualfied string (e.g.,
+ * My.Package.MessageType).
+ */
+ @JRubyMethod(name = "name")
+ public IRubyObject getName(ThreadContext context) {
+ return this.name;
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.name = name
+ *
+ * Assigns a name to this message type. The descriptor must not have been added
+ * to a pool yet.
+ */
+ @JRubyMethod(name = "name=")
+ public IRubyObject setName(ThreadContext context, IRubyObject name) {
+ this.name = name;
+ this.builder.setName(Utils.escapeIdentifier(this.name.asJavaString()));
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.add_field(field) => nil
+ *
+ * Adds the given FieldDescriptor to this message type. The descriptor must not
+ * have been added to a pool yet. Raises an exception if a field with the same
+ * name or number already exists. Sub-type references (e.g. for fields of type
+ * message) are not resolved at this point.
+ */
+ @JRubyMethod(name = "add_field")
+ public IRubyObject addField(ThreadContext context, IRubyObject obj) {
+ RubyFieldDescriptor fieldDef = (RubyFieldDescriptor) obj;
+ this.fieldDefMap.put(fieldDef.getName(context).asJavaString(), fieldDef);
+ this.builder.addField(fieldDef.build());
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.lookup(name) => FieldDescriptor
+ *
+ * Returns the field descriptor for the field with the given name, if present,
+ * or nil if none.
+ */
+ @JRubyMethod
+ public IRubyObject lookup(ThreadContext context, IRubyObject fieldName) {
+ return this.fieldDefMap.get(fieldName.asJavaString());
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.msgclass => message_klass
+ *
+ * Returns the Ruby class created for this message type. Valid only once the
+ * message type has been added to a pool.
+ */
+ @JRubyMethod
+ public IRubyObject msgclass(ThreadContext context) {
+ if (this.klazz == null) {
+ this.klazz = buildClassFromDescriptor(context);
+ }
+ return this.klazz;
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.each(&block)
+ *
+ * Iterates over fields in this message type, yielding to the block on each one.
+ */
+ @JRubyMethod
+ public IRubyObject each(ThreadContext context, Block block) {
+ for (Map.Entry<String, RubyFieldDescriptor> entry : fieldDefMap.entrySet()) {
+ block.yield(context, entry.getValue());
+ }
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.add_oneof(oneof) => nil
+ *
+ * Adds the given OneofDescriptor to this message type. This descriptor must not
+ * have been added to a pool yet. Raises an exception if a oneof with the same
+ * name already exists, or if any of the oneof's fields' names or numbers
+ * conflict with an existing field in this message type. All fields in the oneof
+ * are added to the message descriptor. Sub-type references (e.g. for fields of
+ * type message) are not resolved at this point.
+ */
+ @JRubyMethod(name = "add_oneof")
+ public IRubyObject addOneof(ThreadContext context, IRubyObject obj) {
+ RubyOneofDescriptor def = (RubyOneofDescriptor) obj;
+ builder.addOneofDecl(def.build(builder.getOneofDeclCount()));
+ for (RubyFieldDescriptor fieldDescriptor : def.getFields()) {
+ addField(context, fieldDescriptor);
+ }
+ oneofDefs.put(def.getName(context), def);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.each_oneof(&block) => nil
+ *
+ * Invokes the given block for each oneof in this message type, passing the
+ * corresponding OneofDescriptor.
+ */
+ @JRubyMethod(name = "each_oneof")
+ public IRubyObject eachOneof(ThreadContext context, Block block) {
+ for (RubyOneofDescriptor oneofDescriptor : oneofDefs.values()) {
+ block.yieldSpecific(context, oneofDescriptor);
+ }
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Descriptor.lookup_oneof(name) => OneofDescriptor
+ *
+ * Returns the oneof descriptor for the oneof with the given name, if present,
+ * or nil if none.
+ */
+ @JRubyMethod(name = "lookup_oneof")
+ public IRubyObject lookupOneof(ThreadContext context, IRubyObject name) {
+ if (name instanceof RubySymbol) {
+ name = ((RubySymbol) name).id2name();
+ }
+ return oneofDefs.containsKey(name) ? oneofDefs.get(name) : context.runtime.getNil();
+ }
+
+ public void setDescriptor(Descriptors.Descriptor descriptor) {
+ this.descriptor = descriptor;
+ }
+
+ public Descriptors.Descriptor getDescriptor() {
+ return this.descriptor;
+ }
+
+ public DescriptorProtos.DescriptorProto.Builder getBuilder() {
+ return builder;
+ }
+
+ public void setMapEntry(boolean isMapEntry) {
+ this.builder.setOptions(DescriptorProtos.MessageOptions.newBuilder().setMapEntry(isMapEntry));
+ }
+
+ private RubyModule buildClassFromDescriptor(ThreadContext context) {
+ Ruby runtime = context.runtime;
+
+ ObjectAllocator allocator = new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+ return new RubyMessage(runtime, klazz, descriptor);
+ }
+ };
+
+ // rb_define_class_id
+ RubyClass klass = RubyClass.newClass(runtime, runtime.getObject());
+ klass.setAllocator(allocator);
+ klass.makeMetaClass(runtime.getObject().getMetaClass());
+ klass.inherit(runtime.getObject());
+ klass.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
+ klass.defineAnnotatedMethods(RubyMessage.class);
+ return klass;
+ }
+
+ protected RubyFieldDescriptor lookup(String fieldName) {
+ return fieldDefMap.get(Utils.unescapeIdentifier(fieldName));
+ }
+
+ private IRubyObject name;
+ private RubyModule klazz;
+
+ private DescriptorProtos.DescriptorProto.Builder builder;
+ private Descriptors.Descriptor descriptor;
+ private Map<String, RubyFieldDescriptor> fieldDefMap;
+ private Map<IRubyObject, RubyOneofDescriptor> oneofDefs;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java
new file mode 100644
index 00000000..0345cb99
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.*;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@JRubyClass(name = "DescriptorPool")
+public class RubyDescriptorPool extends RubyObject {
+ public static void createRubyDescriptorPool(Ruby runtime) {
+ RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cDescriptorPool = protobuf.defineClassUnder("DescriptorPool", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+ return new RubyDescriptorPool(runtime, klazz);
+ }
+ });
+
+ cDescriptorPool.defineAnnotatedMethods(RubyDescriptorPool.class);
+ descriptorPool = (RubyDescriptorPool) cDescriptorPool.newInstance(runtime.getCurrentContext(), Block.NULL_BLOCK);
+ }
+
+ public RubyDescriptorPool(Ruby ruby, RubyClass klazz) {
+ super(ruby, klazz);
+ }
+
+ @JRubyMethod
+ public IRubyObject initialize(ThreadContext context) {
+ this.symtab = new HashMap<IRubyObject, IRubyObject>();
+ this.cBuilder = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Builder");
+ this.builder = DescriptorProtos.FileDescriptorProto.newBuilder();
+ return this;
+ }
+
+ @JRubyMethod
+ public IRubyObject build(ThreadContext context, Block block) {
+ RubyBuilder ctx = (RubyBuilder) cBuilder.newInstance(context, Block.NULL_BLOCK);
+ if (block.arity() == Arity.ONE_ARGUMENT) {
+ block.yield(context, ctx);
+ } else {
+ Binding binding = block.getBinding();
+ binding.setSelf(ctx);
+ block.yieldSpecific(context);
+ }
+ ctx.finalizeToPool(context, this);
+ buildFileDescriptor(context);
+ return context.runtime.getNil();
+ }
+
+ @JRubyMethod
+ public IRubyObject lookup(ThreadContext context, IRubyObject name) {
+ IRubyObject descriptor = this.symtab.get(name);
+ if (descriptor == null) {
+ return context.runtime.getNil();
+ }
+ return descriptor;
+ }
+
+ /*
+ * call-seq:
+ * DescriptorPool.generated_pool => descriptor_pool
+ *
+ * Class method that returns the global DescriptorPool. This is a singleton into
+ * which generated-code message and enum types are registered. The user may also
+ * register types in this pool for convenience so that they do not have to hold
+ * a reference to a private pool instance.
+ */
+ @JRubyMethod(meta = true, name = "generated_pool")
+ public static IRubyObject generatedPool(ThreadContext context, IRubyObject recv) {
+ return descriptorPool;
+ }
+
+ protected void addToSymtab(ThreadContext context, RubyDescriptor def) {
+ symtab.put(def.getName(context), def);
+ this.builder.addMessageType(def.getBuilder());
+ }
+
+ protected void addToSymtab(ThreadContext context, RubyEnumDescriptor def) {
+ symtab.put(def.getName(context), def);
+ this.builder.addEnumType(def.getBuilder());
+ }
+
+ private void buildFileDescriptor(ThreadContext context) {
+ Ruby runtime = context.runtime;
+ try {
+ this.builder.setSyntax("proto3");
+ final Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor.buildFrom(
+ this.builder.build(), new Descriptors.FileDescriptor[]{});
+
+ for (Descriptors.EnumDescriptor enumDescriptor : fileDescriptor.getEnumTypes()) {
+ String enumName = Utils.unescapeIdentifier(enumDescriptor.getName());
+ if (enumDescriptor.findValueByNumber(0) == null) {
+ throw runtime.newTypeError("Enum definition " + enumName
+ + " does not contain a value for '0'");
+ }
+ ((RubyEnumDescriptor) symtab.get(runtime.newString(enumName)))
+ .setDescriptor(enumDescriptor);
+ }
+ for (Descriptors.Descriptor descriptor : fileDescriptor.getMessageTypes()) {
+ RubyDescriptor rubyDescriptor = ((RubyDescriptor)
+ symtab.get(runtime.newString(Utils.unescapeIdentifier(descriptor.getName()))));
+ for (Descriptors.FieldDescriptor fieldDescriptor : descriptor.getFields()) {
+ if (fieldDescriptor.isRequired()) {
+ throw runtime.newTypeError("Required fields are unsupported in proto3");
+ }
+ RubyFieldDescriptor rubyFieldDescriptor = rubyDescriptor.lookup(fieldDescriptor.getName());
+ rubyFieldDescriptor.setFieldDef(fieldDescriptor);
+ if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) {
+ RubyDescriptor subType = (RubyDescriptor) lookup(context,
+ runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getMessageType().getName())));
+ rubyFieldDescriptor.setSubType(subType);
+ }
+ if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.ENUM) {
+ RubyEnumDescriptor subType = (RubyEnumDescriptor) lookup(context,
+ runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getEnumType().getName())));
+ rubyFieldDescriptor.setSubType(subType);
+ }
+ }
+ rubyDescriptor.setDescriptor(descriptor);
+ }
+ } catch (Descriptors.DescriptorValidationException e) {
+ throw runtime.newRuntimeError(e.getMessage());
+ }
+ }
+
+ private static RubyDescriptorPool descriptorPool;
+
+ private RubyClass cBuilder;
+ private Map<IRubyObject, IRubyObject> symtab;
+ private DescriptorProtos.FileDescriptorProto.Builder builder;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java
new file mode 100644
index 00000000..929d8699
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.Descriptors;
+import org.jruby.RubyModule;
+import org.jruby.RubyNumeric;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+public class RubyEnum {
+ /*
+ * call-seq:
+ * Enum.lookup(number) => name
+ *
+ * This module method, provided on each generated enum module, looks up an enum
+ * value by number and returns its name as a Ruby symbol, or nil if not found.
+ */
+ @JRubyMethod(meta = true)
+ public static IRubyObject lookup(ThreadContext context, IRubyObject recv, IRubyObject number) {
+ RubyEnumDescriptor rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
+ Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor();
+ Descriptors.EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number));
+ if (value == null) return context.runtime.getNil();
+ return context.runtime.newSymbol(value.getName());
+ }
+
+ /*
+ * call-seq:
+ * Enum.resolve(name) => number
+ *
+ * This module method, provided on each generated enum module, looks up an enum
+ * value by name (as a Ruby symbol) and returns its name, or nil if not found.
+ */
+ @JRubyMethod(meta = true)
+ public static IRubyObject resolve(ThreadContext context, IRubyObject recv, IRubyObject name) {
+ RubyEnumDescriptor rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
+ Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor();
+ Descriptors.EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString());
+ if (value == null) return context.runtime.getNil();
+ return context.runtime.newFixnum(value.getNumber());
+ }
+
+ /*
+ * call-seq:
+ * Enum.descriptor
+ *
+ * This module method, provided on each generated enum module, returns the
+ * EnumDescriptor corresponding to this enum type.
+ */
+ @JRubyMethod(meta = true, name = "descriptor")
+ public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) {
+ return ((RubyModule) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR);
+ }
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java
new file mode 100644
index 00000000..e4cac345
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "EnumBuilderContext")
+public class RubyEnumBuilderContext extends RubyObject {
+ public static void createRubyEnumBuilderContext(Ruby runtime) {
+ RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cMessageBuilderContext = protobuf.defineClassUnder("EnumBuilderContext", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+ return new RubyEnumBuilderContext(runtime, klazz);
+ }
+ });
+ cMessageBuilderContext.defineAnnotatedMethods(RubyEnumBuilderContext.class);
+ }
+
+ public RubyEnumBuilderContext(Ruby ruby, RubyClass klazz) {
+ super(ruby, klazz);
+ }
+
+ @JRubyMethod
+ public IRubyObject initialize(ThreadContext context, IRubyObject enumDescriptor) {
+ this.enumDescriptor = (RubyEnumDescriptor) enumDescriptor;
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * EnumBuilder.add_value(name, number)
+ *
+ * Adds the given name => number mapping to the enum type. Name must be a Ruby
+ * symbol.
+ */
+ @JRubyMethod
+ public IRubyObject value(ThreadContext context, IRubyObject name, IRubyObject number) {
+ this.enumDescriptor.addValue(context, name, number);
+ return context.runtime.getNil();
+ }
+
+ private RubyEnumDescriptor enumDescriptor;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java
new file mode 100644
index 00000000..4df832d0
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.RubyNumeric;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "EnumDescriptor", include = "Enumerable")
+public class RubyEnumDescriptor extends RubyObject {
+ public static void createRubyEnumDescriptor(Ruby runtime) {
+ RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cEnumDescriptor = mProtobuf.defineClassUnder("EnumDescriptor", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+ return new RubyEnumDescriptor(runtime, klazz);
+ }
+ });
+ cEnumDescriptor.includeModule(runtime.getEnumerable());
+ cEnumDescriptor.defineAnnotatedMethods(RubyEnumDescriptor.class);
+ }
+
+ public RubyEnumDescriptor(Ruby runtime, RubyClass klazz) {
+ super(runtime, klazz);
+ }
+
+ /*
+ * call-seq:
+ * EnumDescriptor.new => enum_descriptor
+ *
+ * Creates a new, empty, enum descriptor. Must be added to a pool before the
+ * enum type can be used. The enum type may only be modified prior to adding to
+ * a pool.
+ */
+ @JRubyMethod
+ public IRubyObject initialize(ThreadContext context) {
+ this.builder = DescriptorProtos.EnumDescriptorProto.newBuilder();
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * EnumDescriptor.name => name
+ *
+ * Returns the name of this enum type.
+ */
+ @JRubyMethod(name = "name")
+ public IRubyObject getName(ThreadContext context) {
+ return this.name;
+ }
+
+ /*
+ * call-seq:
+ * EnumDescriptor.name = name
+ *
+ * Sets the name of this enum type. Cannot be called if the enum type has
+ * already been added to a pool.
+ */
+ @JRubyMethod(name = "name=")
+ public IRubyObject setName(ThreadContext context, IRubyObject name) {
+ this.name = name;
+ this.builder.setName(Utils.escapeIdentifier(name.asJavaString()));
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * EnumDescriptor.add_value(key, value)
+ *
+ * Adds a new key => value mapping to this enum type. Key must be given as a
+ * Ruby symbol. Cannot be called if the enum type has already been added to a
+ * pool. Will raise an exception if the key or value is already in use.
+ */
+ @JRubyMethod(name = "add_value")
+ public IRubyObject addValue(ThreadContext context, IRubyObject name, IRubyObject number) {
+ DescriptorProtos.EnumValueDescriptorProto.Builder valueBuilder = DescriptorProtos.EnumValueDescriptorProto.newBuilder();
+ valueBuilder.setName(name.asJavaString());
+ valueBuilder.setNumber(RubyNumeric.num2int(number));
+ this.builder.addValue(valueBuilder);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * EnumDescriptor.each(&block)
+ *
+ * Iterates over key => value mappings in this enum's definition, yielding to
+ * the block with (key, value) arguments for each one.
+ */
+ @JRubyMethod
+ public IRubyObject each(ThreadContext context, Block block) {
+ Ruby runtime = context.runtime;
+ for (Descriptors.EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) {
+ block.yield(context, runtime.newArray(runtime.newSymbol(enumValueDescriptor.getName()),
+ runtime.newFixnum(enumValueDescriptor.getNumber())));
+ }
+ return runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * EnumDescriptor.enummodule => module
+ *
+ * Returns the Ruby module corresponding to this enum type. Cannot be called
+ * until the enum descriptor has been added to a pool.
+ */
+ @JRubyMethod
+ public IRubyObject enummodule(ThreadContext context) {
+ if (this.klazz == null) {
+ this.klazz = buildModuleFromDescriptor(context);
+ }
+ return this.klazz;
+ }
+
+ public void setDescriptor(Descriptors.EnumDescriptor descriptor) {
+ this.descriptor = descriptor;
+ }
+
+ public Descriptors.EnumDescriptor getDescriptor() {
+ return this.descriptor;
+ }
+
+ public DescriptorProtos.EnumDescriptorProto.Builder getBuilder() {
+ return this.builder;
+ }
+
+ private RubyModule buildModuleFromDescriptor(ThreadContext context) {
+ Ruby runtime = context.runtime;
+ Utils.checkNameAvailability(context, name.asJavaString());
+
+ RubyModule enumModule = RubyModule.newModule(runtime);
+ for (Descriptors.EnumValueDescriptor value : descriptor.getValues()) {
+ enumModule.defineConstant(value.getName(), runtime.newFixnum(value.getNumber()));
+ }
+
+ enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
+ enumModule.defineAnnotatedMethods(RubyEnum.class);
+ return enumModule;
+ }
+
+ private IRubyObject name;
+ private RubyModule klazz;
+ private Descriptors.EnumDescriptor descriptor;
+ private DescriptorProtos.EnumDescriptorProto.Builder builder;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java
new file mode 100644
index 00000000..38226c4e
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "FieldDescriptor")
+public class RubyFieldDescriptor extends RubyObject {
+ public static void createRubyFileDescriptor(Ruby runtime) {
+ RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cFieldDescriptor = mProtobuf.defineClassUnder("FieldDescriptor", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+ return new RubyFieldDescriptor(runtime, klazz);
+ }
+ });
+ cFieldDescriptor.defineAnnotatedMethods(RubyFieldDescriptor.class);
+ }
+
+ public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) {
+ super(runtime, klazz);
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.new => field
+ *
+ * Returns a new field descriptor. Its name, type, etc. must be set before it is
+ * added to a message type.
+ */
+ @JRubyMethod
+ public IRubyObject initialize(ThreadContext context) {
+ builder = DescriptorProtos.FieldDescriptorProto.newBuilder();
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.label = label
+ *
+ * Sets the label on this field. Cannot be called if field is part of a message
+ * type already in a pool.
+ */
+ @JRubyMethod(name = "label=")
+ public IRubyObject setLabel(ThreadContext context, IRubyObject value) {
+ this.builder.setLabel(
+ DescriptorProtos.FieldDescriptorProto.Label.valueOf("LABEL_" + value.asJavaString().toUpperCase()));
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.name => name
+ *
+ * Returns the name of this field.
+ */
+ @JRubyMethod(name = "name")
+ public IRubyObject getName(ThreadContext context) {
+ return this.name;
+ }
+
+ @JRubyMethod(name = "subtype")
+ public IRubyObject getSubType(ThreadContext context) {
+ return subType;
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.name = name
+ *
+ * Sets the name of this field. Cannot be called once the containing message
+ * type, if any, is added to a pool.
+ */
+ @JRubyMethod(name = "name=")
+ public IRubyObject setName(ThreadContext context, IRubyObject value) {
+ String nameStr = value.asJavaString();
+ this.name = context.runtime.newString(nameStr);
+ this.builder.setName(Utils.escapeIdentifier(nameStr));
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.type => type
+ *
+ * Returns this field's type, as a Ruby symbol, or nil if not yet set.
+ *
+ * Valid field types are:
+ * :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
+ * :bytes, :message.
+ */
+ @JRubyMethod(name = "type")
+ public IRubyObject getType(ThreadContext context) {
+ return Utils.fieldTypeToRuby(context, this.builder.getType());
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.type = type
+ *
+ * Sets this field's type. Cannot be called if field is part of a message type
+ * already in a pool.
+ */
+ @JRubyMethod(name = "type=")
+ public IRubyObject setType(ThreadContext context, IRubyObject value) {
+ this.builder.setType(DescriptorProtos.FieldDescriptorProto.Type.valueOf("TYPE_" + value.asJavaString().toUpperCase()));
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.number = number
+ *
+ * Sets the tag number for this field. Cannot be called if field is part of a
+ * message type already in a pool.
+ */
+ @JRubyMethod(name = "number=")
+ public IRubyObject setNumber(ThreadContext context, IRubyObject value) {
+ this.builder.setNumber(RubyNumeric.num2int(value));
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.submsg_name = submsg_name
+ *
+ * Sets the name of the message or enum type corresponding to this field, if it
+ * is a message or enum field (respectively). This type name will be resolved
+ * within the context of the pool to which the containing message type is added.
+ * Cannot be called on field that are not of message or enum type, or on fields
+ * that are part of a message type already added to a pool.
+ */
+ @JRubyMethod(name = "submsg_name=")
+ public IRubyObject setSubmsgName(ThreadContext context, IRubyObject name) {
+ this.builder.setTypeName("." + Utils.escapeIdentifier(name.asJavaString()));
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.get(message) => value
+ *
+ * Returns the value set for this field on the given message. Raises an
+ * exception if message is of the wrong type.
+ */
+ @JRubyMethod(name = "get")
+ public IRubyObject getValue(ThreadContext context, IRubyObject msgRb) {
+ RubyMessage message = (RubyMessage) msgRb;
+ if (message.getDescriptor() != fieldDef.getContainingType()) {
+ throw context.runtime.newTypeError("set method called on wrong message type");
+ }
+ return message.getField(context, fieldDef);
+ }
+
+ /*
+ * call-seq:
+ * FieldDescriptor.set(message, value)
+ *
+ * Sets the value corresponding to this field to the given value on the given
+ * message. Raises an exception if message is of the wrong type. Performs the
+ * ordinary type-checks for field setting.
+ */
+ @JRubyMethod(name = "set")
+ public IRubyObject setValue(ThreadContext context, IRubyObject msgRb, IRubyObject value) {
+ RubyMessage message = (RubyMessage) msgRb;
+ if (message.getDescriptor() != fieldDef.getContainingType()) {
+ throw context.runtime.newTypeError("set method called on wrong message type");
+ }
+ message.setField(context, fieldDef, value);
+ return context.runtime.getNil();
+ }
+
+ protected void setSubType(IRubyObject rubyDescriptor) {
+ this.subType = rubyDescriptor;
+ }
+
+ protected void setFieldDef(Descriptors.FieldDescriptor fieldDescriptor) {
+ this.fieldDef = fieldDescriptor;
+ }
+
+ protected void setOneofName(IRubyObject name) {
+ oneofName = name;
+ }
+
+ protected void setOneofIndex(int index) {
+ hasOneofIndex = true;
+ oneofIndex = index;
+ }
+
+ protected IRubyObject getOneofName() {
+ return oneofName;
+ }
+
+ protected Descriptors.FieldDescriptor getFieldDef() {
+ return fieldDef;
+ }
+
+ protected DescriptorProtos.FieldDescriptorProto build() {
+ if (hasOneofIndex)
+ builder.setOneofIndex(oneofIndex);
+ return this.builder.build();
+ }
+
+ private DescriptorProtos.FieldDescriptorProto.Builder builder;
+ private IRubyObject name;
+ private IRubyObject subType;
+ private IRubyObject oneofName;
+ private Descriptors.FieldDescriptor fieldDef;
+ private int oneofIndex;
+ private boolean hasOneofIndex = false;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
new file mode 100644
index 00000000..b25dc6e1
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
@@ -0,0 +1,434 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.Descriptors;
+import com.google.protobuf.DynamicMessage;
+import com.google.protobuf.MapEntry;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.internal.runtime.methods.DynamicMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.util.ByteList;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@JRubyClass(name = "Map", include = "Enumerable")
+public class RubyMap extends RubyObject {
+ public static void createRubyMap(Ruby runtime) {
+ RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cMap = protobuf.defineClassUnder("Map", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
+ return new RubyMap(ruby, rubyClass);
+ }
+ });
+ cMap.includeModule(runtime.getEnumerable());
+ cMap.defineAnnotatedMethods(RubyMap.class);
+ }
+
+ public RubyMap(Ruby ruby, RubyClass rubyClass) {
+ super(ruby, rubyClass);
+ }
+
+ /*
+ * call-seq:
+ * Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
+ * => new map
+ *
+ * Allocates a new Map container. This constructor may be called with 2, 3, or 4
+ * arguments. The first two arguments are always present and are symbols (taking
+ * on the same values as field-type symbols in message descriptors) that
+ * indicate the type of the map key and value fields.
+ *
+ * The supported key types are: :int32, :int64, :uint32, :uint64, :bool,
+ * :string, :bytes.
+ *
+ * The supported value types are: :int32, :int64, :uint32, :uint64, :bool,
+ * :string, :bytes, :enum, :message.
+ *
+ * The third argument, value_typeclass, must be present if value_type is :enum
+ * or :message. As in RepeatedField#new, this argument must be a message class
+ * (for :message) or enum module (for :enum).
+ *
+ * The last argument, if present, provides initial content for map. Note that
+ * this may be an ordinary Ruby hashmap or another Map instance with identical
+ * key and value types. Also note that this argument may be present whether or
+ * not value_typeclass is present (and it is unambiguously separate from
+ * value_typeclass because value_typeclass's presence is strictly determined by
+ * value_type). The contents of this initial hashmap or Map instance are
+ * shallow-copied into the new Map: the original map is unmodified, but
+ * references to underlying objects will be shared if the value type is a
+ * message type.
+ */
+
+ @JRubyMethod(required = 2, optional = 2)
+ public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
+ this.table = new HashMap<IRubyObject, IRubyObject>();
+ this.keyType = Utils.rubyToFieldType(args[0]);
+ this.valueType = Utils.rubyToFieldType(args[1]);
+
+ switch(keyType) {
+ case INT32:
+ case INT64:
+ case UINT32:
+ case UINT64:
+ case BOOL:
+ case STRING:
+ case BYTES:
+ // These are OK.
+ break;
+ default:
+ throw context.runtime.newArgumentError("Invalid key type for map.");
+ }
+
+ int initValueArg = 2;
+ if (needTypeclass(this.valueType) && args.length > 2) {
+ this.valueTypeClass = args[2];
+ Utils.validateTypeClass(context, this.valueType, this.valueTypeClass);
+ initValueArg = 3;
+ } else {
+ this.valueTypeClass = context.runtime.getNilClass();
+ }
+
+ // Table value type is always UINT64: this ensures enough space to store the
+ // native_slot value.
+ if (args.length > initValueArg) {
+ mergeIntoSelf(context, args[initValueArg]);
+ }
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * Map.[]=(key, value) => value
+ *
+ * Inserts or overwrites the value at the given key with the given new value.
+ * Throws an exception if the key type is incorrect. Returns the new value that
+ * was just inserted.
+ */
+ @JRubyMethod(name = "[]=")
+ public IRubyObject indexSet(ThreadContext context, IRubyObject key, IRubyObject value) {
+ Utils.checkType(context, keyType, key, (RubyModule) valueTypeClass);
+ Utils.checkType(context, valueType, value, (RubyModule) valueTypeClass);
+ IRubyObject symbol;
+ if (valueType == Descriptors.FieldDescriptor.Type.ENUM &&
+ Utils.isRubyNum(value) &&
+ ! (symbol = RubyEnum.lookup(context, valueTypeClass, value)).isNil()) {
+ value = symbol;
+ }
+ this.table.put(key, value);
+ return value;
+ }
+
+ /*
+ * call-seq:
+ * Map.[](key) => value
+ *
+ * Accesses the element at the given key. Throws an exception if the key type is
+ * incorrect. Returns nil when the key is not present in the map.
+ */
+ @JRubyMethod(name = "[]")
+ public IRubyObject index(ThreadContext context, IRubyObject key) {
+ if (table.containsKey(key))
+ return this.table.get(key);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Map.==(other) => boolean
+ *
+ * Compares this map to another. Maps are equal if they have identical key sets,
+ * and for each key, the values in both maps compare equal. Elements are
+ * compared as per normal Ruby semantics, by calling their :== methods (or
+ * performing a more efficient comparison for primitive types).
+ *
+ * Maps with dissimilar key types or value types/typeclasses are never equal,
+ * even if value comparison (for example, between integers and floats) would
+ * have otherwise indicated that every element has equal value.
+ */
+ @JRubyMethod(name = "==")
+ public IRubyObject eq(ThreadContext context, IRubyObject _other) {
+ if (_other instanceof RubyHash)
+ return toHash(context).op_equal(context, _other);
+ RubyMap other = (RubyMap) _other;
+ if (this == other) return context.runtime.getTrue();
+ if (!typeCompatible(other) || this.table.size() != other.table.size())
+ return context.runtime.getFalse();
+ for (IRubyObject key : table.keySet()) {
+ if (! other.table.containsKey(key))
+ return context.runtime.getFalse();
+ if (! other.table.get(key).equals(table.get(key)))
+ return context.runtime.getFalse();
+ }
+ return context.runtime.getTrue();
+ }
+
+ /*
+ * call-seq:
+ * Map.inspect => string
+ *
+ * Returns a string representing this map's elements. It will be formatted as
+ * "{key => value, key => value, ...}", with each key and value string
+ * representation computed by its own #inspect method.
+ */
+ @JRubyMethod
+ public IRubyObject inspect() {
+ return toHash(getRuntime().getCurrentContext()).inspect();
+ }
+
+ /*
+ * call-seq:
+ * Map.hash => hash_value
+ *
+ * Returns a hash value based on this map's contents.
+ */
+ @JRubyMethod
+ public IRubyObject hash(ThreadContext context) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ for (IRubyObject key : table.keySet()) {
+ digest.update((byte) key.hashCode());
+ digest.update((byte) table.get(key).hashCode());
+ }
+ return context.runtime.newString(new ByteList(digest.digest()));
+ } catch (NoSuchAlgorithmException ignore) {
+ return context.runtime.newFixnum(System.identityHashCode(table));
+ }
+ }
+
+ /*
+ * call-seq:
+ * Map.keys => [list_of_keys]
+ *
+ * Returns the list of keys contained in the map, in unspecified order.
+ */
+ @JRubyMethod
+ public IRubyObject keys(ThreadContext context) {
+ return RubyArray.newArray(context.runtime, table.keySet());
+ }
+
+ /*
+ * call-seq:
+ * Map.values => [list_of_values]
+ *
+ * Returns the list of values contained in the map, in unspecified order.
+ */
+ @JRubyMethod
+ public IRubyObject values(ThreadContext context) {
+ return RubyArray.newArray(context.runtime, table.values());
+ }
+
+ /*
+ * call-seq:
+ * Map.clear
+ *
+ * Removes all entries from the map.
+ */
+ @JRubyMethod
+ public IRubyObject clear(ThreadContext context) {
+ table.clear();
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Map.each(&block)
+ *
+ * Invokes &block on each |key, value| pair in the map, in unspecified order.
+ * Note that Map also includes Enumerable; map thus acts like a normal Ruby
+ * sequence.
+ */
+ @JRubyMethod
+ public IRubyObject each(ThreadContext context, Block block) {
+ for (IRubyObject key : table.keySet()) {
+ block.yieldSpecific(context, key, table.get(key));
+ }
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * Map.delete(key) => old_value
+ *
+ * Deletes the value at the given key, if any, returning either the old value or
+ * nil if none was present. Throws an exception if the key is of the wrong type.
+ */
+ @JRubyMethod
+ public IRubyObject delete(ThreadContext context, IRubyObject key) {
+ return table.remove(key);
+ }
+
+ /*
+ * call-seq:
+ * Map.has_key?(key) => bool
+ *
+ * Returns true if the given key is present in the map. Throws an exception if
+ * the key has the wrong type.
+ */
+ @JRubyMethod(name = "has_key?")
+ public IRubyObject hasKey(ThreadContext context, IRubyObject key) {
+ return this.table.containsKey(key) ? context.runtime.getTrue() : context.runtime.getFalse();
+ }
+
+ /*
+ * call-seq:
+ * Map.length
+ *
+ * Returns the number of entries (key-value pairs) in the map.
+ */
+ @JRubyMethod
+ public IRubyObject length(ThreadContext context) {
+ return context.runtime.newFixnum(this.table.size());
+ }
+
+ /*
+ * call-seq:
+ * Map.dup => new_map
+ *
+ * Duplicates this map with a shallow copy. References to all non-primitive
+ * element objects (e.g., submessages) are shared.
+ */
+ @JRubyMethod
+ public IRubyObject dup(ThreadContext context) {
+ RubyMap newMap = newThisType(context);
+ for (Map.Entry<IRubyObject, IRubyObject> entry : table.entrySet()) {
+ newMap.table.put(entry.getKey(), entry.getValue());
+ }
+ return newMap;
+ }
+
+ @JRubyMethod(name = "to_h")
+ public RubyHash toHash(ThreadContext context) {
+ return RubyHash.newHash(context.runtime, table, context.runtime.getNil());
+ }
+
+ // Used by Google::Protobuf.deep_copy but not exposed directly.
+ protected IRubyObject deepCopy(ThreadContext context) {
+ RubyMap newMap = newThisType(context);
+ switch (valueType) {
+ case MESSAGE:
+ for (IRubyObject key : table.keySet()) {
+ RubyMessage message = (RubyMessage) table.get(key);
+ newMap.table.put(key.dup(), message.deepCopy(context));
+ }
+ break;
+ default:
+ for (IRubyObject key : table.keySet()) {
+ newMap.table.put(key.dup(), table.get(key).dup());
+ }
+ }
+ return newMap;
+ }
+
+ protected List<DynamicMessage> build(ThreadContext context, RubyDescriptor descriptor) {
+ List<DynamicMessage> list = new ArrayList<DynamicMessage>();
+ RubyClass rubyClass = (RubyClass) descriptor.msgclass(context);
+ Descriptors.FieldDescriptor keyField = descriptor.lookup("key").getFieldDef();
+ Descriptors.FieldDescriptor valueField = descriptor.lookup("value").getFieldDef();
+ for (IRubyObject key : table.keySet()) {
+ RubyMessage mapMessage = (RubyMessage) rubyClass.newInstance(context, Block.NULL_BLOCK);
+ mapMessage.setField(context, keyField, key);
+ mapMessage.setField(context, valueField, table.get(key));
+ list.add(mapMessage.build(context));
+ }
+ return list;
+ }
+
+ protected RubyMap mergeIntoSelf(final ThreadContext context, IRubyObject hashmap) {
+ if (hashmap instanceof RubyHash) {
+ ((RubyHash) hashmap).visitAll(new RubyHash.Visitor() {
+ @Override
+ public void visit(IRubyObject key, IRubyObject val) {
+ indexSet(context, key, val);
+ }
+ });
+ } else if (hashmap instanceof RubyMap) {
+ RubyMap other = (RubyMap) hashmap;
+ if (!typeCompatible(other)) {
+ throw context.runtime.newTypeError("Attempt to merge Map with mismatching types");
+ }
+ } else {
+ throw context.runtime.newTypeError("Unknown type merging into Map");
+ }
+ return this;
+ }
+
+ protected boolean typeCompatible(RubyMap other) {
+ return this.keyType == other.keyType &&
+ this.valueType == other.valueType &&
+ this.valueTypeClass == other.valueTypeClass;
+ }
+
+ private RubyMap newThisType(ThreadContext context) {
+ RubyMap newMap;
+ if (needTypeclass(valueType)) {
+ newMap = (RubyMap) metaClass.newInstance(context,
+ Utils.fieldTypeToRuby(context, keyType),
+ Utils.fieldTypeToRuby(context, valueType),
+ valueTypeClass, Block.NULL_BLOCK);
+ } else {
+ newMap = (RubyMap) metaClass.newInstance(context,
+ Utils.fieldTypeToRuby(context, keyType),
+ Utils.fieldTypeToRuby(context, valueType),
+ Block.NULL_BLOCK);
+ }
+ newMap.table = new HashMap<IRubyObject, IRubyObject>();
+ return newMap;
+ }
+
+ private boolean needTypeclass(Descriptors.FieldDescriptor.Type type) {
+ switch(type) {
+ case MESSAGE:
+ case ENUM:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private Descriptors.FieldDescriptor.Type keyType;
+ private Descriptors.FieldDescriptor.Type valueType;
+ private IRubyObject valueTypeClass;
+ private Map<IRubyObject, IRubyObject> table;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
new file mode 100644
index 00000000..04bc0b76
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
@@ -0,0 +1,744 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.*;
+import org.jruby.*;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.Helpers;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.util.ByteList;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class RubyMessage extends RubyObject {
+ public RubyMessage(Ruby ruby, RubyClass klazz, Descriptors.Descriptor descriptor) {
+ super(ruby, klazz);
+ this.descriptor = descriptor;
+ }
+
+ /*
+ * call-seq:
+ * Message.new(kwargs) => new_message
+ *
+ * Creates a new instance of the given message class. Keyword arguments may be
+ * provided with keywords corresponding to field names.
+ *
+ * Note that no literal Message class exists. Only concrete classes per message
+ * type exist, as provided by the #msgclass method on Descriptors after they
+ * have been added to a pool. The method definitions described here on the
+ * Message class are provided on each concrete message class.
+ */
+ @JRubyMethod(optional = 1)
+ public IRubyObject initialize(final ThreadContext context, IRubyObject[] args) {
+ final Ruby runtime = context.runtime;
+ this.cRepeatedField = (RubyClass) runtime.getClassFromPath("Google::Protobuf::RepeatedField");
+ this.cMap = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Map");
+ this.builder = DynamicMessage.newBuilder(this.descriptor);
+ this.repeatedFields = new HashMap<Descriptors.FieldDescriptor, RubyRepeatedField>();
+ this.maps = new HashMap<Descriptors.FieldDescriptor, RubyMap>();
+ this.fields = new HashMap<Descriptors.FieldDescriptor, IRubyObject>();
+ this.oneofCases = new HashMap<Descriptors.OneofDescriptor, Descriptors.FieldDescriptor>();
+ if (args.length == 1) {
+ if (!(args[0] instanceof RubyHash)) {
+ throw runtime.newArgumentError("expected Hash arguments.");
+ }
+ RubyHash hash = args[0].convertToHash();
+ hash.visitAll(new RubyHash.Visitor() {
+ @Override
+ public void visit(IRubyObject key, IRubyObject value) {
+ if (!(key instanceof RubySymbol))
+ throw runtime.newTypeError("Expected symbols as hash keys in initialization map.");
+ final Descriptors.FieldDescriptor fieldDescriptor = findField(context, key);
+
+ if (Utils.isMapEntry(fieldDescriptor)) {
+ if (!(value instanceof RubyHash))
+ throw runtime.newArgumentError("Expected Hash object as initializer value for map field.");
+
+ final RubyMap map = newMapForField(context, fieldDescriptor);
+ map.mergeIntoSelf(context, value);
+ maps.put(fieldDescriptor, map);
+ } else if (fieldDescriptor.isRepeated()) {
+ if (!(value instanceof RubyArray))
+ throw runtime.newTypeError("Expected array as initializer var for repeated field.");
+ RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, value);
+ addRepeatedField(fieldDescriptor, repeatedField);
+ } else {
+ Descriptors.OneofDescriptor oneof = fieldDescriptor.getContainingOneof();
+ if (oneof != null) {
+ oneofCases.put(oneof, fieldDescriptor);
+ }
+ fields.put(fieldDescriptor, value);
+ }
+
+ }
+ });
+ }
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * Message.[]=(index, value)
+ *
+ * Sets a field's value by field name. The provided field name should be a
+ * string.
+ */
+ @JRubyMethod(name = "[]=")
+ public IRubyObject indexSet(ThreadContext context, IRubyObject fieldName, IRubyObject value) {
+ Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName);
+ return setField(context, fieldDescriptor, value);
+ }
+
+ /*
+ * call-seq:
+ * Message.[](index) => value
+ *
+ * Accesses a field's value by field name. The provided field name should be a
+ * string.
+ */
+ @JRubyMethod(name = "[]")
+ public IRubyObject index(ThreadContext context, IRubyObject fieldName) {
+ Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName);
+ return getField(context, fieldDescriptor);
+ }
+
+ /*
+ * call-seq:
+ * Message.inspect => string
+ *
+ * Returns a human-readable string representing this message. It will be
+ * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
+ * field's value is represented according to its own #inspect method.
+ */
+ @JRubyMethod
+ public IRubyObject inspect() {
+ String cname = metaClass.getName();
+ StringBuilder sb = new StringBuilder("<");
+ sb.append(cname);
+ sb.append(": ");
+ sb.append(this.layoutInspect());
+ sb.append(">");
+
+ return getRuntime().newString(sb.toString());
+ }
+
+ /*
+ * call-seq:
+ * Message.hash => hash_value
+ *
+ * Returns a hash value that represents this message's field values.
+ */
+ @JRubyMethod
+ public IRubyObject hash(ThreadContext context) {
+ int hashCode = System.identityHashCode(this);
+ return context.runtime.newFixnum(hashCode);
+ }
+
+ /*
+ * call-seq:
+ * Message.==(other) => boolean
+ *
+ * Performs a deep comparison of this message with another. Messages are equal
+ * if they have the same type and if each field is equal according to the :==
+ * method's semantics (a more efficient comparison may actually be done if the
+ * field is of a primitive type).
+ */
+ @JRubyMethod(name = "==")
+ public IRubyObject eq(ThreadContext context, IRubyObject other) {
+ Ruby runtime = context.runtime;
+ if (!(other instanceof RubyMessage))
+ return runtime.getFalse();
+ RubyMessage message = (RubyMessage) other;
+ if (descriptor != message.descriptor) {
+ return runtime.getFalse();
+ }
+
+ for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) {
+ IRubyObject thisVal = getField(context, fdef);
+ IRubyObject thatVal = message.getField(context, fdef);
+ IRubyObject ret = thisVal.callMethod(context, "==", thatVal);
+ if (!ret.isTrue()) {
+ return runtime.getFalse();
+ }
+ }
+ return runtime.getTrue();
+ }
+
+ /*
+ * call-seq:
+ * Message.method_missing(*args)
+ *
+ * Provides accessors and setters for message fields according to their field
+ * names. For any field whose name does not conflict with a built-in method, an
+ * accessor is provided with the same name as the field, and a setter is
+ * provided with the name of the field plus the '=' suffix. Thus, given a
+ * message instance 'msg' with field 'foo', the following code is valid:
+ *
+ * msg.foo = 42
+ * puts msg.foo
+ */
+ @JRubyMethod(name = "method_missing", rest = true)
+ public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) {
+ if (args.length == 1) {
+ RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass);
+ IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]);
+ if (oneofDescriptor.isNil()) {
+ return index(context, args[0]);
+ }
+ RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor;
+ Descriptors.FieldDescriptor fieldDescriptor =
+ oneofCases.get(rubyOneofDescriptor.getOneofDescriptor());
+ if (fieldDescriptor == null)
+ return context.runtime.getNil();
+
+ return context.runtime.newSymbol(fieldDescriptor.getName());
+ } else {
+ // fieldName is RubySymbol
+ RubyString field = args[0].asString();
+ RubyString equalSign = context.runtime.newString(Utils.EQUAL_SIGN);
+ if (field.end_with_p(context, equalSign).isTrue()) {
+ field.chomp_bang(context, equalSign);
+ }
+ return indexSet(context, field, args[1]);
+ }
+ }
+
+ /**
+ * call-seq:
+ * Message.dup => new_message
+ * Performs a shallow copy of this message and returns the new copy.
+ */
+ @JRubyMethod
+ public IRubyObject dup(ThreadContext context) {
+ RubyMessage dup = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK);
+ IRubyObject value;
+ for (Descriptors.FieldDescriptor fieldDescriptor : builder.getAllFields().keySet()) {
+ if (fieldDescriptor.isRepeated()) {
+ dup.repeatedFields.put(fieldDescriptor, getRepeatedField(context, fieldDescriptor));
+ } else if (builder.hasField(fieldDescriptor)) {
+ dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, builder.getField(fieldDescriptor)));
+ }
+ }
+ for (Descriptors.FieldDescriptor fieldDescriptor : fields.keySet()) {
+ dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor));
+ }
+ for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) {
+ dup.maps.put(fieldDescriptor, maps.get(fieldDescriptor));
+ }
+ return dup;
+ }
+
+ /*
+ * call-seq:
+ * Message.descriptor => descriptor
+ *
+ * Class method that returns the Descriptor instance corresponding to this
+ * message class's type.
+ */
+ @JRubyMethod(name = "descriptor", meta = true)
+ public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) {
+ return ((RubyClass) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR);
+ }
+
+ /*
+ * call-seq:
+ * MessageClass.encode(msg) => bytes
+ *
+ * Encodes the given message object to its serialized form in protocol buffers
+ * wire format.
+ */
+ @JRubyMethod(meta = true)
+ public static IRubyObject encode(ThreadContext context, IRubyObject recv, IRubyObject value) {
+ RubyMessage message = (RubyMessage) value;
+ return context.runtime.newString(new ByteList(message.build(context).toByteArray()));
+ }
+
+ /*
+ * call-seq:
+ * MessageClass.decode(data) => message
+ *
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
+ * format) under the interpretration given by this message class's definition
+ * and returns a message object with the corresponding field values.
+ */
+ @JRubyMethod(meta = true)
+ public static IRubyObject decode(ThreadContext context, IRubyObject recv, IRubyObject data) {
+ byte[] bin = data.convertToString().getBytes();
+ RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK);
+ try {
+ ret.builder.mergeFrom(bin);
+ } catch (InvalidProtocolBufferException e) {
+ throw context.runtime.newRuntimeError(e.getMessage());
+ }
+ return ret;
+ }
+
+ /*
+ * call-seq:
+ * MessageClass.encode_json(msg) => json_string
+ *
+ * Encodes the given message object into its serialized JSON representation.
+ */
+ @JRubyMethod(name = "encode_json", meta = true)
+ public static IRubyObject encodeJson(ThreadContext context, IRubyObject recv, IRubyObject msgRb) {
+ RubyMessage message = (RubyMessage) msgRb;
+ return Helpers.invoke(context, message.toHash(context), "to_json");
+ }
+
+ /*
+ * call-seq:
+ * MessageClass.decode_json(data) => message
+ *
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
+ * format) under the interpretration given by this message class's definition
+ * and returns a message object with the corresponding field values.
+ */
+ @JRubyMethod(name = "decode_json", meta = true)
+ public static IRubyObject decodeJson(ThreadContext context, IRubyObject recv, IRubyObject json) {
+ Ruby runtime = context.runtime;
+ RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK);
+ RubyModule jsonModule = runtime.getClassFromPath("JSON");
+ RubyHash opts = RubyHash.newHash(runtime);
+ opts.fastASet(runtime.newSymbol("symbolize_names"), runtime.getTrue());
+ IRubyObject[] args = new IRubyObject[] { Helpers.invoke(context, jsonModule, "parse", json, opts) };
+ ret.initialize(context, args);
+ return ret;
+ }
+
+ @JRubyMethod(name = "to_h")
+ public IRubyObject toHash(ThreadContext context) {
+ Ruby runtime = context.runtime;
+ RubyHash ret = RubyHash.newHash(runtime);
+ for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) {
+ IRubyObject value = getField(context, fdef);
+ if (value.respondsTo("to_h")) {
+ value = Helpers.invoke(context, value, "to_h");
+ }
+ ret.fastASet(runtime.newString(fdef.getName()), value);
+ }
+ return ret;
+ }
+
+ protected DynamicMessage build(ThreadContext context) {
+ return build(context, 0);
+ }
+
+ protected DynamicMessage build(ThreadContext context, int depth) {
+ if (depth > SINK_MAXIMUM_NESTING) {
+ throw context.runtime.newRuntimeError("Maximum recursion depth exceeded during encoding.");
+ }
+ for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) {
+ this.builder.clearField(fieldDescriptor);
+ RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor);
+ for (DynamicMessage kv : maps.get(fieldDescriptor).build(context, mapDescriptor)) {
+ this.builder.addRepeatedField(fieldDescriptor, kv);
+ }
+ }
+ for (Descriptors.FieldDescriptor fieldDescriptor : repeatedFields.keySet()) {
+ RubyRepeatedField repeatedField = repeatedFields.get(fieldDescriptor);
+ this.builder.clearField(fieldDescriptor);
+ for (int i = 0; i < repeatedField.size(); i++) {
+ Object item = convert(context, fieldDescriptor, repeatedField.get(i), depth);
+ this.builder.addRepeatedField(fieldDescriptor, item);
+ }
+ }
+ for (Descriptors.FieldDescriptor fieldDescriptor : fields.keySet()) {
+ IRubyObject value = fields.get(fieldDescriptor);
+ this.builder.setField(fieldDescriptor, convert(context, fieldDescriptor, value, depth));
+ }
+ return this.builder.build();
+ }
+
+ protected Descriptors.Descriptor getDescriptor() {
+ return this.descriptor;
+ }
+
+ // Internal use only, called by Google::Protobuf.deep_copy
+ protected IRubyObject deepCopy(ThreadContext context) {
+ RubyMessage copy = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK);
+ for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) {
+ if (fdef.isRepeated()) {
+ copy.addRepeatedField(fdef, this.getRepeatedField(context, fdef).deepCopy(context));
+ } else if (fields.containsKey(fdef)) {
+ copy.fields.put(fdef, fields.get(fdef));
+ } else if (this.builder.hasField(fdef)) {
+ copy.fields.put(fdef, wrapField(context, fdef, this.builder.getField(fdef)));
+ }
+ }
+ return copy;
+ }
+
+ private RubyRepeatedField getRepeatedField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
+ if (this.repeatedFields.containsKey(fieldDescriptor)) {
+ return this.repeatedFields.get(fieldDescriptor);
+ }
+ int count = this.builder.getRepeatedFieldCount(fieldDescriptor);
+ RubyRepeatedField ret = repeatedFieldForFieldDescriptor(context, fieldDescriptor);
+ for (int i = 0; i < count; i++) {
+ ret.push(context, wrapField(context, fieldDescriptor, this.builder.getRepeatedField(fieldDescriptor, i)));
+ }
+ return ret;
+ }
+
+ private void addRepeatedField(Descriptors.FieldDescriptor fieldDescriptor, RubyRepeatedField repeatedField) {
+ this.repeatedFields.put(fieldDescriptor, repeatedField);
+ }
+
+ private IRubyObject buildFrom(ThreadContext context, DynamicMessage dynamicMessage) {
+ this.builder.mergeFrom(dynamicMessage);
+ return this;
+ }
+
+ private Descriptors.FieldDescriptor findField(ThreadContext context, IRubyObject fieldName) {
+ String nameStr = fieldName.asJavaString();
+ Descriptors.FieldDescriptor ret = this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr));
+ if (ret == null)
+ throw context.runtime.newArgumentError("field " + fieldName.asJavaString() + " is not found");
+ return ret;
+ }
+
+ private void checkRepeatedFieldType(ThreadContext context, IRubyObject value,
+ Descriptors.FieldDescriptor fieldDescriptor) {
+ Ruby runtime = context.runtime;
+ if (!(value instanceof RubyRepeatedField)) {
+ throw runtime.newTypeError("Expected repeated field array");
+ }
+ }
+
+ // convert a ruby object to protobuf type, with type check
+ private Object convert(ThreadContext context,
+ Descriptors.FieldDescriptor fieldDescriptor,
+ IRubyObject value, int depth) {
+ Ruby runtime = context.runtime;
+ Object val = null;
+ switch (fieldDescriptor.getType()) {
+ case INT32:
+ case INT64:
+ case UINT32:
+ case UINT64:
+ if (!Utils.isRubyNum(value)) {
+ throw runtime.newTypeError("Expected number type for integral field.");
+ }
+ Utils.checkIntTypePrecision(context, fieldDescriptor.getType(), value);
+ switch (fieldDescriptor.getType()) {
+ case INT32:
+ val = RubyNumeric.num2int(value);
+ break;
+ case INT64:
+ val = RubyNumeric.num2long(value);
+ break;
+ case UINT32:
+ val = Utils.num2uint(value);
+ break;
+ case UINT64:
+ val = Utils.num2ulong(context.runtime, value);
+ break;
+ default:
+ break;
+ }
+ break;
+ case FLOAT:
+ if (!Utils.isRubyNum(value))
+ throw runtime.newTypeError("Expected number type for float field.");
+ val = (float) RubyNumeric.num2dbl(value);
+ break;
+ case DOUBLE:
+ if (!Utils.isRubyNum(value))
+ throw runtime.newTypeError("Expected number type for double field.");
+ val = RubyNumeric.num2dbl(value);
+ break;
+ case BOOL:
+ if (!(value instanceof RubyBoolean))
+ throw runtime.newTypeError("Invalid argument for boolean field.");
+ val = value.isTrue();
+ break;
+ case BYTES:
+ case STRING:
+ Utils.validateStringEncoding(context.runtime, fieldDescriptor.getType(), value);
+ RubyString str = (RubyString) value;
+ switch (fieldDescriptor.getType()) {
+ case BYTES:
+ val = ByteString.copyFrom(str.getBytes());
+ break;
+ case STRING:
+ val = str.asJavaString();
+ break;
+ default:
+ break;
+ }
+ break;
+ case MESSAGE:
+ RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
+ if (!value.getMetaClass().equals(typeClass))
+ throw runtime.newTypeError(value, "Invalid type to assign to submessage field.");
+ val = ((RubyMessage) value).build(context, depth + 1);
+ break;
+ case ENUM:
+ Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType();
+
+ if (Utils.isRubyNum(value)) {
+ val = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value));
+ } else if (value instanceof RubySymbol) {
+ val = enumDescriptor.findValueByName(value.asJavaString());
+ } else {
+ throw runtime.newTypeError("Expected number or symbol type for enum field.");
+ }
+ if (val == null) {
+ throw runtime.newRangeError("Enum value " + value + " is not found.");
+ }
+ break;
+ default:
+ break;
+ }
+ return val;
+ }
+
+ private IRubyObject wrapField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, Object value) {
+ if (value == null) {
+ return context.runtime.getNil();
+ }
+ Ruby runtime = context.runtime;
+ switch (fieldDescriptor.getType()) {
+ case INT32:
+ case INT64:
+ case UINT32:
+ case UINT64:
+ case FLOAT:
+ case DOUBLE:
+ case BOOL:
+ case BYTES:
+ case STRING:
+ return Utils.wrapPrimaryValue(context, fieldDescriptor.getType(), value);
+ case MESSAGE:
+ RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
+ RubyMessage msg = (RubyMessage) typeClass.newInstance(context, Block.NULL_BLOCK);
+ return msg.buildFrom(context, (DynamicMessage) value);
+ case ENUM:
+ Descriptors.EnumValueDescriptor enumValueDescriptor = (Descriptors.EnumValueDescriptor) value;
+ if (enumValueDescriptor.getIndex() == -1) { // UNKNOWN ENUM VALUE
+ return runtime.newFixnum(enumValueDescriptor.getNumber());
+ }
+ return runtime.newSymbol(enumValueDescriptor.getName());
+ default:
+ return runtime.newString(value.toString());
+ }
+ }
+
+ private RubyRepeatedField repeatedFieldForFieldDescriptor(ThreadContext context,
+ Descriptors.FieldDescriptor fieldDescriptor) {
+ IRubyObject typeClass = context.runtime.getNilClass();
+
+ IRubyObject descriptor = getDescriptorForField(context, fieldDescriptor);
+ Descriptors.FieldDescriptor.Type type = fieldDescriptor.getType();
+ if (type == Descriptors.FieldDescriptor.Type.MESSAGE) {
+ typeClass = ((RubyDescriptor) descriptor).msgclass(context);
+
+ } else if (type == Descriptors.FieldDescriptor.Type.ENUM) {
+ typeClass = ((RubyEnumDescriptor) descriptor).enummodule(context);
+ }
+ return new RubyRepeatedField(context.runtime, cRepeatedField, type, typeClass);
+ }
+
+ protected IRubyObject getField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
+ Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof();
+ if (oneofDescriptor != null) {
+ if (oneofCases.containsKey(oneofDescriptor)) {
+ if (oneofCases.get(oneofDescriptor) != fieldDescriptor)
+ return context.runtime.getNil();
+ return fields.get(fieldDescriptor);
+ } else {
+ Descriptors.FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor);
+ if (oneofCase != fieldDescriptor) return context.runtime.getNil();
+ IRubyObject value = wrapField(context, oneofCase, builder.getField(oneofCase));
+ fields.put(fieldDescriptor, value);
+ return value;
+ }
+ }
+
+ if (Utils.isMapEntry(fieldDescriptor)) {
+ RubyMap map = maps.get(fieldDescriptor);
+ if (map == null) {
+ map = newMapForField(context, fieldDescriptor);
+ int mapSize = this.builder.getRepeatedFieldCount(fieldDescriptor);
+ Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1);
+ Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2);
+ RubyDescriptor kvDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor);
+ RubyClass kvClass = (RubyClass) kvDescriptor.msgclass(context);
+ for (int i = 0; i < mapSize; i++) {
+ RubyMessage kvMessage = (RubyMessage) kvClass.newInstance(context, Block.NULL_BLOCK);
+ DynamicMessage message = (DynamicMessage) this.builder.getRepeatedField(fieldDescriptor, i);
+ kvMessage.buildFrom(context, message);
+ map.indexSet(context, kvMessage.getField(context, keyField), kvMessage.getField(context, valueField));
+ }
+ maps.put(fieldDescriptor, map);
+ }
+ return map;
+ }
+ if (fieldDescriptor.isRepeated()) {
+ return getRepeatedField(context, fieldDescriptor);
+ }
+ if (fieldDescriptor.getType() != Descriptors.FieldDescriptor.Type.MESSAGE ||
+ this.builder.hasField(fieldDescriptor) || fields.containsKey(fieldDescriptor)) {
+ if (fields.containsKey(fieldDescriptor)) {
+ return fields.get(fieldDescriptor);
+ } else {
+ IRubyObject value = wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor));
+ if (this.builder.hasField(fieldDescriptor)) {
+ fields.put(fieldDescriptor, value);
+ }
+ return value;
+ }
+ }
+ return context.runtime.getNil();
+ }
+
+ protected IRubyObject setField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) {
+ if (Utils.isMapEntry(fieldDescriptor)) {
+ if (!(value instanceof RubyMap)) {
+ throw context.runtime.newTypeError("Expected Map instance");
+ }
+ RubyMap thisMap = (RubyMap) getField(context, fieldDescriptor);
+ thisMap.mergeIntoSelf(context, value);
+ } else if (fieldDescriptor.isRepeated()) {
+ checkRepeatedFieldType(context, value, fieldDescriptor);
+ if (value instanceof RubyRepeatedField) {
+ addRepeatedField(fieldDescriptor, (RubyRepeatedField) value);
+ } else {
+ RubyArray ary = value.convertToArray();
+ RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, ary);
+ addRepeatedField(fieldDescriptor, repeatedField);
+ }
+ } else {
+ Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof();
+ if (oneofDescriptor != null) {
+ Descriptors.FieldDescriptor oneofCase = oneofCases.get(oneofDescriptor);
+ if (oneofCase != null && oneofCase != fieldDescriptor) {
+ fields.remove(oneofCase);
+ }
+ if (value.isNil()) {
+ oneofCases.remove(oneofDescriptor);
+ fields.remove(fieldDescriptor);
+ } else {
+ oneofCases.put(oneofDescriptor, fieldDescriptor);
+ fields.put(fieldDescriptor, value);
+ }
+ } else {
+ Descriptors.FieldDescriptor.Type fieldType = fieldDescriptor.getType();
+ IRubyObject typeClass = context.runtime.getObject();
+ if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) {
+ typeClass = ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
+ } else if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) {
+ typeClass = ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)).enummodule(context);
+ }
+ Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+ // Convert integer enum to symbol
+ if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) {
+ Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType();
+ if (Utils.isRubyNum(value)) {
+ Descriptors.EnumValueDescriptor val =
+ enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value));
+ if (val.getIndex() != -1) value = context.runtime.newSymbol(val.getName());
+ }
+ }
+ this.fields.put(fieldDescriptor, value);
+ }
+ }
+ return context.runtime.getNil();
+ }
+
+ private String layoutInspect() {
+ ThreadContext context = getRuntime().getCurrentContext();
+ StringBuilder sb = new StringBuilder();
+ for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) {
+ sb.append(Utils.unescapeIdentifier(fdef.getName()));
+ sb.append(": ");
+ sb.append(getField(context, fdef).inspect());
+ sb.append(", ");
+ }
+ return sb.substring(0, sb.length() - 2);
+ }
+
+ private IRubyObject getDescriptorForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
+ RubyDescriptor thisRbDescriptor = (RubyDescriptor) getDescriptor(context, metaClass);
+ return thisRbDescriptor.lookup(fieldDescriptor.getName()).getSubType(context);
+ }
+
+ private RubyRepeatedField rubyToRepeatedField(ThreadContext context,
+ Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) {
+ RubyArray arr = value.convertToArray();
+ RubyRepeatedField repeatedField = repeatedFieldForFieldDescriptor(context, fieldDescriptor);
+ for (int i = 0; i < arr.size(); i++) {
+ repeatedField.push(context, arr.eltInternal(i));
+ }
+ return repeatedField;
+ }
+
+ private RubyMap newMapForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
+ RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor);
+ Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1);
+ Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2);
+ IRubyObject keyType = RubySymbol.newSymbol(context.runtime, keyField.getType().name());
+ IRubyObject valueType = RubySymbol.newSymbol(context.runtime, valueField.getType().name());
+ if (valueField.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) {
+ RubyFieldDescriptor rubyFieldDescriptor = (RubyFieldDescriptor) mapDescriptor.lookup(context,
+ context.runtime.newString("value"));
+ RubyDescriptor rubyDescriptor = (RubyDescriptor) rubyFieldDescriptor.getSubType(context);
+ return (RubyMap) cMap.newInstance(context, keyType, valueType,
+ rubyDescriptor.msgclass(context), Block.NULL_BLOCK);
+ } else {
+ return (RubyMap) cMap.newInstance(context, keyType, valueType, Block.NULL_BLOCK);
+ }
+ }
+
+ private Descriptors.FieldDescriptor getOneofCase(Descriptors.OneofDescriptor oneof) {
+ if (oneofCases.containsKey(oneof)) {
+ return oneofCases.get(oneof);
+ }
+ return builder.getOneofFieldDescriptor(oneof);
+ }
+
+ private Descriptors.Descriptor descriptor;
+ private DynamicMessage.Builder builder;
+ private RubyClass cRepeatedField;
+ private RubyClass cMap;
+ private Map<Descriptors.FieldDescriptor, RubyRepeatedField> repeatedFields;
+ private Map<Descriptors.FieldDescriptor, RubyMap> maps;
+ private Map<Descriptors.FieldDescriptor, IRubyObject> fields;
+ private Map<Descriptors.OneofDescriptor, Descriptors.FieldDescriptor> oneofCases;
+
+ private static final int SINK_MAXIMUM_NESTING = 64;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java
new file mode 100644
index 00000000..a619b803
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Binding;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "MessageBuilderContext")
+public class RubyMessageBuilderContext extends RubyObject {
+ public static void createRubyMessageBuilderContext(Ruby runtime) {
+ RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cMessageBuilderContext = protobuf.defineClassUnder("MessageBuilderContext", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+ return new RubyMessageBuilderContext(runtime, klazz);
+ }
+ });
+ cMessageBuilderContext.defineAnnotatedMethods(RubyMessageBuilderContext.class);
+ }
+
+ public RubyMessageBuilderContext(Ruby ruby, RubyClass klazz) {
+ super(ruby, klazz);
+ }
+
+ @JRubyMethod
+ public IRubyObject initialize(ThreadContext context, IRubyObject descriptor, IRubyObject rubyBuilder) {
+ this.cFieldDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::FieldDescriptor");
+ this.cDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Descriptor");
+ this.cOneofDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::OneofDescriptor");
+ this.cOneofBuilderContext = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Internal::OneofBuilderContext");
+ this.descriptor = (RubyDescriptor) descriptor;
+ this.builder = (RubyBuilder) rubyBuilder;
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * MessageBuilderContext.optional(name, type, number, type_class = nil)
+ *
+ * Defines a new optional field on this message type with the given type, tag
+ * number, and type class (for message and enum fields). The type must be a Ruby
+ * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+ * string, if present (as accepted by FieldDescriptor#submsg_name=).
+ */
+ @JRubyMethod(required = 3, optional = 1)
+ public IRubyObject optional(ThreadContext context, IRubyObject[] args) {
+ Ruby runtime = context.runtime;
+ IRubyObject typeClass = runtime.getNil();
+ if (args.length > 3) typeClass = args[3];
+ msgdefAddField(context, "optional", args[0], args[1], args[2], typeClass);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * MessageBuilderContext.required(name, type, number, type_class = nil)
+ *
+ * Defines a new required field on this message type with the given type, tag
+ * number, and type class (for message and enum fields). The type must be a Ruby
+ * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+ * string, if present (as accepted by FieldDescriptor#submsg_name=).
+ *
+ * Proto3 does not have required fields, but this method exists for
+ * completeness. Any attempt to add a message type with required fields to a
+ * pool will currently result in an error.
+ */
+ @JRubyMethod(required = 3, optional = 1)
+ public IRubyObject required(ThreadContext context, IRubyObject[] args) {
+ IRubyObject typeClass = context.runtime.getNil();
+ if (args.length > 3) typeClass = args[3];
+ msgdefAddField(context, "required", args[0], args[1], args[2], typeClass);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * MessageBuilderContext.repeated(name, type, number, type_class = nil)
+ *
+ * Defines a new repeated field on this message type with the given type, tag
+ * number, and type class (for message and enum fields). The type must be a Ruby
+ * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+ * string, if present (as accepted by FieldDescriptor#submsg_name=).
+ */
+ @JRubyMethod(required = 3, optional = 1)
+ public IRubyObject repeated(ThreadContext context, IRubyObject[] args) {
+ IRubyObject typeClass = context.runtime.getNil();
+ if (args.length > 3) typeClass = args[3];
+ msgdefAddField(context, "repeated", args[0], args[1], args[2], typeClass);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * MessageBuilderContext.map(name, key_type, value_type, number,
+ * value_type_class = nil)
+ *
+ * Defines a new map field on this message type with the given key and value
+ * types, tag number, and type class (for message and enum value types). The key
+ * type must be :int32/:uint32/:int64/:uint64, :bool, or :string. The value type
+ * type must be a Ruby symbol (as accepted by FieldDescriptor#type=) and the
+ * type_class must be a string, if present (as accepted by
+ * FieldDescriptor#submsg_name=).
+ */
+ @JRubyMethod(required = 4, optional = 1)
+ public IRubyObject map(ThreadContext context, IRubyObject[] args) {
+ Ruby runtime = context.runtime;
+ IRubyObject name = args[0];
+ IRubyObject keyType = args[1];
+ IRubyObject valueType = args[2];
+ IRubyObject number = args[3];
+ IRubyObject typeClass = args.length > 4 ? args[4] : context.runtime.getNil();
+
+ // Validate the key type. We can't accept enums, messages, or floats/doubles
+ // as map keys. (We exclude these explicitly, and the field-descriptor setter
+ // below then ensures that the type is one of the remaining valid options.)
+ if (keyType.equals(RubySymbol.newSymbol(runtime, "float")) ||
+ keyType.equals(RubySymbol.newSymbol(runtime, "double")) ||
+ keyType.equals(RubySymbol.newSymbol(runtime, "enum")) ||
+ keyType.equals(RubySymbol.newSymbol(runtime, "message")))
+ throw runtime.newArgumentError("Cannot add a map field with a float, double, enum, or message type.");
+
+ // Create a new message descriptor for the map entry message, and create a
+ // repeated submessage field here with that type.
+ RubyDescriptor mapentryDesc = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK);
+ IRubyObject mapentryDescName = RubySymbol.newSymbol(runtime, name).id2name(context);
+ mapentryDesc.setName(context, mapentryDescName);
+ mapentryDesc.setMapEntry(true);
+
+ //optional <type> key = 1;
+ RubyFieldDescriptor keyField = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK);
+ keyField.setName(context, runtime.newString("key"));
+ keyField.setLabel(context, RubySymbol.newSymbol(runtime, "optional"));
+ keyField.setNumber(context, runtime.newFixnum(1));
+ keyField.setType(context, keyType);
+ mapentryDesc.addField(context, keyField);
+
+ //optional <type> value = 2;
+ RubyFieldDescriptor valueField = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK);
+ valueField.setName(context, runtime.newString("value"));
+ valueField.setLabel(context, RubySymbol.newSymbol(runtime, "optional"));
+ valueField.setNumber(context, runtime.newFixnum(2));
+ valueField.setType(context, valueType);
+ if (! typeClass.isNil()) valueField.setSubmsgName(context, typeClass);
+ mapentryDesc.addField(context, valueField);
+
+ // Add the map-entry message type to the current builder, and use the type to
+ // create the map field itself.
+ this.builder.pendingList.add(mapentryDesc);
+
+ msgdefAddField(context, "repeated", name, runtime.newSymbol("message"), number, mapentryDescName);
+ return runtime.getNil();
+ }
+
+ @JRubyMethod
+ public IRubyObject oneof(ThreadContext context, IRubyObject name, Block block) {
+ RubyOneofDescriptor oneofdef = (RubyOneofDescriptor)
+ cOneofDescriptor.newInstance(context, Block.NULL_BLOCK);
+ RubyOneofBuilderContext ctx = (RubyOneofBuilderContext)
+ cOneofBuilderContext.newInstance(context, oneofdef, Block.NULL_BLOCK);
+ oneofdef.setName(context, name);
+ Binding binding = block.getBinding();
+ binding.setSelf(ctx);
+ block.yieldSpecific(context);
+ descriptor.addOneof(context, oneofdef);
+ return context.runtime.getNil();
+ }
+
+ private void msgdefAddField(ThreadContext context, String label, IRubyObject name,
+ IRubyObject type, IRubyObject number, IRubyObject typeClass) {
+ descriptor.addField(context,
+ Utils.msgdefCreateField(context, label, name, type, number, typeClass, cFieldDescriptor));
+ }
+
+ private RubyDescriptor descriptor;
+ private RubyBuilder builder;
+ private RubyClass cFieldDescriptor;
+ private RubyClass cOneofDescriptor;
+ private RubyClass cOneofBuilderContext;
+ private RubyClass cDescriptor;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java
new file mode 100644
index 00000000..c9b99e04
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "OneofBuilderContext")
+public class RubyOneofBuilderContext extends RubyObject {
+ public static void createRubyOneofBuilderContext(Ruby runtime) {
+ RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyModule internal = protobuf.defineModuleUnder("Internal");
+ RubyClass cRubyOneofBuidlerContext = internal.defineClassUnder("OneofBuilderContext", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
+ return new RubyOneofBuilderContext(ruby, rubyClass);
+ }
+ });
+ cRubyOneofBuidlerContext.defineAnnotatedMethods(RubyOneofBuilderContext.class);
+ }
+
+ public RubyOneofBuilderContext(Ruby ruby, RubyClass rubyClass) {
+ super(ruby, rubyClass);
+ }
+
+ @JRubyMethod
+ public IRubyObject initialize(ThreadContext context, IRubyObject oneofdef) {
+ this.descriptor = (RubyOneofDescriptor) oneofdef;
+ this.cFieldDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::FieldDescriptor");
+ return this;
+ }
+
+ @JRubyMethod(required = 3, optional = 1)
+ public IRubyObject optional(ThreadContext context, IRubyObject[] args) {
+ IRubyObject name = args[0];
+ IRubyObject type = args[1];
+ IRubyObject number = args[2];
+ IRubyObject typeClass = args.length > 3 ? args[3] : context.runtime.getNil();
+ RubyFieldDescriptor fieldDescriptor = Utils.msgdefCreateField(context, "optional",
+ name, type, number, typeClass, cFieldDescriptor);
+ descriptor.addField(context, fieldDescriptor);
+ return this;
+ }
+
+ private RubyOneofDescriptor descriptor;
+ private RubyClass cFieldDescriptor;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java
new file mode 100644
index 00000000..cc4ab662
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java
@@ -0,0 +1,124 @@
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.util.*;
+
+@JRubyClass(name = "OneofDescriptor", include = "Enumerable")
+public class RubyOneofDescriptor extends RubyObject {
+
+ public static void createRubyOneofDescriptor(Ruby runtime) {
+ RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cRubyOneofDescriptor = protobuf.defineClassUnder("OneofDescriptor", runtime.getObject(), new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
+ return new RubyOneofDescriptor(ruby, rubyClass);
+ }
+ });
+ cRubyOneofDescriptor.defineAnnotatedMethods(RubyOneofDescriptor.class);
+ cRubyOneofDescriptor.includeModule(runtime.getEnumerable());
+ }
+
+ public RubyOneofDescriptor(Ruby ruby, RubyClass rubyClass) {
+ super(ruby, rubyClass);
+ }
+
+ @JRubyMethod
+ public IRubyObject initialize(ThreadContext context) {
+ builder = DescriptorProtos.OneofDescriptorProto.newBuilder();
+ fields = new ArrayList<RubyFieldDescriptor>();
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * OneofDescriptor.name => name
+ *
+ * Returns the name of this oneof.
+ */
+ @JRubyMethod(name = "name")
+ public IRubyObject getName(ThreadContext context) {
+ return name;
+ }
+
+ /*
+ * call-seq:
+ * OneofDescriptor.name = name
+ *
+ * Sets a new name for this oneof. The oneof must not have been added to a
+ * message descriptor yet.
+ */
+ @JRubyMethod(name = "name=")
+ public IRubyObject setName(ThreadContext context, IRubyObject name) {
+ this.name = context.runtime.newString(name.asJavaString());
+ this.builder.setName(name.asJavaString());
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * OneofDescriptor.add_field(field) => nil
+ *
+ * Adds a field to this oneof. The field may have been added to this oneof in
+ * the past, or the message to which this oneof belongs (if any), but may not
+ * have already been added to any other oneof or message. Otherwise, an
+ * exception is raised.
+ *
+ * All fields added to the oneof via this method will be automatically added to
+ * the message to which this oneof belongs, if it belongs to one currently, or
+ * else will be added to any message to which the oneof is later added at the
+ * time that it is added.
+ */
+ @JRubyMethod(name = "add_field")
+ public IRubyObject addField(ThreadContext context, IRubyObject obj) {
+ RubyFieldDescriptor fieldDescriptor = (RubyFieldDescriptor) obj;
+ fieldDescriptor.setOneofName(this.name);
+ fields.add(fieldDescriptor);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * OneofDescriptor.each(&block) => nil
+ *
+ * Iterates through fields in this oneof, yielding to the block on each one.
+ */
+ @JRubyMethod
+ public IRubyObject each(ThreadContext context, Block block) {
+ for (RubyFieldDescriptor field : fields) {
+ block.yieldSpecific(context, field);
+ }
+ return context.runtime.getNil();
+ }
+
+ public DescriptorProtos.OneofDescriptorProto build(int index) {
+ for (RubyFieldDescriptor field: fields) {
+ field.setOneofIndex(index);
+ }
+ return this.builder.build();
+ }
+
+ protected Collection<RubyFieldDescriptor> getFields() {
+ return fields;
+ }
+
+ protected Descriptors.OneofDescriptor getOneofDescriptor() {
+ RubyFieldDescriptor fieldDescriptor = fields.get(0);
+ return fieldDescriptor.getFieldDef().getContainingOneof();
+ }
+
+ private IRubyObject name;
+ private DescriptorProtos.OneofDescriptorProto.Builder builder;
+ private List<RubyFieldDescriptor> fields;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java
new file mode 100644
index 00000000..cb3fcd48
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import org.jruby.Ruby;
+import org.jruby.RubyModule;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.anno.JRubyModule;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyModule(name = "Protobuf")
+public class RubyProtobuf {
+
+ public static void createProtobuf(Ruby runtime) {
+ RubyModule mGoogle = runtime.getModule("Google");
+ RubyModule mProtobuf = mGoogle.defineModuleUnder("Protobuf");
+ mProtobuf.defineAnnotatedMethods(RubyProtobuf.class);
+ }
+
+ /*
+ * call-seq:
+ * Google::Protobuf.encode(msg) => bytes
+ *
+ * Encodes the given message object to protocol buffers wire format. This is an
+ * alternative to the #encode method on msg's class.
+ */
+ @JRubyMethod(meta = true)
+ public static IRubyObject encode(ThreadContext context, IRubyObject self, IRubyObject message) {
+ return RubyMessage.encode(context, message.getMetaClass(), message);
+ }
+
+ /*
+ * call-seq:
+ * Google::Protobuf.decode(class, bytes) => msg
+ *
+ * Decodes the given bytes as protocol buffers wire format under the
+ * interpretation given by the given class's message definition. This is an
+ * alternative to the #decode method on the given class.
+ */
+ @JRubyMethod(meta = true)
+ public static IRubyObject decode(ThreadContext context, IRubyObject self, IRubyObject klazz, IRubyObject message) {
+ return RubyMessage.decode(context, klazz, message);
+ }
+
+ /*
+ * call-seq:
+ * Google::Protobuf.encode_json(msg) => json_string
+ *
+ * Encodes the given message object to its JSON representation. This is an
+ * alternative to the #encode_json method on msg's class.
+ */
+ @JRubyMethod(name = "encode_json", meta = true)
+ public static IRubyObject encodeJson(ThreadContext context, IRubyObject self, IRubyObject message) {
+ return RubyMessage.encodeJson(context, message.getMetaClass(), message);
+ }
+
+ /*
+ * call-seq:
+ * Google::Protobuf.decode_json(class, json_string) => msg
+ *
+ * Decodes the given JSON string under the interpretation given by the given
+ * class's message definition. This is an alternative to the #decode_json method
+ * on the given class.
+ */
+ @JRubyMethod(name = "decode_json", meta = true)
+ public static IRubyObject decodeJson(ThreadContext context, IRubyObject self, IRubyObject klazz, IRubyObject message) {
+ return RubyMessage.decodeJson(context, klazz, message);
+ }
+
+ /*
+ * call-seq:
+ * Google::Protobuf.deep_copy(obj) => copy_of_obj
+ *
+ * Performs a deep copy of either a RepeatedField instance or a message object,
+ * recursively copying its members.
+ */
+ @JRubyMethod(name = "deep_copy", meta = true)
+ public static IRubyObject deepCopy(ThreadContext context, IRubyObject self, IRubyObject message) {
+ if (message instanceof RubyMessage) {
+ return ((RubyMessage) message).deepCopy(context);
+ } else if (message instanceof RubyRepeatedField) {
+ return ((RubyRepeatedField) message).deepCopy(context);
+ } else {
+ return ((RubyMap) message).deepCopy(context);
+ }
+ }
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
new file mode 100644
index 00000000..9788317a
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
@@ -0,0 +1,391 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "RepeatedClass", include = "Enumerable")
+public class RubyRepeatedField extends RubyObject {
+ public static void createRubyRepeatedField(Ruby runtime) {
+ RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
+ RubyClass cRepeatedField = mProtobuf.defineClassUnder("RepeatedField", runtime.getObject(),
+ new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+ return new RubyRepeatedField(runtime, klazz);
+ }
+ });
+ cRepeatedField.defineAnnotatedMethods(RubyRepeatedField.class);
+ cRepeatedField.includeModule(runtime.getEnumerable());
+ }
+
+ public RubyRepeatedField(Ruby runtime, RubyClass klazz) {
+ super(runtime, klazz);
+ }
+
+ public RubyRepeatedField(Ruby runtime, RubyClass klazz, Descriptors.FieldDescriptor.Type fieldType, IRubyObject typeClass) {
+ this(runtime, klazz);
+ this.fieldType = fieldType;
+ this.storage = runtime.newArray();
+ this.typeClass = typeClass;
+ }
+
+ @JRubyMethod(required = 1, optional = 2)
+ public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
+ Ruby runtime = context.runtime;
+ this.storage = runtime.newArray();
+ IRubyObject ary = null;
+ if (!(args[0] instanceof RubySymbol)) {
+ throw runtime.newArgumentError("Expected Symbol for type name");
+ }
+ this.fieldType = Utils.rubyToFieldType(args[0]);
+ if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE
+ || fieldType == Descriptors.FieldDescriptor.Type.ENUM) {
+ if (args.length < 2)
+ throw runtime.newArgumentError("Expected at least 2 arguments for message/enum");
+ typeClass = args[1];
+ if (args.length > 2)
+ ary = args[2];
+ Utils.validateTypeClass(context, fieldType, typeClass);
+ } else {
+ if (args.length > 2)
+ throw runtime.newArgumentError("Too many arguments: expected 1 or 2");
+ if (args.length > 1)
+ ary = args[1];
+ }
+ if (ary != null) {
+ RubyArray arr = ary.convertToArray();
+ for (int i = 0; i < arr.size(); i++) {
+ this.storage.add(arr.eltInternal(i));
+ }
+ }
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.[]=(index, value)
+ *
+ * Sets the element at the given index. On out-of-bounds assignments, extends
+ * the array and fills the hole (if any) with default values.
+ */
+ @JRubyMethod(name = "[]=")
+ public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) {
+ Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+ this.storage.set(RubyNumeric.num2int(index), value);
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.[](index) => value
+ *
+ * Accesses the element at the given index. Throws an exception on out-of-bounds
+ * errors.
+ */
+ @JRubyMethod(name = "[]")
+ public IRubyObject index(ThreadContext context, IRubyObject index) {
+ return this.storage.eltInternal(RubyNumeric.num2int(index));
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.insert(*args)
+ *
+ * Pushes each arg in turn onto the end of the repeated field.
+ */
+ @JRubyMethod(rest = true)
+ public IRubyObject insert(ThreadContext context, IRubyObject[] args) {
+ for (int i = 0; i < args.length; i++) {
+ Utils.checkType(context, fieldType, args[i], (RubyModule) typeClass);
+ this.storage.add(args[i]);
+ }
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.push(value)
+ *
+ * Adds a new element to the repeated field.
+ */
+ @JRubyMethod(name = {"push", "<<"})
+ public IRubyObject push(ThreadContext context, IRubyObject value) {
+ Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+ this.storage.add(value);
+ return this;
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.pop => value
+ *
+ * Removes the last element and returns it. Throws an exception if the repeated
+ * field is empty.
+ */
+ @JRubyMethod
+ public IRubyObject pop(ThreadContext context) {
+ IRubyObject ret = this.storage.last();
+ this.storage.remove(ret);
+ return ret;
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.replace(list)
+ *
+ * Replaces the contents of the repeated field with the given list of elements.
+ */
+ @JRubyMethod
+ public IRubyObject replace(ThreadContext context, IRubyObject list) {
+ RubyArray arr = (RubyArray) list;
+ checkArrayElementType(context, arr);
+ this.storage = arr;
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.clear
+ *
+ * Clears (removes all elements from) this repeated field.
+ */
+ @JRubyMethod
+ public IRubyObject clear(ThreadContext context) {
+ this.storage.clear();
+ return context.runtime.getNil();
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.length
+ *
+ * Returns the length of this repeated field.
+ */
+ @JRubyMethod(name = {"count", "length"})
+ public IRubyObject length(ThreadContext context) {
+ return context.runtime.newFixnum(this.storage.size());
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.+(other) => repeated field
+ *
+ * Returns a new repeated field that contains the concatenated list of this
+ * repeated field's elements and other's elements. The other (second) list may
+ * be either another repeated field or a Ruby array.
+ */
+ @JRubyMethod(name = "+")
+ public IRubyObject plus(ThreadContext context, IRubyObject list) {
+ RubyRepeatedField dup = (RubyRepeatedField) dup(context);
+ if (list instanceof RubyArray) {
+ checkArrayElementType(context, (RubyArray) list);
+ dup.storage.addAll((RubyArray) list);
+ } else {
+ RubyRepeatedField repeatedField = (RubyRepeatedField) list;
+ if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && !
+ typeClass.equals(repeatedField.typeClass)))
+ throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type.");
+ dup.storage.addAll((RubyArray) repeatedField.toArray(context));
+ }
+ return dup;
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.hash => hash_value
+ *
+ * Returns a hash value computed from this repeated field's elements.
+ */
+ @JRubyMethod
+ public IRubyObject hash(ThreadContext context) {
+ int hashCode = System.identityHashCode(this.storage);
+ return context.runtime.newFixnum(hashCode);
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.==(other) => boolean
+ *
+ * Compares this repeated field to another. Repeated fields are equal if their
+ * element types are equal, their lengths are equal, and each element is equal.
+ * Elements are compared as per normal Ruby semantics, by calling their :==
+ * methods (or performing a more efficient comparison for primitive types).
+ */
+ @JRubyMethod(name = "==")
+ public IRubyObject eq(ThreadContext context, IRubyObject other) {
+ return this.toArray(context).op_equal(context, other);
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.each(&block)
+ *
+ * Invokes the block once for each element of the repeated field. RepeatedField
+ * also includes Enumerable; combined with this method, the repeated field thus
+ * acts like an ordinary Ruby sequence.
+ */
+ @JRubyMethod
+ public IRubyObject each(ThreadContext context, Block block) {
+ this.storage.each(context, block);
+ return context.runtime.getNil();
+ }
+
+ @JRubyMethod(name = {"to_ary", "to_a"})
+ public IRubyObject toArray(ThreadContext context) {
+ for (int i = 0; i < this.storage.size(); i++) {
+ IRubyObject defaultValue = defaultValue(context);
+ if (storage.eltInternal(i).isNil()) {
+ storage.set(i, defaultValue);
+ }
+ }
+ return this.storage;
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.dup => repeated_field
+ *
+ * Duplicates this repeated field with a shallow copy. References to all
+ * non-primitive element objects (e.g., submessages) are shared.
+ */
+ @JRubyMethod
+ public IRubyObject dup(ThreadContext context) {
+ RubyRepeatedField dup = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
+ for (int i = 0; i < this.storage.size(); i++) {
+ dup.push(context, this.storage.eltInternal(i));
+ }
+ return dup;
+ }
+
+ /*
+ * call-seq:
+ * RepeatedField.inspect => string
+ *
+ * Returns a string representing this repeated field's elements. It will be
+ * formated as "[<element>, <element>, ...]", with each element's string
+ * representation computed by its own #inspect method.
+ */
+ @JRubyMethod
+ public IRubyObject inspect() {
+ StringBuilder str = new StringBuilder("[");
+ for (int i = 0; i < this.storage.size(); i++) {
+ str.append(storage.eltInternal(i).inspect());
+ str.append(", ");
+ }
+
+ if (str.length() > 1) {
+ str.replace(str.length() - 2, str.length(), "]");
+ } else {
+ str.append("]");
+ }
+
+ return getRuntime().newString(str.toString());
+ }
+
+ // Java API
+ protected IRubyObject get(int index) {
+ return this.storage.eltInternal(index);
+ }
+
+ protected RubyRepeatedField deepCopy(ThreadContext context) {
+ RubyRepeatedField copy = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
+ for (int i = 0; i < size(); i++) {
+ IRubyObject value = storage.eltInternal(i);
+ if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) {
+ copy.storage.add(((RubyMessage) value).deepCopy(context));
+ } else {
+ copy.storage.add(value);
+ }
+ }
+ return copy;
+ }
+
+ protected int size() {
+ return this.storage.size();
+ }
+
+ private IRubyObject defaultValue(ThreadContext context) {
+ SentinelOuterClass.Sentinel sentinel = SentinelOuterClass.Sentinel.getDefaultInstance();
+ Object value;
+ switch (fieldType) {
+ case INT32:
+ value = sentinel.getDefaultInt32();
+ break;
+ case INT64:
+ value = sentinel.getDefaultInt64();
+ break;
+ case UINT32:
+ value = sentinel.getDefaultUnit32();
+ break;
+ case UINT64:
+ value = sentinel.getDefaultUint64();
+ break;
+ case FLOAT:
+ value = sentinel.getDefaultFloat();
+ break;
+ case DOUBLE:
+ value = sentinel.getDefaultDouble();
+ break;
+ case BOOL:
+ value = sentinel.getDefaultBool();
+ break;
+ case BYTES:
+ value = sentinel.getDefaultBytes();
+ break;
+ case STRING:
+ value = sentinel.getDefaultString();
+ break;
+ default:
+ return context.runtime.getNil();
+ }
+ return Utils.wrapPrimaryValue(context, fieldType, value);
+ }
+
+ private void checkArrayElementType(ThreadContext context, RubyArray arr) {
+ for (int i = 0; i < arr.getLength(); i++) {
+ Utils.checkType(context, fieldType, arr.eltInternal(i), (RubyModule) typeClass);
+ }
+ }
+
+ private RubyArray storage;
+ private Descriptors.FieldDescriptor.Type fieldType;
+ private IRubyObject typeClass;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java b/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java
new file mode 100644
index 00000000..54f2c729
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java
@@ -0,0 +1,776 @@
+/*
+ * 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.
+ */
+
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: sentinel.proto
+
+package com.google.protobuf.jruby;
+
+public final class SentinelOuterClass {
+ private SentinelOuterClass() {}
+ public static void registerAllExtensions(
+ com.google.protobuf.ExtensionRegistry registry) {
+ }
+ public interface SentinelOrBuilder extends
+ // @@protoc_insertion_point(interface_extends:com.google.protobuf.jruby.Sentinel)
+ com.google.protobuf.MessageOrBuilder {
+
+ /**
+ * <code>optional int32 default_int32 = 1;</code>
+ */
+ int getDefaultInt32();
+
+ /**
+ * <code>optional int64 default_int64 = 2;</code>
+ */
+ long getDefaultInt64();
+
+ /**
+ * <code>optional uint32 default_unit32 = 3;</code>
+ */
+ int getDefaultUnit32();
+
+ /**
+ * <code>optional uint64 default_uint64 = 4;</code>
+ */
+ long getDefaultUint64();
+
+ /**
+ * <code>optional string default_string = 5;</code>
+ */
+ java.lang.String getDefaultString();
+ /**
+ * <code>optional string default_string = 5;</code>
+ */
+ com.google.protobuf.ByteString
+ getDefaultStringBytes();
+
+ /**
+ * <code>optional bool default_bool = 6;</code>
+ */
+ boolean getDefaultBool();
+
+ /**
+ * <code>optional float default_float = 7;</code>
+ */
+ float getDefaultFloat();
+
+ /**
+ * <code>optional double default_double = 8;</code>
+ */
+ double getDefaultDouble();
+
+ /**
+ * <code>optional bytes default_bytes = 9;</code>
+ */
+ com.google.protobuf.ByteString getDefaultBytes();
+ }
+ /**
+ * Protobuf type {@code com.google.protobuf.jruby.Sentinel}
+ */
+ public static final class Sentinel extends
+ com.google.protobuf.GeneratedMessage implements
+ // @@protoc_insertion_point(message_implements:com.google.protobuf.jruby.Sentinel)
+ SentinelOrBuilder {
+ // Use Sentinel.newBuilder() to construct.
+ private Sentinel(com.google.protobuf.GeneratedMessage.Builder builder) {
+ super(builder);
+ }
+ private Sentinel() {
+ defaultInt32_ = 0;
+ defaultInt64_ = 0L;
+ defaultUnit32_ = 0;
+ defaultUint64_ = 0L;
+ defaultString_ = "";
+ defaultBool_ = false;
+ defaultFloat_ = 0F;
+ defaultDouble_ = 0D;
+ defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
+ }
+
+ @java.lang.Override
+ public final com.google.protobuf.UnknownFieldSet
+ getUnknownFields() {
+ return com.google.protobuf.UnknownFieldSet.getDefaultInstance();
+ }
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
+ }
+
+ public static final com.google.protobuf.Parser<Sentinel> PARSER =
+ new com.google.protobuf.AbstractParser<Sentinel>() {
+ public Sentinel parsePartialFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ Builder builder = newBuilder();
+ try {
+ builder.mergeFrom(input, extensionRegistry);
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(builder.buildPartial());
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(
+ e.getMessage()).setUnfinishedMessage(builder.buildPartial());
+ }
+ return builder.buildPartial();
+ }
+ };
+
+ @java.lang.Override
+ public com.google.protobuf.Parser<Sentinel> getParserForType() {
+ return PARSER;
+ }
+
+ public static final int DEFAULT_INT32_FIELD_NUMBER = 1;
+ private int defaultInt32_;
+ /**
+ * <code>optional int32 default_int32 = 1;</code>
+ */
+ public int getDefaultInt32() {
+ return defaultInt32_;
+ }
+
+ public static final int DEFAULT_INT64_FIELD_NUMBER = 2;
+ private long defaultInt64_;
+ /**
+ * <code>optional int64 default_int64 = 2;</code>
+ */
+ public long getDefaultInt64() {
+ return defaultInt64_;
+ }
+
+ public static final int DEFAULT_UNIT32_FIELD_NUMBER = 3;
+ private int defaultUnit32_;
+ /**
+ * <code>optional uint32 default_unit32 = 3;</code>
+ */
+ public int getDefaultUnit32() {
+ return defaultUnit32_;
+ }
+
+ public static final int DEFAULT_UINT64_FIELD_NUMBER = 4;
+ private long defaultUint64_;
+ /**
+ * <code>optional uint64 default_uint64 = 4;</code>
+ */
+ public long getDefaultUint64() {
+ return defaultUint64_;
+ }
+
+ public static final int DEFAULT_STRING_FIELD_NUMBER = 5;
+ private java.lang.Object defaultString_;
+ /**
+ * <code>optional string default_string = 5;</code>
+ */
+ public java.lang.String getDefaultString() {
+ java.lang.Object ref = defaultString_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ defaultString_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ * <code>optional string default_string = 5;</code>
+ */
+ public com.google.protobuf.ByteString
+ getDefaultStringBytes() {
+ java.lang.Object ref = defaultString_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ defaultString_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
+ public static final int DEFAULT_BOOL_FIELD_NUMBER = 6;
+ private boolean defaultBool_;
+ /**
+ * <code>optional bool default_bool = 6;</code>
+ */
+ public boolean getDefaultBool() {
+ return defaultBool_;
+ }
+
+ public static final int DEFAULT_FLOAT_FIELD_NUMBER = 7;
+ private float defaultFloat_;
+ /**
+ * <code>optional float default_float = 7;</code>
+ */
+ public float getDefaultFloat() {
+ return defaultFloat_;
+ }
+
+ public static final int DEFAULT_DOUBLE_FIELD_NUMBER = 8;
+ private double defaultDouble_;
+ /**
+ * <code>optional double default_double = 8;</code>
+ */
+ public double getDefaultDouble() {
+ return defaultDouble_;
+ }
+
+ public static final int DEFAULT_BYTES_FIELD_NUMBER = 9;
+ private com.google.protobuf.ByteString defaultBytes_;
+ /**
+ * <code>optional bytes default_bytes = 9;</code>
+ */
+ public com.google.protobuf.ByteString getDefaultBytes() {
+ return defaultBytes_;
+ }
+
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input);
+ }
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input, extensionRegistry);
+ }
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+
+ public static Builder newBuilder() { return new Builder(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(com.google.protobuf.jruby.SentinelOuterClass.Sentinel prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ /**
+ * Protobuf type {@code com.google.protobuf.jruby.Sentinel}
+ */
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+ // @@protoc_insertion_point(builder_implements:com.google.protobuf.jruby.Sentinel)
+ com.google.protobuf.jruby.SentinelOuterClass.SentinelOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
+ }
+
+ // Construct using com.google.protobuf.jruby.SentinelOuterClass.Sentinel.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ public Builder clear() {
+ super.clear();
+ defaultInt32_ = 0;
+
+ defaultInt64_ = 0L;
+
+ defaultUnit32_ = 0;
+
+ defaultUint64_ = 0L;
+
+ defaultString_ = "";
+
+ defaultBool_ = false;
+
+ defaultFloat_ = 0F;
+
+ defaultDouble_ = 0D;
+
+ defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
+
+ return this;
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
+ }
+
+ public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() {
+ return com.google.protobuf.jruby.SentinelOuterClass.Sentinel.getDefaultInstance();
+ }
+
+ public com.google.protobuf.jruby.SentinelOuterClass.Sentinel build() {
+ com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ public com.google.protobuf.jruby.SentinelOuterClass.Sentinel buildPartial() {
+ com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(this);
+ result.defaultInt32_ = defaultInt32_;
+ result.defaultInt64_ = defaultInt64_;
+ result.defaultUnit32_ = defaultUnit32_;
+ result.defaultUint64_ = defaultUint64_;
+ result.defaultString_ = defaultString_;
+ result.defaultBool_ = defaultBool_;
+ result.defaultFloat_ = defaultFloat_;
+ result.defaultDouble_ = defaultDouble_;
+ result.defaultBytes_ = defaultBytes_;
+ onBuilt();
+ return result;
+ }
+
+
+ private int defaultInt32_ ;
+ /**
+ * <code>optional int32 default_int32 = 1;</code>
+ */
+ public int getDefaultInt32() {
+ return defaultInt32_;
+ }
+ /**
+ * <code>optional int32 default_int32 = 1;</code>
+ */
+ public Builder setDefaultInt32(int value) {
+
+ defaultInt32_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional int32 default_int32 = 1;</code>
+ */
+ public Builder clearDefaultInt32() {
+
+ defaultInt32_ = 0;
+ onChanged();
+ return this;
+ }
+
+ private long defaultInt64_ ;
+ /**
+ * <code>optional int64 default_int64 = 2;</code>
+ */
+ public long getDefaultInt64() {
+ return defaultInt64_;
+ }
+ /**
+ * <code>optional int64 default_int64 = 2;</code>
+ */
+ public Builder setDefaultInt64(long value) {
+
+ defaultInt64_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional int64 default_int64 = 2;</code>
+ */
+ public Builder clearDefaultInt64() {
+
+ defaultInt64_ = 0L;
+ onChanged();
+ return this;
+ }
+
+ private int defaultUnit32_ ;
+ /**
+ * <code>optional uint32 default_unit32 = 3;</code>
+ */
+ public int getDefaultUnit32() {
+ return defaultUnit32_;
+ }
+ /**
+ * <code>optional uint32 default_unit32 = 3;</code>
+ */
+ public Builder setDefaultUnit32(int value) {
+
+ defaultUnit32_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional uint32 default_unit32 = 3;</code>
+ */
+ public Builder clearDefaultUnit32() {
+
+ defaultUnit32_ = 0;
+ onChanged();
+ return this;
+ }
+
+ private long defaultUint64_ ;
+ /**
+ * <code>optional uint64 default_uint64 = 4;</code>
+ */
+ public long getDefaultUint64() {
+ return defaultUint64_;
+ }
+ /**
+ * <code>optional uint64 default_uint64 = 4;</code>
+ */
+ public Builder setDefaultUint64(long value) {
+
+ defaultUint64_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional uint64 default_uint64 = 4;</code>
+ */
+ public Builder clearDefaultUint64() {
+
+ defaultUint64_ = 0L;
+ onChanged();
+ return this;
+ }
+
+ private java.lang.Object defaultString_ = "";
+ /**
+ * <code>optional string default_string = 5;</code>
+ */
+ public java.lang.String getDefaultString() {
+ java.lang.Object ref = defaultString_;
+ if (!(ref instanceof java.lang.String)) {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ defaultString_ = s;
+ }
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ * <code>optional string default_string = 5;</code>
+ */
+ public com.google.protobuf.ByteString
+ getDefaultStringBytes() {
+ java.lang.Object ref = defaultString_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ defaultString_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ * <code>optional string default_string = 5;</code>
+ */
+ public Builder setDefaultString(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+
+ defaultString_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional string default_string = 5;</code>
+ */
+ public Builder clearDefaultString() {
+
+ defaultString_ = getDefaultInstance().getDefaultString();
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional string default_string = 5;</code>
+ */
+ public Builder setDefaultStringBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+
+ defaultString_ = value;
+ onChanged();
+ return this;
+ }
+
+ private boolean defaultBool_ ;
+ /**
+ * <code>optional bool default_bool = 6;</code>
+ */
+ public boolean getDefaultBool() {
+ return defaultBool_;
+ }
+ /**
+ * <code>optional bool default_bool = 6;</code>
+ */
+ public Builder setDefaultBool(boolean value) {
+
+ defaultBool_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional bool default_bool = 6;</code>
+ */
+ public Builder clearDefaultBool() {
+
+ defaultBool_ = false;
+ onChanged();
+ return this;
+ }
+
+ private float defaultFloat_ ;
+ /**
+ * <code>optional float default_float = 7;</code>
+ */
+ public float getDefaultFloat() {
+ return defaultFloat_;
+ }
+ /**
+ * <code>optional float default_float = 7;</code>
+ */
+ public Builder setDefaultFloat(float value) {
+
+ defaultFloat_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional float default_float = 7;</code>
+ */
+ public Builder clearDefaultFloat() {
+
+ defaultFloat_ = 0F;
+ onChanged();
+ return this;
+ }
+
+ private double defaultDouble_ ;
+ /**
+ * <code>optional double default_double = 8;</code>
+ */
+ public double getDefaultDouble() {
+ return defaultDouble_;
+ }
+ /**
+ * <code>optional double default_double = 8;</code>
+ */
+ public Builder setDefaultDouble(double value) {
+
+ defaultDouble_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional double default_double = 8;</code>
+ */
+ public Builder clearDefaultDouble() {
+
+ defaultDouble_ = 0D;
+ onChanged();
+ return this;
+ }
+
+ private com.google.protobuf.ByteString defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
+ /**
+ * <code>optional bytes default_bytes = 9;</code>
+ */
+ public com.google.protobuf.ByteString getDefaultBytes() {
+ return defaultBytes_;
+ }
+ /**
+ * <code>optional bytes default_bytes = 9;</code>
+ */
+ public Builder setDefaultBytes(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+
+ defaultBytes_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional bytes default_bytes = 9;</code>
+ */
+ public Builder clearDefaultBytes() {
+
+ defaultBytes_ = getDefaultInstance().getDefaultBytes();
+ onChanged();
+ return this;
+ }
+ public final Builder setUnknownFields(
+ final com.google.protobuf.UnknownFieldSet unknownFields) {
+ return this;
+ }
+
+ public final Builder mergeUnknownFields(
+ final com.google.protobuf.UnknownFieldSet unknownFields) {
+ return this;
+ }
+
+
+ // @@protoc_insertion_point(builder_scope:com.google.protobuf.jruby.Sentinel)
+ }
+
+ // @@protoc_insertion_point(class_scope:com.google.protobuf.jruby.Sentinel)
+ private static final com.google.protobuf.jruby.SentinelOuterClass.Sentinel defaultInstance;static {
+ defaultInstance = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel();
+ }
+
+ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ }
+
+ private static final com.google.protobuf.Descriptors.Descriptor
+ internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable;
+
+ public static com.google.protobuf.Descriptors.FileDescriptor
+ getDescriptor() {
+ return descriptor;
+ }
+ private static com.google.protobuf.Descriptors.FileDescriptor
+ descriptor;
+ static {
+ java.lang.String[] descriptorData = {
+ "\n\016sentinel.proto\022\031com.google.protobuf.jr" +
+ "uby\"\334\001\n\010Sentinel\022\025\n\rdefault_int32\030\001 \001(\005\022" +
+ "\025\n\rdefault_int64\030\002 \001(\003\022\026\n\016default_unit32" +
+ "\030\003 \001(\r\022\026\n\016default_uint64\030\004 \001(\004\022\026\n\016defaul" +
+ "t_string\030\005 \001(\t\022\024\n\014default_bool\030\006 \001(\010\022\025\n\r" +
+ "default_float\030\007 \001(\002\022\026\n\016default_double\030\010 " +
+ "\001(\001\022\025\n\rdefault_bytes\030\t \001(\014B\002H\002b\006proto3"
+ };
+ com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+ new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
+ public com.google.protobuf.ExtensionRegistry assignDescriptors(
+ com.google.protobuf.Descriptors.FileDescriptor root) {
+ descriptor = root;
+ return null;
+ }
+ };
+ com.google.protobuf.Descriptors.FileDescriptor
+ .internalBuildGeneratedFileFrom(descriptorData,
+ new com.google.protobuf.Descriptors.FileDescriptor[] {
+ }, assigner);
+ internal_static_com_google_protobuf_jruby_Sentinel_descriptor =
+ getDescriptor().getMessageTypes().get(0);
+ internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_com_google_protobuf_jruby_Sentinel_descriptor,
+ new java.lang.String[] { "DefaultInt32", "DefaultInt64", "DefaultUnit32", "DefaultUint64", "DefaultString", "DefaultBool", "DefaultFloat", "DefaultDouble", "DefaultBytes", });
+ }
+
+ // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/Utils.java b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java
new file mode 100644
index 00000000..596a0979
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java
@@ -0,0 +1,300 @@
+/*
+ * 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jcodings.Encoding;
+import org.jcodings.specific.ASCIIEncoding;
+import org.jcodings.specific.USASCIIEncoding;
+import org.jcodings.specific.UTF8Encoding;
+import org.jruby.*;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.math.BigInteger;
+
+public class Utils {
+ public static Descriptors.FieldDescriptor.Type rubyToFieldType(IRubyObject typeClass) {
+ return Descriptors.FieldDescriptor.Type.valueOf(typeClass.asJavaString().toUpperCase());
+ }
+
+ public static IRubyObject fieldTypeToRuby(ThreadContext context, Descriptors.FieldDescriptor.Type type) {
+ return fieldTypeToRuby(context, type.name());
+ }
+
+ public static IRubyObject fieldTypeToRuby(ThreadContext context, DescriptorProtos.FieldDescriptorProto.Type type) {
+ return fieldTypeToRuby(context, type.name());
+ }
+
+ private static IRubyObject fieldTypeToRuby(ThreadContext context, String typeName) {
+
+ return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase());
+ }
+
+ public static void checkType(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType,
+ IRubyObject value, RubyModule typeClass) {
+ Ruby runtime = context.runtime;
+ Object val;
+ switch(fieldType) {
+ case INT32:
+ case INT64:
+ case UINT32:
+ case UINT64:
+ if (!isRubyNum(value)) {
+ throw runtime.newTypeError("Expected number type for integral field.");
+ }
+ switch(fieldType) {
+ case INT32:
+ RubyNumeric.num2int(value);
+ break;
+ case INT64:
+ RubyNumeric.num2long(value);
+ break;
+ case UINT32:
+ num2uint(value);
+ break;
+ default:
+ num2ulong(context.runtime, value);
+ break;
+ }
+ checkIntTypePrecision(context, fieldType, value);
+ break;
+ case FLOAT:
+ if (!isRubyNum(value))
+ throw runtime.newTypeError("Expected number type for float field.");
+ break;
+ case DOUBLE:
+ if (!isRubyNum(value))
+ throw runtime.newTypeError("Expected number type for double field.");
+ break;
+ case BOOL:
+ if (!(value instanceof RubyBoolean))
+ throw runtime.newTypeError("Invalid argument for boolean field.");
+ break;
+ case BYTES:
+ case STRING:
+ validateStringEncoding(context.runtime, fieldType, value);
+ break;
+ case MESSAGE:
+ if (value.getMetaClass() != typeClass) {
+ throw runtime.newTypeError(value, typeClass);
+ }
+ break;
+ case ENUM:
+ if (value instanceof RubySymbol) {
+ Descriptors.EnumDescriptor enumDescriptor =
+ ((RubyEnumDescriptor) typeClass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR)).getDescriptor();
+ val = enumDescriptor.findValueByName(value.asJavaString());
+ if (val == null)
+ throw runtime.newRangeError("Enum value " + value + " is not found.");
+ } else if(!isRubyNum(value)) {
+ throw runtime.newTypeError("Expected number or symbol type for enum field.");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ public static IRubyObject wrapPrimaryValue(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType, Object value) {
+ Ruby runtime = context.runtime;
+ switch (fieldType) {
+ case INT32:
+ return runtime.newFixnum((Integer) value);
+ case INT64:
+ return runtime.newFixnum((Long) value);
+ case UINT32:
+ return runtime.newFixnum(((Integer) value) & (-1l >>> 32));
+ case UINT64:
+ long ret = (Long) value;
+ return ret >= 0 ? runtime.newFixnum(ret) :
+ RubyBignum.newBignum(runtime, UINT64_COMPLEMENTARY.add(new BigInteger(ret + "")));
+ case FLOAT:
+ return runtime.newFloat((Float) value);
+ case DOUBLE:
+ return runtime.newFloat((Double) value);
+ case BOOL:
+ return (Boolean) value ? runtime.getTrue() : runtime.getFalse();
+ case BYTES:
+ return runtime.newString(((ByteString) value).toStringUtf8());
+ case STRING:
+ return runtime.newString(value.toString());
+ default:
+ return runtime.getNil();
+ }
+ }
+
+ public static int num2uint(IRubyObject value) {
+ long longVal = RubyNumeric.num2long(value);
+ if (longVal > UINT_MAX)
+ throw value.getRuntime().newRangeError("Integer " + longVal + " too big to convert to 'unsigned int'");
+ long num = longVal;
+ if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE)
+ // encode to UINT32
+ num = (-longVal ^ (-1l >>> 32) ) + 1;
+ RubyNumeric.checkInt(value, num);
+ return (int) num;
+ }
+
+ public static long num2ulong(Ruby runtime, IRubyObject value) {
+ if (value instanceof RubyFloat) {
+ RubyBignum bignum = RubyBignum.newBignum(runtime, ((RubyFloat) value).getDoubleValue());
+ return RubyBignum.big2ulong(bignum);
+ } else if (value instanceof RubyBignum) {
+ return RubyBignum.big2ulong((RubyBignum) value);
+ } else {
+ return RubyNumeric.num2long(value);
+ }
+ }
+
+ public static void validateStringEncoding(Ruby runtime, Descriptors.FieldDescriptor.Type type, IRubyObject value) {
+ if (!(value instanceof RubyString))
+ throw runtime.newTypeError("Invalid argument for string field.");
+ Encoding encoding = ((RubyString) value).getEncoding();
+ switch(type) {
+ case BYTES:
+ if (encoding != ASCIIEncoding.INSTANCE)
+ throw runtime.newTypeError("Encoding for bytes fields" +
+ " must be \"ASCII-8BIT\", but was " + encoding);
+ break;
+ case STRING:
+ if (encoding != UTF8Encoding.INSTANCE
+ && encoding != USASCIIEncoding.INSTANCE)
+ throw runtime.newTypeError("Encoding for string fields" +
+ " must be \"UTF-8\" or \"ASCII\", but was " + encoding);
+ break;
+ default:
+ break;
+ }
+ }
+
+ public static void checkNameAvailability(ThreadContext context, String name) {
+ if (context.runtime.getObject().getConstantAt(name) != null)
+ throw context.runtime.newNameError(name + " is already defined", name);
+ }
+
+ /**
+ * Replace invalid "." in descriptor with __DOT__
+ * @param name
+ * @return
+ */
+ public static String escapeIdentifier(String name) {
+ return name.replace(".", BADNAME_REPLACEMENT);
+ }
+
+ /**
+ * Replace __DOT__ in descriptor name with "."
+ * @param name
+ * @return
+ */
+ public static String unescapeIdentifier(String name) {
+ return name.replace(BADNAME_REPLACEMENT, ".");
+ }
+
+ public static boolean isMapEntry(Descriptors.FieldDescriptor fieldDescriptor) {
+ return fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
+ fieldDescriptor.isRepeated() &&
+ fieldDescriptor.getMessageType().getOptions().getMapEntry();
+ }
+
+ public static RubyFieldDescriptor msgdefCreateField(ThreadContext context, String label, IRubyObject name,
+ IRubyObject type, IRubyObject number, IRubyObject typeClass, RubyClass cFieldDescriptor) {
+ Ruby runtime = context.runtime;
+ RubyFieldDescriptor fieldDef = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK);
+ fieldDef.setLabel(context, runtime.newString(label));
+ fieldDef.setName(context, name);
+ fieldDef.setType(context, type);
+ fieldDef.setNumber(context, number);
+
+ if (!typeClass.isNil()) {
+ if (!(typeClass instanceof RubyString)) {
+ throw runtime.newArgumentError("expected string for type class");
+ }
+ fieldDef.setSubmsgName(context, typeClass);
+ }
+ return fieldDef;
+ }
+
+ protected static void checkIntTypePrecision(ThreadContext context, Descriptors.FieldDescriptor.Type type, IRubyObject value) {
+ if (value instanceof RubyFloat) {
+ double doubleVal = RubyNumeric.num2dbl(value);
+ if (Math.floor(doubleVal) != doubleVal) {
+ throw context.runtime.newRangeError("Non-integral floating point value assigned to integer field.");
+ }
+ }
+ if (type == Descriptors.FieldDescriptor.Type.UINT32 || type == Descriptors.FieldDescriptor.Type.UINT64) {
+ if (RubyNumeric.num2dbl(value) < 0) {
+ throw context.runtime.newRangeError("Assigning negative value to unsigned integer field.");
+ }
+ }
+ }
+
+ protected static boolean isRubyNum(Object value) {
+ return value instanceof RubyFixnum || value instanceof RubyFloat || value instanceof RubyBignum;
+ }
+
+ protected static void validateTypeClass(ThreadContext context, Descriptors.FieldDescriptor.Type type, IRubyObject value) {
+ Ruby runtime = context.runtime;
+ if (!(value instanceof RubyModule)) {
+ throw runtime.newArgumentError("TypeClass has incorrect type");
+ }
+ RubyModule klass = (RubyModule) value;
+ IRubyObject descriptor = klass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR);
+ if (descriptor.isNil()) {
+ throw runtime.newArgumentError("Type class has no descriptor. Please pass a " +
+ "class or enum as returned by the DescriptorPool.");
+ }
+ if (type == Descriptors.FieldDescriptor.Type.MESSAGE) {
+ if (! (descriptor instanceof RubyDescriptor)) {
+ throw runtime.newArgumentError("Descriptor has an incorrect type");
+ }
+ } else if (type == Descriptors.FieldDescriptor.Type.ENUM) {
+ if (! (descriptor instanceof RubyEnumDescriptor)) {
+ throw runtime.newArgumentError("Descriptor has an incorrect type");
+ }
+ }
+ }
+
+ public static String BADNAME_REPLACEMENT = "__DOT__";
+
+ public static String DESCRIPTOR_INSTANCE_VAR = "@descriptor";
+
+ public static String EQUAL_SIGN = "=";
+
+ private static BigInteger UINT64_COMPLEMENTARY = new BigInteger("18446744073709551616"); //Math.pow(2, 64)
+
+ private static long UINT_MAX = 0xffffffffl;
+}
diff --git a/ruby/src/main/java/google/ProtobufJavaService.java b/ruby/src/main/java/google/ProtobufJavaService.java
new file mode 100644
index 00000000..bffb492a
--- /dev/null
+++ b/ruby/src/main/java/google/ProtobufJavaService.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package google;
+
+import com.google.protobuf.jruby.*;
+import org.jruby.Ruby;
+import org.jruby.runtime.load.BasicLibraryService;
+
+import java.io.IOException;
+
+public class ProtobufJavaService implements BasicLibraryService {
+ @Override
+ public boolean basicLoad(Ruby ruby) throws IOException {
+ ruby.defineModule("Google");
+ RubyProtobuf.createProtobuf(ruby);
+ RubyDescriptor.createRubyDescriptor(ruby);
+ RubyBuilder.createRubyBuilder(ruby);
+ RubyFieldDescriptor.createRubyFileDescriptor(ruby);
+ RubyMessageBuilderContext.createRubyMessageBuilderContext(ruby);
+ RubyEnumDescriptor.createRubyEnumDescriptor(ruby);
+ RubyEnumBuilderContext.createRubyEnumBuilderContext(ruby);
+ RubyDescriptorPool.createRubyDescriptorPool(ruby);
+ RubyRepeatedField.createRubyRepeatedField(ruby);
+ RubyFieldDescriptor.createRubyFileDescriptor(ruby);
+ RubyMap.createRubyMap(ruby);
+ RubyOneofDescriptor.createRubyOneofDescriptor(ruby);
+ RubyOneofBuilderContext.createRubyOneofBuilderContext(ruby);
+ return true;
+ }
+}
diff --git a/ruby/src/main/sentinel.proto b/ruby/src/main/sentinel.proto
new file mode 100644
index 00000000..89a1ae19
--- /dev/null
+++ b/ruby/src/main/sentinel.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+package com.google.protobuf.jruby;
+option optimize_for = CODE_SIZE;
+
+message Sentinel {
+ optional int32 default_int32 = 1;
+ optional int64 default_int64 = 2;
+ optional uint32 default_unit32 = 3;
+ optional uint64 default_uint64 = 4;
+ optional string default_string = 5;
+ optional bool default_bool = 6;
+ optional float default_float = 7;
+ optional double default_double = 8;
+ optional bytes default_bytes = 9;
+}
diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb
new file mode 100644
index 00000000..9d0f0a98
--- /dev/null
+++ b/ruby/tests/basic.rb
@@ -0,0 +1,1006 @@
+#!/usr/bin/ruby
+
+require 'google/protobuf'
+require 'test/unit'
+
+# ------------- generated code --------------
+
+module BasicTest
+ pool = Google::Protobuf::DescriptorPool.new
+ pool.build do
+ add_message "TestMessage" do
+ optional :optional_int32, :int32, 1
+ optional :optional_int64, :int64, 2
+ optional :optional_uint32, :uint32, 3
+ optional :optional_uint64, :uint64, 4
+ optional :optional_bool, :bool, 5
+ optional :optional_float, :float, 6
+ optional :optional_double, :double, 7
+ optional :optional_string, :string, 8
+ optional :optional_bytes, :bytes, 9
+ optional :optional_msg, :message, 10, "TestMessage2"
+ optional :optional_enum, :enum, 11, "TestEnum"
+
+ repeated :repeated_int32, :int32, 12
+ repeated :repeated_int64, :int64, 13
+ repeated :repeated_uint32, :uint32, 14
+ repeated :repeated_uint64, :uint64, 15
+ repeated :repeated_bool, :bool, 16
+ repeated :repeated_float, :float, 17
+ repeated :repeated_double, :double, 18
+ repeated :repeated_string, :string, 19
+ repeated :repeated_bytes, :bytes, 20
+ repeated :repeated_msg, :message, 21, "TestMessage2"
+ repeated :repeated_enum, :enum, 22, "TestEnum"
+ end
+ add_message "TestMessage2" do
+ optional :foo, :int32, 1
+ end
+
+ add_message "Recursive1" do
+ optional :foo, :message, 1, "Recursive2"
+ end
+ add_message "Recursive2" do
+ optional :foo, :message, 1, "Recursive1"
+ end
+
+ add_enum "TestEnum" do
+ value :Default, 0
+ value :A, 1
+ value :B, 2
+ value :C, 3
+ end
+
+ add_message "BadFieldNames" do
+ optional :dup, :int32, 1
+ optional :class, :int32, 2
+ optional :"a.b", :int32, 3
+ end
+
+ add_message "MapMessage" do
+ map :map_string_int32, :string, :int32, 1
+ map :map_string_msg, :string, :message, 2, "TestMessage2"
+ end
+ add_message "MapMessageWireEquiv" do
+ repeated :map_string_int32, :message, 1, "MapMessageWireEquiv_entry1"
+ repeated :map_string_msg, :message, 2, "MapMessageWireEquiv_entry2"
+ end
+ add_message "MapMessageWireEquiv_entry1" do
+ optional :key, :string, 1
+ optional :value, :int32, 2
+ end
+ add_message "MapMessageWireEquiv_entry2" do
+ optional :key, :string, 1
+ optional :value, :message, 2, "TestMessage2"
+ end
+
+ add_message "OneofMessage" do
+ oneof :my_oneof do
+ optional :a, :string, 1
+ optional :b, :int32, 2
+ optional :c, :message, 3, "TestMessage2"
+ optional :d, :enum, 4, "TestEnum"
+ end
+ end
+ end
+
+ TestMessage = pool.lookup("TestMessage").msgclass
+ TestMessage2 = pool.lookup("TestMessage2").msgclass
+ Recursive1 = pool.lookup("Recursive1").msgclass
+ Recursive2 = pool.lookup("Recursive2").msgclass
+ TestEnum = pool.lookup("TestEnum").enummodule
+ BadFieldNames = pool.lookup("BadFieldNames").msgclass
+ MapMessage = pool.lookup("MapMessage").msgclass
+ MapMessageWireEquiv = pool.lookup("MapMessageWireEquiv").msgclass
+ MapMessageWireEquiv_entry1 =
+ pool.lookup("MapMessageWireEquiv_entry1").msgclass
+ MapMessageWireEquiv_entry2 =
+ pool.lookup("MapMessageWireEquiv_entry2").msgclass
+ OneofMessage = pool.lookup("OneofMessage").msgclass
+
+# ------------ test cases ---------------
+
+ class MessageContainerTest < Test::Unit::TestCase
+
+ def test_defaults
+ m = TestMessage.new
+ assert m.optional_int32 == 0
+ assert m.optional_int64 == 0
+ assert m.optional_uint32 == 0
+ assert m.optional_uint64 == 0
+ assert m.optional_bool == false
+ assert m.optional_float == 0.0
+ assert m.optional_double == 0.0
+ assert m.optional_string == ""
+ assert m.optional_bytes == ""
+ assert m.optional_msg == nil
+ assert m.optional_enum == :Default
+ end
+
+ def test_setters
+ m = TestMessage.new
+ m.optional_int32 = -42
+ assert m.optional_int32 == -42
+ m.optional_int64 = -0x1_0000_0000
+ assert m.optional_int64 == -0x1_0000_0000
+ m.optional_uint32 = 0x9000_0000
+ assert m.optional_uint32 == 0x9000_0000
+ m.optional_uint64 = 0x9000_0000_0000_0000
+ assert m.optional_uint64 == 0x9000_0000_0000_0000
+ m.optional_bool = true
+ assert m.optional_bool == true
+ m.optional_float = 0.5
+ assert m.optional_float == 0.5
+ m.optional_double = 0.5
+ m.optional_string = "hello"
+ assert m.optional_string == "hello"
+ m.optional_bytes = "world".encode!('ASCII-8BIT')
+ assert m.optional_bytes == "world"
+ m.optional_msg = TestMessage2.new(:foo => 42)
+ assert m.optional_msg == TestMessage2.new(:foo => 42)
+ end
+
+ def test_ctor_args
+ m = TestMessage.new(:optional_int32 => -42,
+ :optional_msg => TestMessage2.new,
+ :optional_enum => :C,
+ :repeated_string => ["hello", "there", "world"])
+ assert m.optional_int32 == -42
+ assert m.optional_msg.class == TestMessage2
+ assert m.repeated_string.length == 3
+ assert m.optional_enum == :C
+ assert m.repeated_string[0] == "hello"
+ assert m.repeated_string[1] == "there"
+ assert m.repeated_string[2] == "world"
+ end
+
+ def test_inspect
+ m = TestMessage.new(:optional_int32 => -42,
+ :optional_enum => :A,
+ :optional_msg => TestMessage2.new,
+ :repeated_string => ["hello", "there", "world"])
+ expected = '<BasicTest::TestMessage: optional_int32: -42, optional_int64: 0, optional_uint32: 0, optional_uint64: 0, optional_bool: false, optional_float: 0.0, optional_double: 0.0, optional_string: "", optional_bytes: "", optional_msg: <BasicTest::TestMessage2: foo: 0>, optional_enum: :A, repeated_int32: [], repeated_int64: [], repeated_uint32: [], repeated_uint64: [], repeated_bool: [], repeated_float: [], repeated_double: [], repeated_string: ["hello", "there", "world"], repeated_bytes: [], repeated_msg: [], repeated_enum: []>'
+ assert m.inspect == expected
+ end
+
+ def test_hash
+ m1 = TestMessage.new(:optional_int32 => 42)
+ m2 = TestMessage.new(:optional_int32 => 102)
+ assert m1.hash != 0
+ assert m2.hash != 0
+ # relying on the randomness here -- if hash function changes and we are
+ # unlucky enough to get a collision, then change the values above.
+ assert m1.hash != m2.hash
+ end
+
+ def test_type_errors
+ m = TestMessage.new
+ assert_raise TypeError do
+ m.optional_int32 = "hello"
+ end
+ assert_raise TypeError do
+ m.optional_string = 42
+ end
+ assert_raise TypeError do
+ m.optional_string = nil
+ end
+ assert_raise TypeError do
+ m.optional_bool = 42
+ end
+ assert_raise TypeError do
+ m.optional_msg = TestMessage.new # expects TestMessage2
+ end
+
+ assert_raise TypeError do
+ m.repeated_int32 = [] # needs RepeatedField
+ end
+
+ assert_raise TypeError do
+ m.repeated_int32.push "hello"
+ end
+
+ assert_raise TypeError do
+ m.repeated_msg.push TestMessage.new
+ end
+ end
+
+ def test_string_encoding
+ m = TestMessage.new
+
+ # Assigning a normal (ASCII or UTF8) string to a bytes field, or
+ # ASCII-8BIT to a string field, raises an error.
+ assert_raise TypeError do
+ m.optional_bytes = "Test string ASCII".encode!('ASCII')
+ end
+ assert_raise TypeError do
+ m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8')
+ end
+ assert_raise TypeError do
+ m.optional_string = ["FFFF"].pack('H*')
+ end
+
+ # "Ordinary" use case.
+ m.optional_bytes = ["FFFF"].pack('H*')
+ m.optional_string = "\u0100"
+
+ # strings are mutable so we can do this, but serialize should catch it.
+ m.optional_string = "asdf".encode!('UTF-8')
+ m.optional_string.encode!('ASCII-8BIT')
+ assert_raise TypeError do
+ data = TestMessage.encode(m)
+ end
+ end
+
+ def test_rptfield_int32
+ l = Google::Protobuf::RepeatedField.new(:int32)
+ assert l.count == 0
+ l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
+ assert l.count == 3
+ assert_equal [1, 2, 3], l
+ assert_equal l, [1, 2, 3]
+ l.push 4
+ assert l == [1, 2, 3, 4]
+ dst_list = []
+ l.each { |val| dst_list.push val }
+ assert dst_list == [1, 2, 3, 4]
+ assert l.to_a == [1, 2, 3, 4]
+ assert l[0] == 1
+ assert l[3] == 4
+ l[0] = 5
+ assert l == [5, 2, 3, 4]
+
+ l2 = l.dup
+ assert l == l2
+ assert l.object_id != l2.object_id
+ l2.push 6
+ assert l.count == 4
+ assert l2.count == 5
+
+ assert l.inspect == '[5, 2, 3, 4]'
+
+ l.insert(7, 8, 9)
+ assert l == [5, 2, 3, 4, 7, 8, 9]
+ assert l.pop == 9
+ assert l == [5, 2, 3, 4, 7, 8]
+
+ assert_raise TypeError do
+ m = TestMessage.new
+ l.push m
+ end
+
+ m = TestMessage.new
+ m.repeated_int32 = l
+ assert m.repeated_int32 == [5, 2, 3, 4, 7, 8]
+ assert m.repeated_int32.object_id == l.object_id
+ l.push 42
+ assert m.repeated_int32.pop == 42
+
+ l3 = l + l.dup
+ assert l3.count == l.count * 2
+ l.count.times do |i|
+ assert l3[i] == l[i]
+ assert l3[l.count + i] == l[i]
+ end
+
+ l.clear
+ assert l.count == 0
+ l += [1, 2, 3, 4]
+ l.replace([5, 6, 7, 8])
+ assert l == [5, 6, 7, 8]
+
+ l4 = Google::Protobuf::RepeatedField.new(:int32)
+ l4[5] = 42
+ assert l4 == [0, 0, 0, 0, 0, 42]
+
+ l4 << 100
+ assert l4 == [0, 0, 0, 0, 0, 42, 100]
+ l4 << 101 << 102
+ assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102]
+ end
+
+ def test_rptfield_msg
+ l = Google::Protobuf::RepeatedField.new(:message, TestMessage)
+ l.push TestMessage.new
+ assert l.count == 1
+ assert_raise TypeError do
+ l.push TestMessage2.new
+ end
+ assert_raise TypeError do
+ l.push 42
+ end
+
+ l2 = l.dup
+ assert l2[0] == l[0]
+ assert l2[0].object_id == l[0].object_id
+
+ l2 = Google::Protobuf.deep_copy(l)
+ assert l2[0] == l[0]
+ assert l2[0].object_id != l[0].object_id
+
+ l3 = l + l2
+ assert l3.count == 2
+ assert l3[0] == l[0]
+ assert l3[1] == l2[0]
+ l3[0].optional_int32 = 1000
+ assert l[0].optional_int32 == 1000
+
+ new_msg = TestMessage.new(:optional_int32 => 200)
+ l4 = l + [new_msg]
+ assert l4.count == 2
+ new_msg.optional_int32 = 1000
+ assert l4[1].optional_int32 == 1000
+ end
+
+ def test_rptfield_enum
+ l = Google::Protobuf::RepeatedField.new(:enum, TestEnum)
+ l.push :A
+ l.push :B
+ l.push :C
+ assert l.count == 3
+ assert_raise RangeError do
+ l.push :D
+ end
+ assert l[0] == :A
+
+ l.push 4
+ assert l[3] == 4
+ end
+
+ def test_rptfield_initialize
+ assert_raise ArgumentError do
+ l = Google::Protobuf::RepeatedField.new
+ end
+ assert_raise ArgumentError do
+ l = Google::Protobuf::RepeatedField.new(:message)
+ end
+ assert_raise ArgumentError do
+ l = Google::Protobuf::RepeatedField.new([1, 2, 3])
+ end
+ assert_raise ArgumentError do
+ l = Google::Protobuf::RepeatedField.new(:message, [TestMessage2.new])
+ end
+ end
+
+ def test_map_basic
+ # allowed key types:
+ # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes.
+
+ m = Google::Protobuf::Map.new(:string, :int32)
+ m["asdf"] = 1
+ assert m["asdf"] == 1
+ m["jkl;"] = 42
+ assert m == { "jkl;" => 42, "asdf" => 1 }
+ assert m.has_key?("asdf")
+ assert !m.has_key?("qwerty")
+ assert m.length == 2
+
+ m2 = m.dup
+ assert m == m2
+ assert m.hash != 0
+ assert m.hash == m2.hash
+
+ collected = {}
+ m.each { |k,v| collected[v] = k }
+ assert collected == { 42 => "jkl;", 1 => "asdf" }
+
+ assert m.delete("asdf") == 1
+ assert !m.has_key?("asdf")
+ assert m["asdf"] == nil
+ assert !m.has_key?("asdf")
+
+ # We only assert on inspect value when there is one map entry because the
+ # order in which elements appear is unspecified (depends on the internal
+ # hash function). We don't want a brittle test.
+ assert m.inspect == "{\"jkl;\"=>42}"
+
+ assert m.keys == ["jkl;"]
+ assert m.values == [42]
+
+ m.clear
+ assert m.length == 0
+ assert m == {}
+
+ assert_raise TypeError do
+ m[1] = 1
+ end
+ assert_raise RangeError do
+ m["asdf"] = 0x1_0000_0000
+ end
+ end
+
+ def test_map_ctor
+ m = Google::Protobuf::Map.new(:string, :int32,
+ {"a" => 1, "b" => 2, "c" => 3})
+ assert m == {"a" => 1, "c" => 3, "b" => 2}
+ end
+
+ def test_map_keytypes
+ m = Google::Protobuf::Map.new(:int32, :int32)
+ m[1] = 42
+ m[-1] = 42
+ assert_raise RangeError do
+ m[0x8000_0000] = 1
+ end
+ assert_raise TypeError do
+ m["asdf"] = 1
+ end
+
+ m = Google::Protobuf::Map.new(:int64, :int32)
+ m[0x1000_0000_0000_0000] = 1
+ assert_raise RangeError do
+ m[0x1_0000_0000_0000_0000] = 1
+ end
+ assert_raise TypeError do
+ m["asdf"] = 1
+ end
+
+ m = Google::Protobuf::Map.new(:uint32, :int32)
+ m[0x8000_0000] = 1
+ assert_raise RangeError do
+ m[0x1_0000_0000] = 1
+ end
+ assert_raise RangeError do
+ m[-1] = 1
+ end
+
+ m = Google::Protobuf::Map.new(:uint64, :int32)
+ m[0x8000_0000_0000_0000] = 1
+ assert_raise RangeError do
+ m[0x1_0000_0000_0000_0000] = 1
+ end
+ assert_raise RangeError do
+ m[-1] = 1
+ end
+
+ m = Google::Protobuf::Map.new(:bool, :int32)
+ m[true] = 1
+ m[false] = 2
+ assert_raise TypeError do
+ m[1] = 1
+ end
+ assert_raise TypeError do
+ m["asdf"] = 1
+ end
+
+ m = Google::Protobuf::Map.new(:string, :int32)
+ m["asdf"] = 1
+ assert_raise TypeError do
+ m[1] = 1
+ end
+ assert_raise TypeError do
+ bytestring = ["FFFF"].pack("H*")
+ m[bytestring] = 1
+ end
+
+ m = Google::Protobuf::Map.new(:bytes, :int32)
+ bytestring = ["FFFF"].pack("H*")
+ m[bytestring] = 1
+ assert_raise TypeError do
+ m["asdf"] = 1
+ end
+ assert_raise TypeError do
+ m[1] = 1
+ end
+ end
+
+ def test_map_msg_enum_valuetypes
+ m = Google::Protobuf::Map.new(:string, :message, TestMessage)
+ m["asdf"] = TestMessage.new
+ assert_raise TypeError do
+ m["jkl;"] = TestMessage2.new
+ end
+
+ m = Google::Protobuf::Map.new(
+ :string, :message, TestMessage,
+ { "a" => TestMessage.new(:optional_int32 => 42),
+ "b" => TestMessage.new(:optional_int32 => 84) })
+ assert m.length == 2
+ assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84]
+
+ m = Google::Protobuf::Map.new(:string, :enum, TestEnum,
+ { "x" => :A, "y" => :B, "z" => :C })
+ assert m.length == 3
+ assert m["z"] == :C
+ m["z"] = 2
+ assert m["z"] == :B
+ m["z"] = 4
+ assert m["z"] == 4
+ assert_raise RangeError do
+ m["z"] = :Z
+ end
+ assert_raise TypeError do
+ m["z"] = "z"
+ end
+ end
+
+ def test_map_dup_deep_copy
+ m = Google::Protobuf::Map.new(
+ :string, :message, TestMessage,
+ { "a" => TestMessage.new(:optional_int32 => 42),
+ "b" => TestMessage.new(:optional_int32 => 84) })
+
+ m2 = m.dup
+ assert m == m2
+ assert m.object_id != m2.object_id
+ assert m["a"].object_id == m2["a"].object_id
+ assert m["b"].object_id == m2["b"].object_id
+
+ m2 = Google::Protobuf.deep_copy(m)
+ assert m == m2
+ assert m.object_id != m2.object_id
+ assert m["a"].object_id != m2["a"].object_id
+ assert m["b"].object_id != m2["b"].object_id
+ end
+
+ def test_map_field
+ m = MapMessage.new
+ assert m.map_string_int32 == {}
+ assert m.map_string_msg == {}
+
+ m = MapMessage.new(
+ :map_string_int32 => {"a" => 1, "b" => 2},
+ :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
+ "b" => TestMessage2.new(:foo => 2)})
+ assert m.map_string_int32.keys.sort == ["a", "b"]
+ assert m.map_string_int32["a"] == 1
+ assert m.map_string_msg["b"].foo == 2
+
+ m.map_string_int32["c"] = 3
+ assert m.map_string_int32["c"] == 3
+ m.map_string_msg["c"] = TestMessage2.new(:foo => 3)
+ assert m.map_string_msg["c"] == TestMessage2.new(:foo => 3)
+ m.map_string_msg.delete("b")
+ m.map_string_msg.delete("c")
+ assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
+
+ assert_raise TypeError do
+ m.map_string_msg["e"] = TestMessage.new # wrong value type
+ end
+ # ensure nothing was added by the above
+ assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
+
+ m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
+ assert_raise TypeError do
+ m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
+ end
+ assert_raise TypeError do
+ m.map_string_int32 = {}
+ end
+
+ assert_raise TypeError do
+ m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
+ end
+ end
+
+ def test_map_encode_decode
+ m = MapMessage.new(
+ :map_string_int32 => {"a" => 1, "b" => 2},
+ :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
+ "b" => TestMessage2.new(:foo => 2)})
+ m2 = MapMessage.decode(MapMessage.encode(m))
+ assert m == m2
+
+ m3 = MapMessageWireEquiv.decode(MapMessage.encode(m))
+ assert m3.map_string_int32.length == 2
+
+ kv = {}
+ m3.map_string_int32.map { |msg| kv[msg.key] = msg.value }
+ assert kv == {"a" => 1, "b" => 2}
+
+ kv = {}
+ m3.map_string_msg.map { |msg| kv[msg.key] = msg.value }
+ assert kv == {"a" => TestMessage2.new(:foo => 1),
+ "b" => TestMessage2.new(:foo => 2)}
+ end
+
+ def test_oneof_descriptors
+ d = OneofMessage.descriptor
+ o = d.lookup_oneof("my_oneof")
+ assert o != nil
+ assert o.class == Google::Protobuf::OneofDescriptor
+ assert o.name == "my_oneof"
+ oneof_count = 0
+ d.each_oneof{ |oneof|
+ oneof_count += 1
+ assert oneof == o
+ }
+ assert oneof_count == 1
+ assert o.count == 4
+ field_names = o.map{|f| f.name}.sort
+ assert field_names == ["a", "b", "c", "d"]
+ end
+
+ def test_oneof
+ d = OneofMessage.new
+ assert d.a == nil
+ assert d.b == nil
+ assert d.c == nil
+ assert d.d == nil
+ assert d.my_oneof == nil
+
+ d.a = "hi"
+ assert d.a == "hi"
+ assert d.b == nil
+ assert d.c == nil
+ assert d.d == nil
+ assert d.my_oneof == :a
+
+ d.b = 42
+ assert d.a == nil
+ assert d.b == 42
+ assert d.c == nil
+ assert d.d == nil
+ assert d.my_oneof == :b
+
+ d.c = TestMessage2.new(:foo => 100)
+ assert d.a == nil
+ assert d.b == nil
+ assert d.c.foo == 100
+ assert d.d == nil
+ assert d.my_oneof == :c
+
+ d.d = :C
+ assert d.a == nil
+ assert d.b == nil
+ assert d.c == nil
+ assert d.d == :C
+ assert d.my_oneof == :d
+
+ d2 = OneofMessage.decode(OneofMessage.encode(d))
+ assert d2 == d
+
+ encoded_field_a = OneofMessage.encode(OneofMessage.new(:a => "string"))
+ encoded_field_b = OneofMessage.encode(OneofMessage.new(:b => 1000))
+ encoded_field_c = OneofMessage.encode(
+ OneofMessage.new(:c => TestMessage2.new(:foo => 1)))
+ encoded_field_d = OneofMessage.encode(OneofMessage.new(:d => :B))
+
+ d3 = OneofMessage.decode(
+ encoded_field_c + encoded_field_a + encoded_field_d)
+ assert d3.a == nil
+ assert d3.b == nil
+ assert d3.c == nil
+ assert d3.d == :B
+
+ d4 = OneofMessage.decode(
+ encoded_field_c + encoded_field_a + encoded_field_d +
+ encoded_field_c)
+ assert d4.a == nil
+ assert d4.b == nil
+ assert d4.c.foo == 1
+ assert d4.d == nil
+
+ d5 = OneofMessage.new(:a => "hello")
+ assert d5.a != nil
+ d5.a = nil
+ assert d5.a == nil
+ assert OneofMessage.encode(d5) == ''
+ assert d5.my_oneof == nil
+ end
+
+ def test_enum_field
+ m = TestMessage.new
+ assert m.optional_enum == :Default
+ m.optional_enum = :A
+ assert m.optional_enum == :A
+ assert_raise RangeError do
+ m.optional_enum = :ASDF
+ end
+ m.optional_enum = 1
+ assert m.optional_enum == :A
+ m.optional_enum = 100
+ assert m.optional_enum == 100
+ end
+
+ def test_dup
+ m = TestMessage.new
+ m.optional_string = "hello"
+ m.optional_int32 = 42
+ m.repeated_msg.push TestMessage2.new(:foo => 100)
+ m.repeated_msg.push TestMessage2.new(:foo => 200)
+
+ m2 = m.dup
+ assert m == m2
+ m.optional_int32 += 1
+ assert m != m2
+ assert m.repeated_msg[0] == m2.repeated_msg[0]
+ assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id
+ end
+
+ def test_deep_copy
+ m = TestMessage.new(:optional_int32 => 42,
+ :repeated_msg => [TestMessage2.new(:foo => 100)])
+ m2 = Google::Protobuf.deep_copy(m)
+ assert m == m2
+ assert m.repeated_msg == m2.repeated_msg
+ assert m.repeated_msg.object_id != m2.repeated_msg.object_id
+ assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id
+ end
+
+ def test_eq
+ m = TestMessage.new(:optional_int32 => 42,
+ :repeated_int32 => [1, 2, 3])
+ m2 = TestMessage.new(:optional_int32 => 43,
+ :repeated_int32 => [1, 2, 3])
+ assert m != m2
+ end
+
+ def test_enum_lookup
+ assert TestEnum::A == 1
+ assert TestEnum::B == 2
+ assert TestEnum::C == 3
+
+ assert TestEnum::lookup(1) == :A
+ assert TestEnum::lookup(2) == :B
+ assert TestEnum::lookup(3) == :C
+
+ assert TestEnum::resolve(:A) == 1
+ assert TestEnum::resolve(:B) == 2
+ assert TestEnum::resolve(:C) == 3
+ end
+
+ def test_parse_serialize
+ m = TestMessage.new(:optional_int32 => 42,
+ :optional_string => "hello world",
+ :optional_enum => :B,
+ :repeated_string => ["a", "b", "c"],
+ :repeated_int32 => [42, 43, 44],
+ :repeated_enum => [:A, :B, :C, 100],
+ :repeated_msg => [TestMessage2.new(:foo => 1),
+ TestMessage2.new(:foo => 2)])
+ data = TestMessage.encode m
+ m2 = TestMessage.decode data
+ assert m == m2
+
+ data = Google::Protobuf.encode m
+ m2 = Google::Protobuf.decode(TestMessage, data)
+ assert m == m2
+ end
+
+ def test_def_errors
+ s = Google::Protobuf::DescriptorPool.new
+ assert_raise TypeError do
+ s.build do
+ # enum with no default (integer value 0)
+ add_enum "MyEnum" do
+ value :A, 1
+ end
+ end
+ end
+ assert_raise TypeError do
+ s.build do
+ # message with required field (unsupported in proto3)
+ add_message "MyMessage" do
+ required :foo, :int32, 1
+ end
+ end
+ end
+ end
+
+ def test_corecursive
+ # just be sure that we can instantiate types with corecursive field-type
+ # references.
+ m = Recursive1.new(:foo => Recursive2.new(:foo => Recursive1.new))
+ assert Recursive1.descriptor.lookup("foo").subtype ==
+ Recursive2.descriptor
+ assert Recursive2.descriptor.lookup("foo").subtype ==
+ Recursive1.descriptor
+
+ serialized = Recursive1.encode(m)
+ m2 = Recursive1.decode(serialized)
+ assert m == m2
+ end
+
+ def test_serialize_cycle
+ m = Recursive1.new(:foo => Recursive2.new)
+ m.foo.foo = m
+ assert_raise RuntimeError do
+ serialized = Recursive1.encode(m)
+ end
+ end
+
+ def test_bad_field_names
+ m = BadFieldNames.new(:dup => 1, :class => 2)
+ m2 = m.dup
+ assert m == m2
+ assert m['dup'] == 1
+ assert m['class'] == 2
+ m['dup'] = 3
+ assert m['dup'] == 3
+ m['a.b'] = 4
+ assert m['a.b'] == 4
+ end
+
+
+ def test_int_ranges
+ m = TestMessage.new
+
+ m.optional_int32 = 0
+ m.optional_int32 = -0x8000_0000
+ m.optional_int32 = +0x7fff_ffff
+ m.optional_int32 = 1.0
+ m.optional_int32 = -1.0
+ m.optional_int32 = 2e9
+ assert_raise RangeError do
+ m.optional_int32 = -0x8000_0001
+ end
+ assert_raise RangeError do
+ m.optional_int32 = +0x8000_0000
+ end
+ assert_raise RangeError do
+ m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
+ end
+ assert_raise RangeError do
+ m.optional_int32 = 1e12
+ end
+ assert_raise RangeError do
+ m.optional_int32 = 1.5
+ end
+
+ m.optional_uint32 = 0
+ m.optional_uint32 = +0xffff_ffff
+ m.optional_uint32 = 1.0
+ m.optional_uint32 = 4e9
+ assert_raise RangeError do
+ m.optional_uint32 = -1
+ end
+ assert_raise RangeError do
+ m.optional_uint32 = -1.5
+ end
+ assert_raise RangeError do
+ m.optional_uint32 = -1.5e12
+ end
+ assert_raise RangeError do
+ m.optional_uint32 = -0x1000_0000_0000_0000
+ end
+ assert_raise RangeError do
+ m.optional_uint32 = +0x1_0000_0000
+ end
+ assert_raise RangeError do
+ m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
+ end
+ assert_raise RangeError do
+ m.optional_uint32 = 1e12
+ end
+ assert_raise RangeError do
+ m.optional_uint32 = 1.5
+ end
+
+ m.optional_int64 = 0
+ m.optional_int64 = -0x8000_0000_0000_0000
+ m.optional_int64 = +0x7fff_ffff_ffff_ffff
+ m.optional_int64 = 1.0
+ m.optional_int64 = -1.0
+ m.optional_int64 = 8e18
+ m.optional_int64 = -8e18
+ assert_raise RangeError do
+ m.optional_int64 = -0x8000_0000_0000_0001
+ end
+ assert_raise RangeError do
+ m.optional_int64 = +0x8000_0000_0000_0000
+ end
+ assert_raise RangeError do
+ m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
+ end
+ assert_raise RangeError do
+ m.optional_int64 = 1e50
+ end
+ assert_raise RangeError do
+ m.optional_int64 = 1.5
+ end
+
+ m.optional_uint64 = 0
+ m.optional_uint64 = +0xffff_ffff_ffff_ffff
+ m.optional_uint64 = 1.0
+ m.optional_uint64 = 16e18
+ assert_raise RangeError do
+ m.optional_uint64 = -1
+ end
+ assert_raise RangeError do
+ m.optional_uint64 = -1.5
+ end
+ assert_raise RangeError do
+ m.optional_uint64 = -1.5e12
+ end
+ assert_raise RangeError do
+ m.optional_uint64 = -0x1_0000_0000_0000_0000
+ end
+ assert_raise RangeError do
+ m.optional_uint64 = +0x1_0000_0000_0000_0000
+ end
+ assert_raise RangeError do
+ m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
+ end
+ assert_raise RangeError do
+ m.optional_uint64 = 1e50
+ end
+ assert_raise RangeError do
+ m.optional_uint64 = 1.5
+ end
+
+ end
+
+ def test_stress_test
+ m = TestMessage.new
+ m.optional_int32 = 42
+ m.optional_int64 = 0x100000000
+ m.optional_string = "hello world"
+ 10.times do m.repeated_msg.push TestMessage2.new(:foo => 42) end
+ 10.times do m.repeated_string.push "hello world" end
+
+ data = TestMessage.encode(m)
+
+ l = 0
+ 10_000.times do
+ m = TestMessage.decode(data)
+ data_new = TestMessage.encode(m)
+ assert data_new == data
+ data = data_new
+ end
+ end
+
+ def test_reflection
+ m = TestMessage.new(:optional_int32 => 1234)
+ msgdef = m.class.descriptor
+ assert msgdef.class == Google::Protobuf::Descriptor
+ assert msgdef.any? {|field| field.name == "optional_int32"}
+ optional_int32 = msgdef.lookup "optional_int32"
+ assert optional_int32.class == Google::Protobuf::FieldDescriptor
+ assert optional_int32 != nil
+ assert optional_int32.name == "optional_int32"
+ assert optional_int32.type == :int32
+ optional_int32.set(m, 5678)
+ assert m.optional_int32 == 5678
+ m.optional_int32 = 1000
+ assert optional_int32.get(m) == 1000
+
+ optional_msg = msgdef.lookup "optional_msg"
+ assert optional_msg.subtype == TestMessage2.descriptor
+
+ optional_msg.set(m, optional_msg.subtype.msgclass.new)
+
+ assert msgdef.msgclass == TestMessage
+
+ optional_enum = msgdef.lookup "optional_enum"
+ assert optional_enum.subtype == TestEnum.descriptor
+ assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor
+ optional_enum.subtype.each do |k, v|
+ # set with integer, check resolution to symbolic name
+ optional_enum.set(m, v)
+ assert optional_enum.get(m) == k
+ end
+ end
+
+ def test_json
+ skip("Unimplemented") if RUBY_PLATFORM == "java"
+ m = TestMessage.new(:optional_int32 => 1234,
+ :optional_int64 => -0x1_0000_0000,
+ :optional_uint32 => 0x8000_0000,
+ :optional_uint64 => 0xffff_ffff_ffff_ffff,
+ :optional_bool => true,
+ :optional_float => 1.0,
+ :optional_double => -1e100,
+ :optional_string => "Test string",
+ :optional_bytes => ["FFFFFFFF"].pack('H*'),
+ :optional_msg => TestMessage2.new(:foo => 42),
+ :repeated_int32 => [1, 2, 3, 4],
+ :repeated_string => ["a", "b", "c"],
+ :repeated_bool => [true, false, true, false],
+ :repeated_msg => [TestMessage2.new(:foo => 1),
+ TestMessage2.new(:foo => 2)])
+
+ json_text = TestMessage.encode_json(m)
+ m2 = TestMessage.decode_json(json_text)
+ assert m == m2
+ end
+
+ def test_json_maps
+ skip("Unimplemented") if RUBY_PLATFORM == "java"
+ m = MapMessage.new(:map_string_int32 => {"a" => 1})
+ expected = '{"map_string_int32":{"a":1},"map_string_msg":{}}'
+ assert MapMessage.encode_json(m) == expected
+ m2 = MapMessage.decode_json(MapMessage.encode_json(m))
+ assert m == m2
+ end
+ end
+end
diff --git a/ruby/tests/generated_code.proto b/ruby/tests/generated_code.proto
new file mode 100644
index 00000000..b1d63232
--- /dev/null
+++ b/ruby/tests/generated_code.proto
@@ -0,0 +1,67 @@
+syntax = "proto3";
+
+package A.B.C;
+
+message TestMessage {
+ optional int32 optional_int32 = 1;
+ optional int64 optional_int64 = 2;
+ optional uint32 optional_uint32 = 3;
+ optional uint64 optional_uint64 = 4;
+ optional bool optional_bool = 5;
+ optional double optional_double = 6;
+ optional float optional_float = 7;
+ optional string optional_string = 8;
+ optional bytes optional_bytes = 9;
+ optional TestEnum optional_enum = 10;
+ optional TestMessage optional_msg = 11;
+
+ repeated int32 repeated_int32 = 21;
+ repeated int64 repeated_int64 = 22;
+ repeated uint32 repeated_uint32 = 23;
+ repeated uint64 repeated_uint64 = 24;
+ repeated bool repeated_bool = 25;
+ repeated double repeated_double = 26;
+ repeated float repeated_float = 27;
+ repeated string repeated_string = 28;
+ repeated bytes repeated_bytes = 29;
+ repeated TestEnum repeated_enum = 30;
+ repeated TestMessage repeated_msg = 31;
+
+ oneof my_oneof {
+ int32 oneof_int32 = 41;
+ int64 oneof_int64 = 42;
+ uint32 oneof_uint32 = 43;
+ uint64 oneof_uint64 = 44;
+ bool oneof_bool = 45;
+ double oneof_double = 46;
+ float oneof_float = 47;
+ string oneof_string = 48;
+ bytes oneof_bytes = 49;
+ TestEnum oneof_enum = 50;
+ TestMessage oneof_msg = 51;
+ }
+
+ map<int32, string> map_int32_string = 61;
+ map<int64, string> map_int64_string = 62;
+ map<uint32, string> map_uint32_string = 63;
+ map<uint64, string> map_uint64_string = 64;
+ map<bool, string> map_bool_string = 65;
+ map<string, string> map_string_string = 66;
+ map<string, TestMessage> map_string_msg = 67;
+ map<string, TestEnum> map_string_enum = 68;
+ map<string, int32> map_string_int32 = 69;
+ map<string, bool> map_string_bool = 70;
+
+ message NestedMessage {
+ optional int32 foo = 1;
+ }
+
+ optional NestedMessage nested_message = 80;
+}
+
+enum TestEnum {
+ Default = 0;
+ A = 1;
+ B = 2;
+ C = 3;
+}
diff --git a/ruby/tests/generated_code.rb b/ruby/tests/generated_code.rb
new file mode 100644
index 00000000..5a685433
--- /dev/null
+++ b/ruby/tests/generated_code.rb
@@ -0,0 +1,74 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: generated_code.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "A.B.C.TestMessage" do
+ optional :optional_int32, :int32, 1
+ optional :optional_int64, :int64, 2
+ optional :optional_uint32, :uint32, 3
+ optional :optional_uint64, :uint64, 4
+ optional :optional_bool, :bool, 5
+ optional :optional_double, :double, 6
+ optional :optional_float, :float, 7
+ optional :optional_string, :string, 8
+ optional :optional_bytes, :string, 9
+ optional :optional_enum, :enum, 10, "A.B.C.TestEnum"
+ optional :optional_msg, :message, 11, "A.B.C.TestMessage"
+ repeated :repeated_int32, :int32, 21
+ repeated :repeated_int64, :int64, 22
+ repeated :repeated_uint32, :uint32, 23
+ repeated :repeated_uint64, :uint64, 24
+ repeated :repeated_bool, :bool, 25
+ repeated :repeated_double, :double, 26
+ repeated :repeated_float, :float, 27
+ repeated :repeated_string, :string, 28
+ repeated :repeated_bytes, :string, 29
+ repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum"
+ repeated :repeated_msg, :message, 31, "A.B.C.TestMessage"
+ map :map_int32_string, :int32, :string, 61
+ map :map_int64_string, :int64, :string, 62
+ map :map_uint32_string, :uint32, :string, 63
+ map :map_uint64_string, :uint64, :string, 64
+ map :map_bool_string, :bool, :string, 65
+ map :map_string_string, :string, :string, 66
+ map :map_string_msg, :string, :message, 67, "A.B.C.TestMessage"
+ map :map_string_enum, :string, :enum, 68, "A.B.C.TestEnum"
+ map :map_string_int32, :string, :int32, 69
+ map :map_string_bool, :string, :bool, 70
+ optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage"
+ oneof :my_oneof do
+ optional :oneof_int32, :int32, 41
+ optional :oneof_int64, :int64, 42
+ optional :oneof_uint32, :uint32, 43
+ optional :oneof_uint64, :uint64, 44
+ optional :oneof_bool, :bool, 45
+ optional :oneof_double, :double, 46
+ optional :oneof_float, :float, 47
+ optional :oneof_string, :string, 48
+ optional :oneof_bytes, :string, 49
+ optional :oneof_enum, :enum, 50, "A.B.C.TestEnum"
+ optional :oneof_msg, :message, 51, "A.B.C.TestMessage"
+ end
+ end
+ add_message "A.B.C.TestMessage.NestedMessage" do
+ optional :foo, :int32, 1
+ end
+ add_enum "A.B.C.TestEnum" do
+ value :Default, 0
+ value :A, 1
+ value :B, 2
+ value :C, 3
+ end
+end
+
+module A
+ module B
+ module C
+ TestMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage").msgclass
+ TestMessage::NestedMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.NestedMessage").msgclass
+ TestEnum = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestEnum").enummodule
+ end
+ end
+end
diff --git a/ruby/tests/generated_code_test.rb b/ruby/tests/generated_code_test.rb
new file mode 100644
index 00000000..daef357a
--- /dev/null
+++ b/ruby/tests/generated_code_test.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/ruby
+
+# generated_code.rb is in the same directory as this test.
+$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
+
+require 'generated_code'
+require 'test/unit'
+
+class GeneratedCodeTest < Test::Unit::TestCase
+ def test_generated_msg
+ # just test that we can instantiate the message. The purpose of this test
+ # is to ensure that the output of the code generator is valid Ruby and
+ # successfully creates message definitions and classes, not to test every
+ # aspect of the extension (basic.rb is for that).
+ m = A::B::C::TestMessage.new()
+ end
+end
diff --git a/ruby/tests/stress.rb b/ruby/tests/stress.rb
new file mode 100644
index 00000000..082d5e22
--- /dev/null
+++ b/ruby/tests/stress.rb
@@ -0,0 +1,38 @@
+#!/usr/bin/ruby
+
+require 'google/protobuf'
+require 'test/unit'
+
+module StressTest
+ pool = Google::Protobuf::DescriptorPool.new
+ pool.build do
+ add_message "TestMessage" do
+ optional :a, :int32, 1
+ repeated :b, :message, 2, "M"
+ end
+ add_message "M" do
+ optional :foo, :string, 1
+ end
+ end
+
+ TestMessage = pool.lookup("TestMessage").msgclass
+ M = pool.lookup("M").msgclass
+
+ class StressTest < Test::Unit::TestCase
+ def get_msg
+ TestMessage.new(:a => 1000,
+ :b => [M.new(:foo => "hello"),
+ M.new(:foo => "world")])
+ end
+ def test_stress
+ m = get_msg
+ data = TestMessage.encode(m)
+ 100_000.times do
+ mnew = TestMessage.decode(data)
+ mnew = mnew.dup
+ assert_equal mnew.inspect, m.inspect
+ assert TestMessage.encode(mnew) == data
+ end
+ end
+ end
+end
diff --git a/src/Makefile.am b/src/Makefile.am
index 327339a9..8a27b823 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,59 +31,122 @@ nobase_dist_proto_DATA = google/protobuf/descriptor.proto \
clean-local:
rm -f *.loT
-CLEANFILES = $(protoc_outputs) unittest_proto_middleman \
+public_config = google/protobuf/stubs/pbconfig.h
+
+CLEANFILES = $(protoc_outputs) $(public_config) unittest_proto_middleman \
testzip.jar testzip.list testzip.proto testzip.zip
MAINTAINERCLEANFILES = \
Makefile.in
-nobase_include_HEADERS = \
- google/protobuf/stubs/common.h \
- google/protobuf/stubs/once.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_message_util.h \
- google/protobuf/generated_message_reflection.h \
- google/protobuf/message.h \
- google/protobuf/message_lite.h \
- google/protobuf/reflection_ops.h \
- google/protobuf/repeated_field.h \
- google/protobuf/service.h \
- google/protobuf/text_format.h \
- google/protobuf/unknown_field_set.h \
- google/protobuf/wire_format.h \
- google/protobuf/wire_format_lite.h \
- google/protobuf/wire_format_lite_inl.h \
- google/protobuf/io/coded_stream.h \
- $(GZHEADERS) \
- google/protobuf/io/printer.h \
- google/protobuf/io/tokenizer.h \
- google/protobuf/io/zero_copy_stream.h \
- google/protobuf/io/zero_copy_stream_impl.h \
- google/protobuf/io/zero_copy_stream_impl_lite.h \
- google/protobuf/compiler/code_generator.h \
- google/protobuf/compiler/command_line_interface.h \
- google/protobuf/compiler/importer.h \
- google/protobuf/compiler/parser.h \
- google/protobuf/compiler/plugin.h \
- google/protobuf/compiler/plugin.pb.h \
- google/protobuf/compiler/cpp/cpp_generator.h \
- google/protobuf/compiler/java/java_generator.h \
- google/protobuf/compiler/python/python_generator.h
+# Generate and distribute a minimum config.h file to make hash_map work.
+# The autoheader config has too much info, which might conflict with other
+# macros applications might include. Thus, we create a stubs/pbconfig.h, that
+# only #defines what we really need, and prefix it with GOOGLE_PROTOBUF_ to
+# avoid conflicts.
+$(public_config): $(top_builddir)/config.h $(top_srcdir)/config.h.include
+ echo "// Note: Google Protobuf internal only. Do NOT include." > $@
+ cat $(top_builddir)/config.h | grep -f $(top_srcdir)/config.h.include | \
+ sed 's,#define , #define GOOGLE_PROTOBUF_,' >> $@
+
+nobase_include_HEADERS = \
+ google/protobuf/stubs/atomic_sequence_num.h \
+ google/protobuf/stubs/atomicops.h \
+ google/protobuf/stubs/atomicops_internals_aix.h \
+ google/protobuf/stubs/atomicops_internals_arm64_gcc.h \
+ google/protobuf/stubs/atomicops_internals_arm_gcc.h \
+ google/protobuf/stubs/atomicops_internals_arm_qnx.h \
+ google/protobuf/stubs/atomicops_internals_atomicword_compat.h \
+ google/protobuf/stubs/atomicops_internals_generic_gcc.h \
+ google/protobuf/stubs/atomicops_internals_macosx.h \
+ google/protobuf/stubs/atomicops_internals_mips_gcc.h \
+ google/protobuf/stubs/atomicops_internals_pnacl.h \
+ google/protobuf/stubs/atomicops_internals_solaris.h \
+ 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/common.h \
+ google/protobuf/stubs/fastmem.h \
+ google/protobuf/stubs/hash.h \
+ google/protobuf/stubs/once.h \
+ google/protobuf/stubs/platform_macros.h \
+ google/protobuf/stubs/shared_ptr.h \
+ google/protobuf/stubs/singleton.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/dynamic_message.h \
+ google/protobuf/extension_set.h \
+ google/protobuf/generated_enum_reflection.h \
+ google/protobuf/generated_enum_util.h \
+ google/protobuf/generated_message_reflection.h \
+ google/protobuf/generated_message_util.h \
+ google/protobuf/map_entry.h \
+ google/protobuf/map_entry_lite.h \
+ google/protobuf/map_field.h \
+ google/protobuf/map_field_lite.h \
+ google/protobuf/map_field_inl.h \
+ google/protobuf/map.h \
+ google/protobuf/map_type_handler.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 \
+ google/protobuf/wire_format.h \
+ google/protobuf/wire_format_lite.h \
+ google/protobuf/wire_format_lite_inl.h \
+ google/protobuf/io/coded_stream.h \
+ $(GZHEADERS) \
+ google/protobuf/io/printer.h \
+ google/protobuf/io/strtod.h \
+ google/protobuf/io/tokenizer.h \
+ google/protobuf/io/zero_copy_stream.h \
+ google/protobuf/io/zero_copy_stream_impl.h \
+ google/protobuf/io/zero_copy_stream_impl_lite.h \
+ google/protobuf/compiler/code_generator.h \
+ google/protobuf/compiler/command_line_interface.h \
+ google/protobuf/compiler/importer.h \
+ google/protobuf/compiler/parser.h \
+ google/protobuf/compiler/plugin.h \
+ google/protobuf/compiler/plugin.pb.h \
+ google/protobuf/compiler/cpp/cpp_generator.h \
+ google/protobuf/compiler/java/java_generator.h \
+ google/protobuf/compiler/java/java_names.h \
+ google/protobuf/compiler/javanano/javanano_generator.h \
+ google/protobuf/compiler/python/python_generator.h \
+ google/protobuf/compiler/ruby/ruby_generator.h
+
+nobase_nodist_include_HEADERS = \
+ $(public_config)
lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
libprotobuf_lite_la_LIBADD = $(PTHREAD_LIBS)
-libprotobuf_lite_la_LDFLAGS = -version-info 7:0:0 -export-dynamic -no-undefined
+libprotobuf_lite_la_LDFLAGS = -version-info 10:0:0 -export-dynamic -no-undefined
libprotobuf_lite_la_SOURCES = \
+ google/protobuf/stubs/atomicops_internals_x86_gcc.cc \
+ google/protobuf/stubs/atomicops_internals_x86_msvc.cc \
google/protobuf/stubs/common.cc \
google/protobuf/stubs/once.cc \
google/protobuf/stubs/hash.h \
- google/protobuf/stubs/map-util.h \
- google/protobuf/stubs/stl_util-inl.h \
+ google/protobuf/stubs/map_util.h \
+ 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 \
@@ -93,9 +156,10 @@ libprotobuf_lite_la_SOURCES = \
google/protobuf/io/coded_stream_inl.h \
google/protobuf/io/zero_copy_stream.cc \
google/protobuf/io/zero_copy_stream_impl_lite.cc
+nodist_libprotobuf_lite_la_SOURCES = $(public_config)
libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
-libprotobuf_la_LDFLAGS = -version-info 7:0:0 -export-dynamic -no-undefined
+libprotobuf_la_LDFLAGS = -version-info 10:0:0 -export-dynamic -no-undefined
libprotobuf_la_SOURCES = \
$(libprotobuf_lite_la_SOURCES) \
google/protobuf/stubs/strutil.cc \
@@ -104,12 +168,14 @@ 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/map_field.cc \
google/protobuf/message.cc \
+ google/protobuf/reflection_internal.h \
google/protobuf/reflection_ops.cc \
google/protobuf/service.cc \
google/protobuf/text_format.cc \
@@ -117,13 +183,15 @@ libprotobuf_la_SOURCES = \
google/protobuf/wire_format.cc \
google/protobuf/io/gzip_stream.cc \
google/protobuf/io/printer.cc \
+ google/protobuf/io/strtod.cc \
google/protobuf/io/tokenizer.cc \
google/protobuf/io/zero_copy_stream_impl.cc \
google/protobuf/compiler/importer.cc \
google/protobuf/compiler/parser.cc
+nodist_libprotobuf_la_SOURCES = $(nodist_libprotobuf_lite_la_SOURCES)
libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la
-libprotoc_la_LDFLAGS = -version-info 7:0:0 -export-dynamic -no-undefined
+libprotoc_la_LDFLAGS = -version-info 10:0:0 -export-dynamic -no-undefined
libprotoc_la_SOURCES = \
google/protobuf/compiler/code_generator.cc \
google/protobuf/compiler/command_line_interface.cc \
@@ -146,20 +214,25 @@ libprotoc_la_SOURCES = \
google/protobuf/compiler/cpp/cpp_generator.cc \
google/protobuf/compiler/cpp/cpp_helpers.cc \
google/protobuf/compiler/cpp/cpp_helpers.h \
+ google/protobuf/compiler/cpp/cpp_map_field.cc \
+ google/protobuf/compiler/cpp/cpp_map_field.h \
google/protobuf/compiler/cpp/cpp_message.cc \
google/protobuf/compiler/cpp/cpp_message.h \
google/protobuf/compiler/cpp/cpp_message_field.cc \
google/protobuf/compiler/cpp/cpp_message_field.h \
+ google/protobuf/compiler/cpp/cpp_options.h \
google/protobuf/compiler/cpp/cpp_primitive_field.cc \
google/protobuf/compiler/cpp/cpp_primitive_field.h \
google/protobuf/compiler/cpp/cpp_service.cc \
google/protobuf/compiler/cpp/cpp_service.h \
google/protobuf/compiler/cpp/cpp_string_field.cc \
google/protobuf/compiler/cpp/cpp_string_field.h \
+ 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 \
@@ -167,19 +240,55 @@ libprotoc_la_SOURCES = \
google/protobuf/compiler/java/java_file.cc \
google/protobuf/compiler/java/java_file.h \
google/protobuf/compiler/java/java_generator.cc \
+ google/protobuf/compiler/java/java_generator_factory.cc \
+ google/protobuf/compiler/java/java_generator_factory.h \
google/protobuf/compiler/java/java_helpers.cc \
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 \
google/protobuf/compiler/java/java_primitive_field.h \
+ google/protobuf/compiler/java/java_shared_code_generator.cc \
+ google/protobuf/compiler/java/java_shared_code_generator.h \
google/protobuf/compiler/java/java_service.cc \
google/protobuf/compiler/java/java_service.h \
google/protobuf/compiler/java/java_string_field.cc \
google/protobuf/compiler/java/java_string_field.h \
- google/protobuf/compiler/python/python_generator.cc
+ google/protobuf/compiler/java/java_doc_comment.cc \
+ google/protobuf/compiler/java/java_doc_comment.h \
+ google/protobuf/compiler/javanano/javanano_enum.cc \
+ google/protobuf/compiler/javanano/javanano_enum.h \
+ google/protobuf/compiler/javanano/javanano_enum_field.cc \
+ google/protobuf/compiler/javanano/javanano_enum_field.h \
+ google/protobuf/compiler/javanano/javanano_extension.cc \
+ google/protobuf/compiler/javanano/javanano_extension.h \
+ google/protobuf/compiler/javanano/javanano_field.cc \
+ google/protobuf/compiler/javanano/javanano_field.h \
+ google/protobuf/compiler/javanano/javanano_file.cc \
+ google/protobuf/compiler/javanano/javanano_file.h \
+ google/protobuf/compiler/javanano/javanano_generator.cc \
+ google/protobuf/compiler/javanano/javanano_generator.h \
+ google/protobuf/compiler/javanano/javanano_helpers.cc \
+ google/protobuf/compiler/javanano/javanano_helpers.h \
+ google/protobuf/compiler/javanano/javanano_map_field.cc \
+ google/protobuf/compiler/javanano/javanano_map_field.h \
+ google/protobuf/compiler/javanano/javanano_message.cc \
+ google/protobuf/compiler/javanano/javanano_message.h \
+ google/protobuf/compiler/javanano/javanano_message_field.cc \
+ google/protobuf/compiler/javanano/javanano_message_field.h \
+ google/protobuf/compiler/javanano/javanano_params.h \
+ google/protobuf/compiler/javanano/javanano_primitive_field.cc \
+ google/protobuf/compiler/javanano/javanano_primitive_field.h \
+ google/protobuf/compiler/python/python_generator.cc \
+ google/protobuf/compiler/ruby/ruby_generator.cc
bin_PROGRAMS = protoc
protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
@@ -188,18 +297,32 @@ protoc_SOURCES = google/protobuf/compiler/main.cc
# Tests ==============================================================
protoc_inputs = \
+ google/protobuf/map_lite_unittest.proto \
+ google/protobuf/map_proto2_unittest.proto \
+ google/protobuf/map_unittest.proto \
google/protobuf/unittest.proto \
- google/protobuf/unittest_empty.proto \
- google/protobuf/unittest_import.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/compiler/cpp/cpp_test_bad_identifiers.proto
+ google/protobuf/unittest_optimize_for.proto \
+ google/protobuf/unittest_preserve_unknown_enum.proto \
+ google/protobuf/unittest_preserve_unknown_enum2.proto \
+ google/protobuf/unittest_proto3_arena.proto \
+ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto \
+ google/protobuf/compiler/cpp/test_large_enum_value.proto
EXTRA_DIST = \
$(protoc_inputs) \
@@ -207,9 +330,16 @@ EXTRA_DIST = \
google/protobuf/io/gzip_stream.h \
google/protobuf/io/gzip_stream_unittest.sh \
google/protobuf/testdata/golden_message \
+ google/protobuf/testdata/golden_message_oneof_implemented \
+ google/protobuf/testdata/golden_message_proto3 \
google/protobuf/testdata/golden_packed_fields_message \
+ google/protobuf/testdata/bad_utf8_string \
google/protobuf/testdata/text_format_unittest_data.txt \
- google/protobuf/testdata/text_format_unittest_extensions_data.txt \
+ google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt \
+ google/protobuf/testdata/text_format_unittest_data_pointy.txt \
+ google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt \
+ google/protobuf/testdata/text_format_unittest_extensions_data.txt \
+ google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt \
google/protobuf/package_info.h \
google/protobuf/io/package_info.h \
google/protobuf/compiler/package_info.h \
@@ -217,35 +347,63 @@ EXTRA_DIST = \
google/protobuf/unittest_enormous_descriptor.proto
protoc_lite_outputs = \
+ google/protobuf/map_lite_unittest.pb.cc \
+ google/protobuf/map_lite_unittest.pb.h \
google/protobuf/unittest_lite.pb.cc \
google/protobuf/unittest_lite.pb.h \
google/protobuf/unittest_import_lite.pb.cc \
- google/protobuf/unittest_import_lite.pb.h
+ google/protobuf/unittest_import_lite.pb.h \
+ google/protobuf/unittest_import_public_lite.pb.cc \
+ google/protobuf/unittest_import_public_lite.pb.h
protoc_outputs = \
$(protoc_lite_outputs) \
+ google/protobuf/map_proto2_unittest.pb.cc \
+ google/protobuf/map_proto2_unittest.pb.h \
+ google/protobuf/map_unittest.pb.cc \
+ google/protobuf/map_unittest.pb.h \
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_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_import_public.pb.cc \
+ google/protobuf/unittest_import_public.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_preserve_unknown_enum2.pb.cc \
+ google/protobuf/unittest_preserve_unknown_enum2.pb.h \
+ google/protobuf/unittest_proto3_arena.pb.cc \
+ google/protobuf/unittest_proto3_arena.pb.h \
+ google/protobuf/compiler/cpp/test_large_enum_value.pb.cc \
+ google/protobuf/compiler/cpp/test_large_enum_value.pb.h \
google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc \
google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h
-BUILT_SOURCES = $(protoc_outputs)
+BUILT_SOURCES = $(public_config) $(protoc_outputs)
if USE_EXTERNAL_PROTOC
@@ -267,6 +425,11 @@ endif
$(protoc_outputs): unittest_proto_middleman
COMMON_TEST_SOURCES = \
+ google/protobuf/arena_test_util.cc \
+ google/protobuf/arena_test_util.h \
+ google/protobuf/map_test_util.cc \
+ google/protobuf/map_test_util.h \
+ google/protobuf/map_test_util_impl.h \
google/protobuf/test_util.cc \
google/protobuf/test_util.h \
google/protobuf/testing/googletest.cc \
@@ -290,13 +453,25 @@ protobuf_test_SOURCES = \
google/protobuf/stubs/once_unittest.cc \
google/protobuf/stubs/strutil_unittest.cc \
google/protobuf/stubs/structurally_valid_unittest.cc \
+ 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/map_field_test.cc \
+ google/protobuf/map_test.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_reflection_unittest.cc \
google/protobuf/repeated_field_unittest.cc \
google/protobuf/text_format_unittest.cc \
google/protobuf/unknown_field_set_unittest.cc \
@@ -311,16 +486,20 @@ protobuf_test_SOURCES = \
google/protobuf/compiler/mock_code_generator.h \
google/protobuf/compiler/parser_unittest.cc \
google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc \
+ google/protobuf/compiler/cpp/cpp_unittest.h \
google/protobuf/compiler/cpp/cpp_unittest.cc \
google/protobuf/compiler/cpp/cpp_plugin_unittest.cc \
google/protobuf/compiler/java/java_plugin_unittest.cc \
+ google/protobuf/compiler/java/java_doc_comment_unittest.cc \
google/protobuf/compiler/python/python_plugin_unittest.cc \
+ google/protobuf/compiler/ruby/ruby_generator_unittest.cc \
$(COMMON_TEST_SOURCES)
nodist_protobuf_test_SOURCES = $(protoc_outputs)
# Run cpp_unittest again with PROTOBUF_TEST_NO_DESCRIPTORS defined.
protobuf_lazy_descriptor_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la \
- $(top_builddir)/gtest/lib/libgtest.la \
+ libprotoc.la \
+ $(top_builddir)/gtest/lib/libgtest.la \
$(top_builddir)/gtest/lib/libgtest_main.la
protobuf_lazy_descriptor_test_CPPFLAGS = -I$(top_srcdir)/gtest/include \
-I$(top_builddir)/gtest/include \
@@ -336,8 +515,12 @@ protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la
protobuf_lite_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
protobuf_lite_test_SOURCES = \
google/protobuf/lite_unittest.cc \
+ google/protobuf/map_lite_test_util.cc \
+ google/protobuf/map_lite_test_util.h \
google/protobuf/test_util_lite.cc \
google/protobuf/test_util_lite.h
+ # TODO(teboring) add the file back and make the test build.
+ # google/protobuf/map_lite_test.cc
nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs)
# Test plugin binary.
diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto
new file mode 100644
index 00000000..bf2aa0a9
--- /dev/null
+++ b/src/google/protobuf/any.proto
@@ -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.
+syntax = "proto3";
+
+package google.protobuf;
+
+option java_generate_equals_and_hash = true;
+option java_multiple_files = true;
+option java_outer_classname = "AnyProto";
+option java_package = "com.google.protobuf";
+
+
+// `Any` contains an arbitrary serialized message along with a URL
+// that describes the type of the serialized message.
+//
+//
+//
+// # JSON
+// The JSON representation of an `Any` value uses the regular
+// representation of the deserialized, embedded message, with an
+// additional field `@type` which contains the type URL. Example:
+//
+// package google.profile;
+// message Person {
+// string first_name = 1;
+// string last_name = 2;
+// }
+//
+// {
+// "@type": "type.googleapis.com/google.profile.Person",
+// "firstName": <string>,
+// "lastName": <string>
+// }
+//
+// If the embedded message type is well-known and has a custom JSON
+// representation, that representation will be embedded adding a field
+// `value` which holds the custom JSON in addition to the the `@type`
+// field. Example (for message [google.protobuf.Duration][google.protobuf.Duration]):
+//
+// {
+// "@type": "type.googleapis.com/google.protobuf.Duration",
+// "value": "1.212s"
+// }
+//
+message Any {
+ // A URL/resource name whose content describes the type of the
+ // serialized message.
+ //
+ // For URLs which use the schema `http`, `https`, or no schema, the
+ // following restrictions and interpretations apply:
+ //
+ // * If no schema is provided, https is assumed.
+ // * The last segment of the URL's path must represent the fully
+ // qualified name of the type (as in `path/google.protobuf.Duration`).
+ // * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type]
+ // value in binary format, or produce an error.
+ // * Applications are allowed to cache lookup results based on the
+ // URL, or have them precompiled into a binary to avoid any
+ // lookup. Therefore, binary compatibility need to be preserved
+ // on changes to types. (Use versioned type names to manage
+ // breaking changes.)
+ //
+ // Schemas other than `http`, `https` (or the empty schema) might be
+ // used with implementation specific semantics.
+ //
+ //
+ string type_url = 1;
+
+ // Must be valid serialized data of the above specified type.
+ bytes value = 2;
+}
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
new file mode 100755
index 00000000..bda37413
--- /dev/null
+++ b/src/google/protobuf/arena.cc
@@ -0,0 +1,285 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/arena.h>
+
+#ifdef ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif
+
+namespace google {
+namespace protobuf {
+
+google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_;
+#ifdef PROTOBUF_USE_DLLS
+Arena::ThreadCache& Arena::thread_cache() {
+ static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
+ return thread_cache_;
+}
+#else
+GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL };
+#endif
+
+void Arena::Init() {
+ lifecycle_id_ = lifecycle_id_generator_.GetNext();
+ blocks_ = 0;
+ hint_ = 0;
+ owns_first_block_ = true;
+ cleanup_list_ = 0;
+
+ if (options_.initial_block != NULL && options_.initial_block_size > 0) {
+ // Add first unowned block to list.
+ Block* first_block = reinterpret_cast<Block*>(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;
+ }
+
+ // Call the initialization hook
+ if (options_.on_arena_init != NULL) {
+ hooks_cookie_ = options_.on_arena_init(this);
+ } else {
+ hooks_cookie_ = NULL;
+ }
+}
+
+Arena::~Arena() {
+ uint64 space_allocated = Reset();
+
+ // Call the destruction hook
+ if (options_.on_arena_destruction != NULL) {
+ options_.on_arena_destruction(this, hooks_cookie_, space_allocated);
+ }
+}
+
+uint64 Arena::Reset() {
+ CleanupList();
+ uint64 space_allocated = FreeBlocks();
+ // Invalidate any ThreadCaches pointing to any blocks we just destroyed.
+ lifecycle_id_ = lifecycle_id_generator_.GetNext();
+
+ // Call the reset hook
+ if (options_.on_arena_reset != NULL) {
+ options_.on_arena_reset(this, hooks_cookie_, space_allocated);
+ }
+
+ return space_allocated;
+}
+
+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*>(options_.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;
+ }
+#ifdef ADDRESS_SANITIZER
+ // Poison the rest of the block for ASAN. It was unpoisoned by the underlying
+ // malloc but it's not yet usable until we return it as part of an allocation.
+ ASAN_POISON_MEMORY_REGION(
+ reinterpret_cast<char*>(b) + b->pos, b->size - b->pos);
+#endif
+ return b;
+}
+
+void Arena::AddBlock(Block* b) {
+ MutexLock l(&blocks_lock_);
+ b->next = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+ google::protobuf::internal::Release_Store(&blocks_, reinterpret_cast<google::protobuf::internal::AtomicWord>(b));
+ if (b->avail() != 0) {
+ // Direct future allocations to this block.
+ google::protobuf::internal::Release_Store(&hint_, reinterpret_cast<google::protobuf::internal::AtomicWord>(b));
+ }
+}
+
+void Arena::AddListNode(void* elem, void (*cleanup)(void*)) {
+ Node* node = reinterpret_cast<Node*>(AllocateAligned(sizeof(Node)));
+ node->elem = elem;
+ node->cleanup = cleanup;
+ node->next = reinterpret_cast<Node*>(
+ google::protobuf::internal::NoBarrier_AtomicExchange(&cleanup_list_,
+ reinterpret_cast<google::protobuf::internal::AtomicWord>(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<Block*>(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->avail() >= n) {
+ 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;
+#ifdef ADDRESS_SANITIZER
+ ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b) + p, n);
+#endif
+ return reinterpret_cast<char*>(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<google::protobuf::internal::AtomicWord>(b));
+ return AllocFromBlock(b, n);
+ }
+ b = NewBlock(me, b, n, options_.start_block_size, options_.max_block_size);
+ AddBlock(b);
+ if (b->owner == me) { // If this block can be reused (see NewBlock()).
+ SetThreadCacheBlock(b);
+ }
+ return reinterpret_cast<char*>(b) + kHeaderSize;
+}
+
+uint64 Arena::SpaceAllocated() const {
+ uint64 space_allocated = 0;
+ Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+ while (b != NULL) {
+ space_allocated += (b->size);
+ b = b->next;
+ }
+ return space_allocated;
+}
+
+uint64 Arena::SpaceUsed() const {
+ uint64 space_used = 0;
+ Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+ while (b != NULL) {
+ space_used += (b->pos - kHeaderSize);
+ b = b->next;
+ }
+ return space_used;
+}
+
+uint64 Arena::FreeBlocks() {
+ uint64 space_allocated = 0;
+ Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+ Block* first_block = NULL;
+ while (b != NULL) {
+ space_allocated += (b->size);
+ Block* next = b->next;
+ if (next != NULL) {
+ options_.block_dealloc(b, b->size);
+ } else {
+ if (owns_first_block_) {
+ options_.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_allocated;
+}
+
+void Arena::CleanupList() {
+ Node* head =
+ reinterpret_cast<Node*>(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<Block*>(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..bb15e80c
--- /dev/null
+++ b/src/google/protobuf/arena.h
@@ -0,0 +1,602 @@
+// 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 <typeinfo>
+
+#include <google/protobuf/stubs/atomic_sequence_num.h>
+#include <google/protobuf/stubs/atomicops.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/type_traits.h>
+
+namespace google {
+namespace protobuf {
+
+class Arena; // defined below
+class Message; // message.h
+
+namespace internal {
+class ArenaString; // arenastring.h
+class LazyField; // lazy_field.h
+
+template<typename Type>
+class GenericTypeHandler; // repeated_field.h
+
+// Templated cleanup methods.
+template<typename T> void arena_destruct_object(void* object) {
+ reinterpret_cast<T*>(object)->~T();
+}
+template<typename T> void arena_delete_object(void* object) {
+ delete reinterpret_cast<T*>(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.
+ //
+ // NOTE: block_alloc and dealloc functions are expected to behave like
+ // malloc and free, including Asan poisoning.
+ 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);
+
+ // Hooks for adding external functionality such as user-specific metrics
+ // collection, specific debugging abilities, etc.
+ // Init hook may return a pointer to a cookie to be stored in the arena.
+ // reset and destruction hooks will then be called with the same cookie
+ // pointer. This allows us to save an external object per arena instance and
+ // use it on the other hooks (Note: It is just as legal for init to return
+ // NULL and not use the cookie feature).
+ // on_arena_reset and on_arena_destruction also receive the space used in
+ // the arena just before the reset.
+ void* (*on_arena_init)(Arena* arena);
+ void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
+ void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
+
+ // type_name is promised to be a static string - its lifetime extends to
+ // match program's lifetime.
+ void (*on_arena_allocation)(const char* type_name, uint64 alloc_size,
+ Arena* arena, void* cookie);
+
+ ArenaOptions()
+ : start_block_size(kDefaultStartBlockSize),
+ max_block_size(kDefaultMaxBlockSize),
+ initial_block(NULL),
+ initial_block_size(0),
+ block_alloc(&malloc),
+ block_dealloc(&internal::arena_free),
+ on_arena_init(NULL),
+ on_arena_reset(NULL),
+ on_arena_destruction(NULL),
+ on_arena_allocation(NULL) {}
+
+ 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<T>(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) : options_(options) {
+ Init();
+ }
+
+ // Default constructor with sensible default options, tuned for average
+ // use-cases.
+ Arena() {
+ Init();
+ }
+
+ // 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();
+
+ // 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 <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ static T* CreateMessage(::google::protobuf::Arena* arena) {
+ if (arena == NULL) {
+ return new T;
+ } else {
+ return arena->CreateMessageInternal<T>(static_cast<T*>(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<T>() instead.
+ template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ static T* Create(::google::protobuf::Arena* arena) {
+ if (arena == NULL) {
+ return new T();
+ } else {
+ return arena->CreateInternal<T>(
+ SkipDeleteList<T>(static_cast<T*>(0)));
+ }
+ }
+
+ // Version of the above with one constructor argument for the created object.
+ template <typename T, typename Arg> 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<T>(SkipDeleteList<T>(static_cast<T*>(0)),
+ arg);
+ }
+ }
+
+ // Version of the above with two constructor arguments for the created object.
+ template <typename T, typename Arg1, typename Arg2> 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<T>(SkipDeleteList<T>(static_cast<T*>(0)),
+ arg1,
+ arg2);
+ }
+ }
+
+ // Version of the above with three constructor arguments for the created
+ // object.
+ template <typename T, typename Arg1, typename Arg2, typename Arg3>
+ GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+ const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3) {
+ if (arena == NULL) {
+ return new T(arg1, arg2, arg3);
+ } else {
+ return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
+ arg1,
+ arg2,
+ arg3);
+ }
+ }
+
+ // Version of the above with four constructor arguments for the created
+ // object.
+ template <typename T, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+ GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+ const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4) {
+ if (arena == NULL) {
+ return new T(arg1, arg2, arg3, arg4);
+ } else {
+ return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
+ arg1,
+ arg2,
+ arg3,
+ arg4);
+ }
+ }
+
+ // 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 <typename T> 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 arena->CreateInternalRawArray<T>(num_elements);
+ }
+ }
+
+ // 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 SpaceAllocated() const GOOGLE_ATTRIBUTE_NOINLINE;
+ // As above, but does not include any free space in underlying blocks.
+ 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 <typename T> GOOGLE_ATTRIBUTE_NOINLINE
+ void Own(T* object) {
+ OwnInternal(object, google::protobuf::internal::is_convertible<T*, ::google::protobuf::Message*>());
+ }
+
+ // 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 <typename T> GOOGLE_ATTRIBUTE_NOINLINE
+ void OwnDestructor(T* object) {
+ if (object != NULL) {
+ AddListNode(object, &internal::arena_destruct_object<T>);
+ }
+ }
+
+ // 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<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ static inline ::google::protobuf::Arena* GetArena(const T* value) {
+ return GetArenaInternal(value, static_cast<T*>(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<T>::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<typename T>
+ struct is_arena_constructable {
+ template<typename U>
+ static char ArenaConstructable(
+ const typename U::InternalArenaConstructable_*);
+ template<typename U>
+ 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<bool,
+ sizeof(ArenaConstructable<const T>(static_cast<const T*>(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
+ };
+
+ template<typename Type> 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_;
+#ifdef PROTOBUF_USE_DLLS
+ // Thread local variables cannot be exposed through DLL interface but we can
+ // wrap them in static functions.
+ static ThreadCache& thread_cache();
+#else
+ static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
+ static ThreadCache& thread_cache() { return thread_cache_; }
+#endif
+
+ // 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<T>.
+ //
+ template<typename T>
+ 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<typename T>
+ static inline bool SkipDeleteList(...) {
+ return google::protobuf::internal::has_trivial_destructor<T>::value;
+ }
+
+ // CreateMessage<T> 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<typename Msg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ static Msg* CreateMaybeMessage(
+ Arena* arena, typename Msg::InternalArenaConstructable_*) {
+ return CreateMessage<Msg>(arena);
+ }
+
+ template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ static T* CreateMaybeMessage(Arena* arena, ...) {
+ return Create<T>(arena);
+ }
+
+ // Just allocate the required size for the given type assuming the
+ // type has a trivial constructor.
+ template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ inline T* CreateInternalRawArray(uint32 num_elements) {
+ return static_cast<T*>(AllocateAligned(sizeof(T) * num_elements));
+ }
+
+ template <typename T> 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<T>);
+ }
+ return t;
+ }
+
+ template <typename T, typename Arg> 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<T>);
+ }
+ return t;
+ }
+
+ template <typename T, typename Arg1, typename Arg2> 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<T>);
+ }
+ return t;
+ }
+
+ template <typename T, typename Arg1, typename Arg2, typename Arg3>
+ GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
+ const Arg1& arg1,
+ const Arg2& arg2,
+ const Arg3& arg3) {
+ T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3);
+ if (!skip_explicit_ownership) {
+ AddListNode(t, &internal::arena_destruct_object<T>);
+ }
+ return t;
+ }
+
+ template <typename T, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+ GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
+ const Arg1& arg1,
+ const Arg2& arg2,
+ const Arg3& arg3,
+ const Arg4& arg4) {
+ T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3, arg4);
+ if (!skip_explicit_ownership) {
+ AddListNode(t, &internal::arena_destruct_object<T>);
+ }
+ return t;
+ }
+
+ template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*) {
+ return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
+ this);
+ }
+
+ // CreateInArenaStorage is used to implement map field. Without it,
+ // google::protobuf::Map need to call generated message's protected arena constructor,
+ // which needs to declare google::protobuf::Map as friend of generated message.
+ template <typename T>
+ static void CreateInArenaStorage(T* ptr, Arena* arena) {
+ CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>::value);
+ }
+ template <typename T>
+ static void CreateInArenaStorageInternal(
+ T* ptr, Arena* arena, google::protobuf::internal::true_type) {
+ new (ptr) T(arena);
+ }
+
+ template <typename T>
+ static void CreateInArenaStorageInternal(
+ T* ptr, Arena* arena, google::protobuf::internal::false_type) {
+ new (ptr) T;
+ }
+
+ // 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<typename T> 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<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ void OwnInternal(T* object, google::protobuf::internal::false_type) {
+ if (object != NULL) {
+ AddListNode(object, &internal::arena_delete_object<T>);
+ }
+ }
+
+ // Implementation for GetArena(). Only message objects with
+ // InternalArenaConstructable_ tags can be associated with an arena, and such
+ // objects must implement a GetArenaNoVirtual() method.
+ template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ static inline ::google::protobuf::Arena* GetArenaInternal(const T* value,
+ typename T::InternalArenaConstructable_*) {
+ return value->GetArenaNoVirtual();
+ }
+
+ template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+ static inline ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) {
+ return NULL;
+ }
+
+
+ void* AllocateAligned(size_t size);
+
+ void Init();
+
+ // 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().
+
+ 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);
+ template <typename Key, typename T>
+ friend class Map;
+
+ // The arena may save a cookie it receives from the external on_init hook
+ // and then use it when calling the on_reset and on_destruction hooks.
+ void* hooks_cookie_;
+
+ ArenaOptions options_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena);
+};
+
+template<typename T>
+const typename Arena::is_arena_constructable<T>::type
+ Arena::is_arena_constructable<T>::value =
+ typename Arena::is_arena_constructable<T>::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 <google/protobuf/arena.h>
+#include <google/protobuf/unittest.pb.h>
+
+#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/python/google/protobuf/pyext/python_protobuf.cc b/src/google/protobuf/arena_test_util.cc
index 1b1ab5d1..21f55c6e 100644
--- a/python/google/protobuf/pyext/python_protobuf.cc
+++ b/src/google/protobuf/arena_test_util.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -28,36 +28,22 @@
// (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: qrczak@google.com (Marcin Kowalczyk)
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena_test_util.h>
-#include <google/protobuf/pyext/python_protobuf.h>
+
+#define EXPECT_EQ GOOGLE_CHECK_EQ
namespace google {
namespace protobuf {
-namespace python {
-
-static const Message* GetCProtoInsidePyProtoStub(PyObject* msg) {
- return NULL;
-}
-static Message* MutableCProtoInsidePyProtoStub(PyObject* msg) {
- return NULL;
-}
-
-// This is initialized with a default, stub implementation.
-// If python-google.protobuf.cc is loaded, the function pointer is overridden
-// with a full implementation.
-const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg) =
- GetCProtoInsidePyProtoStub;
-Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg) =
- MutableCProtoInsidePyProtoStub;
+namespace internal {
-const Message* GetCProtoInsidePyProto(PyObject* msg) {
- return GetCProtoInsidePyProtoPtr(msg);
-}
-Message* MutableCProtoInsidePyProto(PyObject* msg) {
- return MutableCProtoInsidePyProtoPtr(msg);
+NoHeapChecker::~NoHeapChecker() {
+ capture_alloc.Unhook();
+ EXPECT_EQ(0, capture_alloc.alloc_count());
+ EXPECT_EQ(0, capture_alloc.free_count());
}
-} // namespace python
+} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/arena_test_util.h b/src/google/protobuf/arena_test_util.h
new file mode 100644
index 00000000..7db7a90e
--- /dev/null
+++ b/src/google/protobuf/arena_test_util.h
@@ -0,0 +1,59 @@
+// 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_ARENA_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+class NoHeapChecker {
+ public:
+ NoHeapChecker() {
+ capture_alloc.Hook();
+ }
+ ~NoHeapChecker();
+ 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;
+};
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
new file mode 100644
index 00000000..d9b198e0
--- /dev/null
+++ b/src/google/protobuf/arena_unittest.cc
@@ -0,0 +1,1173 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/arena.h>
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <cstring>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_arena.pb.h>
+#include <google/protobuf/unittest_no_arena.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <gtest/gtest.h>
+
+
+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_;
+};
+
+// A simple class that does not allow copying and so cannot be used as a
+// parameter type without "const &".
+class PleaseDontCopyMe {
+ public:
+ explicit PleaseDontCopyMe(int value) : value_(value) {}
+
+ int value() const { return value_; }
+
+ private:
+ int value_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PleaseDontCopyMe);
+};
+
+// A class that takes four different types as constructor arguments.
+class MustBeConstructedWithOneThroughFour {
+ public:
+ MustBeConstructedWithOneThroughFour(
+ int one, const char* two, const string& three,
+ const PleaseDontCopyMe* four)
+ : one_(one), two_(two), three_(three), four_(four) {}
+
+ int one_;
+ const char* const two_;
+ string three_;
+ const PleaseDontCopyMe* four_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughFour);
+};
+
+} // namespace
+
+TEST(ArenaTest, ArenaConstructable) {
+ EXPECT_TRUE(Arena::is_arena_constructable<TestAllTypes>::type::value);
+ EXPECT_TRUE(Arena::is_arena_constructable<const TestAllTypes>::type::value);
+ EXPECT_FALSE(Arena::is_arena_constructable<Arena>::type::value);
+}
+
+TEST(ArenaTest, BasicCreate) {
+ Arena arena;
+ EXPECT_TRUE(Arena::Create<int32>(&arena) != NULL);
+ EXPECT_TRUE(Arena::Create<int64>(&arena) != NULL);
+ EXPECT_TRUE(Arena::Create<float>(&arena) != NULL);
+ EXPECT_TRUE(Arena::Create<double>(&arena) != NULL);
+ EXPECT_TRUE(Arena::Create<string>(&arena) != NULL);
+ arena.Own(new int32);
+ arena.Own(new int64);
+ arena.Own(new float);
+ arena.Own(new double);
+ arena.Own(new string);
+ arena.Own<int>(NULL);
+ Notifier notifier;
+ SimpleDataType* data = Arena::Create<SimpleDataType>(&arena);
+ data->SetNotifier(&notifier);
+ data = new SimpleDataType;
+ data->SetNotifier(&notifier);
+ arena.Own(data);
+ arena.Reset();
+ EXPECT_EQ(2, notifier.GetCount());
+}
+
+TEST(ArenaTest, CreateWithManyConstructorArguments) {
+ Arena arena;
+ const string three("3");
+ const PleaseDontCopyMe four(4);
+ const MustBeConstructedWithOneThroughFour* new_object =
+ Arena::Create<MustBeConstructedWithOneThroughFour>(
+ &arena, 1, "2", three, &four);
+ EXPECT_TRUE(new_object != NULL);
+ ASSERT_EQ(1, new_object->one_);
+ ASSERT_STREQ("2", new_object->two_);
+ ASSERT_EQ("3", new_object->three_);
+ ASSERT_EQ(4, new_object->four_->value());
+}
+
+TEST(ArenaTest, InitialBlockTooSmall) {
+ // Construct a small (64 byte) initial block of memory to be used by the
+ // arena allocator; then, allocate an object which will not fit in the
+ // initial block.
+ std::vector<char> arena_block(64);
+ ArenaOptions options;
+ options.initial_block = &arena_block[0];
+ options.initial_block_size = arena_block.size();
+ Arena arena(options);
+
+ char* p = ::google::protobuf::Arena::CreateArray<char>(&arena, 96);
+ uintptr_t allocation = reinterpret_cast<uintptr_t>(p);
+
+ // Ensure that the arena allocator did not return memory pointing into the
+ // initial block of memory.
+ uintptr_t arena_start = reinterpret_cast<uintptr_t>(&arena_block[0]);
+ uintptr_t arena_end = arena_start + arena_block.size();
+ EXPECT_FALSE(allocation >= arena_start && allocation < arena_end);
+
+ // Write to the memory we allocated; this should (but is not guaranteed to)
+ // trigger a check for heap corruption if the object was allocated from the
+ // initially-provided block.
+ memset(p, '\0', 96);
+}
+
+TEST(ArenaTest, Parsing) {
+ TestAllTypes original;
+ TestUtil::SetAllFields(&original);
+
+ // Test memory leak.
+ Arena arena;
+ TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&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<TestEmptyMessage>(&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<TestEmptyMessage>(&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<TestEmptyMessage>(&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<TestEmptyMessage>(&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<TestAllTypes>(&arena1);
+ arena2_message = Arena::CreateMessage<TestAllTypes>(&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<TestAllTypes>(&arena1);
+ arena2_message = Arena::CreateMessage<TestAllTypes>(&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<TestAllTypes>(&arena1);
+ arena2_message = Arena::CreateMessage<TestAllTypes>(&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<TestAllTypes>(&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<TestAllTypes>(&arena);
+ arena_message->mutable_optional_nested_message()->set_bb(118);
+ scoped_ptr<TestAllTypes::NestedMessage> 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<TestAllTypes>(&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<TestAllTypes>(&arena);
+ arena_message->set_optional_string("hello");
+ scoped_ptr<string> 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<TestAllTypes>(&arena1);
+ {
+ Arena arena2;
+ TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&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<TestAllTypes>(&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<TestAllTypes>(&shared_arena);
+ TestAllTypes* message2 = Arena::CreateMessage<TestAllTypes>(&shared_arena);
+ TestUtil::SetAllFields(message1);
+ message1->UnsafeArenaSwap(message2);
+ TestUtil::ExpectAllFieldsSet(*message2);
+}
+
+TEST(ArenaTest, SwapBetweenArenasUsingReflection) {
+ Arena arena1;
+ TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+ {
+ Arena arena2;
+ TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&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<TestAllTypes>(&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<TestAllTypes>(&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;
+}
+
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
+TEST(ArenaTest, ReleaseFromArenaMessageUsingReflectionMakesCopy) {
+ TestAllTypes::NestedMessage* nested_msg = NULL;
+ // Note: no string: reflection API only supports releasing submessages.
+ {
+ Arena arena;
+ TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&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 = static_cast<TestAllTypes::NestedMessage*>(
+ r->ReleaseMessage(arena_message, f));
+ }
+ EXPECT_EQ(42, nested_msg->bb());
+ delete nested_msg;
+}
+#endif // !GOOGLE_PROTOBUF_NO_RTTI
+
+TEST(ArenaTest, UnsafeArenaReleaseDoesNotMakeCopy) {
+ Arena arena;
+ TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&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<TestAllTypes>(&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<TestAllTypes::NestedMessage>(&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<TestAllTypes::NestedMessage>(&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<TestAllTypes>(&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<TestAllTypes::NestedMessage>(&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<TestAllTypes::NestedMessage>(&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<ArenaMessage>(&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<TestAllTypes> 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<TestAllTypes> 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<TestAllTypes>(&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<TestAllTypes::NestedMessage>(&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<TestAllTypes::NestedMessage>(&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<TestAllTypes>(&arena);
+ for (int i = 0; i < 10; i++) {
+ TestAllTypes::NestedMessage* nested =
+ Arena::CreateMessage<TestAllTypes::NestedMessage>(&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<TestAllTypes::NestedMessage>(&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<TestAllTypes>(&arena);
+ TestAllTypes* message2 = Arena::CreateMessage<TestAllTypes>(&arena);
+ string* arena_string = Arena::Create<string>(&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<TestAllTypes>(&arena);
+ for (int i = 0; i < 10; i++) {
+ string* arena_string = Arena::Create<string>(&arena);
+ message->mutable_repeated_string()->UnsafeArenaAddAllocated(arena_string);
+ EXPECT_EQ(arena_string, message->mutable_repeated_string(i));
+ }
+}
+
+TEST(ArenaTest, UnsafeArenaRelease) {
+ Arena arena;
+ TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+
+ string* s = new string("test string");
+ message->unsafe_arena_set_allocated_optional_string(s);
+ EXPECT_TRUE(message->has_optional_string());
+ EXPECT_EQ("test string", message->optional_string());
+ s = message->unsafe_arena_release_optional_string();
+ EXPECT_FALSE(message->has_optional_string());
+ delete s;
+
+ s = new string("test string");
+ message->unsafe_arena_set_allocated_oneof_string(s);
+ EXPECT_TRUE(message->has_oneof_string());
+ EXPECT_EQ("test string", message->oneof_string());
+ s = message->unsafe_arena_release_oneof_string();
+ EXPECT_FALSE(message->has_oneof_string());
+ delete s;
+}
+
+TEST(ArenaTest, ArenaOneofReflection) {
+ Arena arena;
+ TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+ const Descriptor* desc = message->GetDescriptor();
+ const Reflection* refl = message->GetReflection();
+
+ const FieldDescriptor* string_field = desc->FindFieldByName(
+ "oneof_string");
+ const FieldDescriptor* msg_field = desc->FindFieldByName(
+ "oneof_nested_message");
+ const OneofDescriptor* oneof = desc->FindOneofByName(
+ "oneof_field");
+
+ refl->SetString(message, string_field, "Test value");
+ EXPECT_TRUE(refl->HasOneof(*message, oneof));
+ refl->ClearOneof(message, oneof);
+ EXPECT_FALSE(refl->HasOneof(*message, oneof));
+
+ Message* submsg = refl->MutableMessage(message, msg_field);
+ EXPECT_TRUE(refl->HasOneof(*message, oneof));
+ refl->ClearOneof(message, oneof);
+ EXPECT_FALSE(refl->HasOneof(*message, oneof));
+ refl->MutableMessage(message, msg_field);
+ EXPECT_TRUE(refl->HasOneof(*message, oneof));
+ submsg = refl->ReleaseMessage(message, msg_field);
+ EXPECT_FALSE(refl->HasOneof(*message, oneof));
+ EXPECT_TRUE(submsg->GetArena() == NULL);
+ delete submsg;
+}
+
+namespace {
+void TestSwapRepeatedField(Arena* arena1, Arena* arena2) {
+ // Test "safe" (copying) semantics for direct Swap() on RepeatedPtrField
+ // between arenas.
+ RepeatedPtrField<TestAllTypes> field1(arena1);
+ RepeatedPtrField<TestAllTypes> field2(arena2);
+ for (int i = 0; i < 10; i++) {
+ TestAllTypes* t = Arena::CreateMessage<TestAllTypes>(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<TestAllTypes>(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<TestAllExtensions>(&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);
+}
+
+TEST(ArenaTest, RepeatedFieldOnArena) {
+ // Preallocate an initial arena block to avoid mallocs during hooked region.
+ std::vector<char> arena_block(1024 * 1024);
+ ArenaOptions options;
+ options.initial_block = &arena_block[0];
+ options.initial_block_size = arena_block.size();
+ Arena arena(options);
+
+ {
+ internal::NoHeapChecker no_heap;
+
+ // Fill some repeated fields on the arena to test for leaks. Also verify no
+ // memory allocations.
+ RepeatedField<int32> repeated_int32(&arena);
+ RepeatedPtrField<TestAllTypes> 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<TestAllTypes> 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<TestAllTypes>* repeated_ptr_on_arena =
+ Arena::CreateMessage< RepeatedPtrField<TestAllTypes> >(&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<int>* repeated_int_on_arena =
+ Arena::CreateMessage< RepeatedField<int> >(&arena);
+ for (int i = 0; i < 100; i++) {
+ repeated_int_on_arena->Add(i);
+ }
+
+ }
+
+ arena.Reset();
+}
+
+
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
+TEST(ArenaTest, MutableMessageReflection) {
+ Arena arena;
+ TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+ const Reflection* r = message->GetReflection();
+ const Descriptor* d = message->GetDescriptor();
+ const FieldDescriptor* field = d->FindFieldByName("optional_nested_message");
+ TestAllTypes::NestedMessage* submessage =
+ static_cast<TestAllTypes::NestedMessage*>(
+ 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 = static_cast<TestAllTypes::NestedMessage*>(
+ r->MutableMessage(message, oneof_field));
+ submessage_expected = message->mutable_oneof_nested_message();
+
+ EXPECT_EQ(submessage_expected, submessage);
+ EXPECT_EQ(&arena, submessage->GetArena());
+}
+#endif // !GOOGLE_PROTOBUF_NO_RTTI
+
+
+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<char> arena_block(128 * 1024);
+ ArenaOptions options;
+ options.initial_block = &arena_block[0];
+ options.initial_block_size = arena_block.size();
+ Arena arena(options);
+
+ {
+
+ TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+ FillArenaAwareFields(message);
+ }
+
+ arena.Reset();
+}
+
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
+// 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<char> arena_block(128 * 1024);
+ ArenaOptions options;
+ options.initial_block = &arena_block[0];
+ options.initial_block_size = arena_block.size();
+ Arena arena(options);
+ const google::protobuf::MessageLite* prototype = &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 = static_cast<TestAllTypes*>(generic_message);
+ EXPECT_EQ(42, deserialized->optional_int32());
+ }
+
+ arena.Reset();
+}
+#endif // !GOOGLE_PROTOBUF_NO_RTTI
+
+
+// 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<string> 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<string> field_on_arena(&arena);
+ for (int i = 0; i < 100; i++) {
+ *field_on_arena.Add() = "test string long enough to exceed inline buffer";
+ }
+ }
+}
+
+// Align n to next multiple of 8
+namespace {
+uint64 Align8(uint64 n) { return (n + 7) & -8; }
+} // namespace
+
+TEST(ArenaTest, SpaceAllocated_and_Used) {
+ ArenaOptions options;
+ options.start_block_size = 256;
+ options.max_block_size = 8192;
+ Arena arena_1(options);
+ EXPECT_EQ(0, arena_1.SpaceAllocated());
+ EXPECT_EQ(0, arena_1.SpaceUsed());
+ EXPECT_EQ(0, arena_1.Reset());
+ ::google::protobuf::Arena::CreateArray<char>(&arena_1, 320);
+ // Arena will allocate slightly more than 320 for the block headers.
+ EXPECT_LE(320, arena_1.SpaceAllocated());
+ EXPECT_EQ(Align8(320), arena_1.SpaceUsed());
+ EXPECT_LE(320, arena_1.Reset());
+
+ // Test with initial block.
+ std::vector<char> arena_block(1024);
+ options.initial_block = &arena_block[0];
+ options.initial_block_size = arena_block.size();
+ Arena arena_2(options);
+ EXPECT_EQ(1024, arena_2.SpaceAllocated());
+ EXPECT_EQ(0, arena_2.SpaceUsed());
+ EXPECT_EQ(1024, arena_2.Reset());
+ ::google::protobuf::Arena::CreateArray<char>(&arena_2, 55);
+ EXPECT_EQ(1024, arena_2.SpaceAllocated());
+ EXPECT_EQ(Align8(55), 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);
+ EXPECT_EQ(0, arena_3.SpaceUsed());
+ ::google::protobuf::Arena::CreateArray<char>(&arena_3, 190);
+ EXPECT_EQ(256, arena_3.SpaceAllocated());
+ EXPECT_EQ(Align8(190), arena_3.SpaceUsed());
+ ::google::protobuf::Arena::CreateArray<char>(&arena_3, 70);
+ EXPECT_EQ(256 + 512, arena_3.SpaceAllocated());
+ EXPECT_EQ(Align8(190) + Align8(70), 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<char>(&arena, i);
+ GOOGLE_CHECK_EQ(reinterpret_cast<uintptr_t>(p) % 8, 0) << i << ": " << p;
+ }
+}
+
+TEST(ArenaTest, GetArenaShouldReturnTheArenaForArenaAllocatedMessages) {
+ ::google::protobuf::Arena arena;
+ ArenaMessage* message = Arena::CreateMessage<ArenaMessage>(&arena);
+ const ArenaMessage* const_pointer_to_message = message;
+ EXPECT_EQ(&arena, Arena::GetArena(message));
+ EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message));
+}
+
+TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaAllocatedMessages) {
+ ArenaMessage message;
+ const ArenaMessage* const_pointer_to_message = &message;
+ EXPECT_EQ(NULL, Arena::GetArena(&message));
+ EXPECT_EQ(NULL, Arena::GetArena(const_pointer_to_message));
+}
+
+// A helper utility class to only contain static hook functions, some
+// counters to be used to verify the counters have been called and a cookie
+// value to be verified.
+class ArenaHooksTestUtil {
+ public:
+ static void* on_init(::google::protobuf::Arena* arena) {
+ ++num_init;
+ int* cookie = new int(kCookieValue);
+ return static_cast<void*>(cookie);
+ }
+
+ static void on_reset(::google::protobuf::Arena* arena, void* cookie,
+ uint64 space_used) {
+ ++num_reset;
+ int cookie_value = *static_cast<int*>(cookie);
+ EXPECT_EQ(kCookieValue, cookie_value);
+ }
+
+ static void on_destruction(::google::protobuf::Arena* arena, void* cookie,
+ uint64 space_used) {
+ ++num_destruct;
+ int cookie_value = *static_cast<int*>(cookie);
+ EXPECT_EQ(kCookieValue, cookie_value);
+ delete static_cast<int*>(cookie);
+ }
+
+ static const int kCookieValue = 999;
+ static uint32 num_init;
+ static uint32 num_reset;
+ static uint32 num_destruct;
+};
+uint32 ArenaHooksTestUtil::num_init = 0;
+uint32 ArenaHooksTestUtil::num_reset = 0;
+uint32 ArenaHooksTestUtil::num_destruct = 0;
+const int ArenaHooksTestUtil::kCookieValue;
+
+// Test the hooks are correctly called and that the cookie is passed.
+TEST(ArenaTest, ArenaHooksSanity) {
+ ::google::protobuf::ArenaOptions options;
+ options.on_arena_init = ArenaHooksTestUtil::on_init;
+ options.on_arena_reset = ArenaHooksTestUtil::on_reset;
+ options.on_arena_destruction = ArenaHooksTestUtil::on_destruction;
+
+ // Scope for defining the arena
+ {
+ ::google::protobuf::Arena arena(options);
+ EXPECT_EQ(1, ArenaHooksTestUtil::num_init);
+
+ arena.Reset();
+ arena.Reset();
+ EXPECT_EQ(2, ArenaHooksTestUtil::num_reset);
+ }
+ EXPECT_EQ(3, ArenaHooksTestUtil::num_reset);
+ EXPECT_EQ(1, ArenaHooksTestUtil::num_destruct);
+}
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/arenastring.cc b/src/google/protobuf/arenastring.cc
new file mode 100644
index 00000000..cce61d74
--- /dev/null
+++ b/src/google/protobuf/arenastring.cc
@@ -0,0 +1,53 @@
+// 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 <google/protobuf/arenastring.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+
+void ArenaStringPtr::AssignWithDefault(const ::std::string* default_value,
+ ArenaStringPtr value) {
+ const ::std::string* me = *UnsafeRawStringPointer();
+ const ::std::string* other = *value.UnsafeRawStringPointer();
+ // If the pointers are the same then do nothing.
+ if (me != other) {
+ SetNoArena(default_value, value.GetNoArena(default_value));
+ }
+}
+
+} // 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..d829ed91
--- /dev/null
+++ b/src/google/protobuf/arenastring.h
@@ -0,0 +1,315 @@
+// 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 <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/fastmem.h>
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_message_util.h>
+
+
+
+// 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 LIBPROTOBUF_EXPORT 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_<field>() 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_<field>() 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_<field> 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_<field> 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;
+ }
+ }
+
+ void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr 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 <google/protobuf/arenastring.h>
+
+#include <string>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <cstdlib>
+
+#include <google/protobuf/stubs/common.h>
+#include <gtest/gtest.h>
+
+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/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc
index 455c239a..0039b00a 100644
--- a/src/google/protobuf/compiler/code_generator.cc
+++ b/src/google/protobuf/compiler/code_generator.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -44,6 +44,11 @@ namespace compiler {
CodeGenerator::~CodeGenerator() {}
GeneratorContext::~GeneratorContext() {}
+io::ZeroCopyOutputStream*
+GeneratorContext::OpenForAppend(const string& filename) {
+ return NULL;
+}
+
io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
const string& filename, const string& insertion_point) {
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion.";
@@ -58,8 +63,7 @@ void GeneratorContext::ListParsedFiles(
// Parses a set of comma-delimited name/value pairs.
void ParseGeneratorParameter(const string& text,
vector<pair<string, string> >* output) {
- vector<string> parts;
- SplitStringUsing(text, ",", &parts);
+ vector<string> parts = Split(text, ",", true);
for (int i = 0; i < parts.size(); i++) {
string::size_type equals_pos = parts[i].find_first_of('=');
diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h
index 252f68d1..321a8ccd 100644
--- a/src/google/protobuf/compiler/code_generator.h
+++ b/src/google/protobuf/compiler/code_generator.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -104,6 +104,9 @@ class LIBPROTOC_EXPORT GeneratorContext {
// contain "." or ".." components.
virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0;
+ // Similar to Open() but the output will be appended to the file if exists
+ virtual io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
+
// Creates a ZeroCopyOutputStream which will insert code into the given file
// at the given insertion point. See plugin.proto (plugin.pb.h) for more
// information on insertion points. The default implementation
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 1c76994b..567238ae 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -48,9 +48,13 @@
#include <iostream>
#include <ctype.h>
-#include <google/protobuf/stubs/hash.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.pb.h>
@@ -59,12 +63,13 @@
#include <google/protobuf/descriptor.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
-#include <google/protobuf/stubs/map-util.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
@@ -145,8 +150,8 @@ void AddTrailingSlash(string* path) {
bool VerifyDirectoryExists(const string& path) {
if (path.empty()) return true;
- if (access(path.c_str(), W_OK) == -1) {
- cerr << path << ": " << strerror(errno) << endl;
+ if (access(path.c_str(), F_OK) == -1) {
+ std::cerr << path << ": " << strerror(errno) << std::endl;
return false;
} else {
return true;
@@ -159,15 +164,14 @@ bool VerifyDirectoryExists(const string& path) {
// directories listed in |filename|.
bool TryCreateParentDirectory(const string& prefix, const string& filename) {
// Recursively create parent directories to the output file.
- vector<string> parts;
- SplitStringUsing(filename, "/", &parts);
+ vector<string> parts = Split(filename, "/", true);
string path_so_far = prefix;
for (int i = 0; i < parts.size() - 1; i++) {
path_so_far += parts[i];
if (mkdir(path_so_far.c_str(), 0777) != 0) {
if (errno != EEXIST) {
- cerr << filename << ": while trying to create directory "
- << path_so_far << ": " << strerror(errno) << endl;
+ std::cerr << filename << ": while trying to create directory "
+ << path_so_far << ": " << strerror(errno) << std::endl;
return false;
}
}
@@ -196,9 +200,9 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
tree_ != NULL &&
tree_->VirtualFileToDiskFile(filename, &dfile)) {
- cerr << dfile;
+ std::cerr << dfile;
} else {
- cerr << filename;
+ std::cerr << filename;
}
// Users typically expect 1-based line/column numbers, so we add 1
@@ -207,15 +211,16 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
// Allow for both GCC- and Visual-Studio-compatible output.
switch (format_) {
case CommandLineInterface::ERROR_FORMAT_GCC:
- cerr << ":" << (line + 1) << ":" << (column + 1);
+ std::cerr << ":" << (line + 1) << ":" << (column + 1);
break;
case CommandLineInterface::ERROR_FORMAT_MSVS:
- cerr << "(" << (line + 1) << ") : error in column=" << (column + 1);
+ std::cerr << "(" << (line + 1)
+ << ") : error in column=" << (column + 1);
break;
}
}
- cerr << ": " << message << endl;
+ std::cerr << ": " << message << std::endl;
}
// implements io::ErrorCollector -----------------------------------
@@ -249,8 +254,12 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
// format, unless one has already been written.
void AddJarManifest();
+ // Get name of all output files.
+ void GetOutputFilenames(vector<string>* output_filenames);
+
// implements GeneratorContext --------------------------------------
io::ZeroCopyOutputStream* Open(const string& filename);
+ io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
io::ZeroCopyOutputStream* OpenForInsert(
const string& filename, const string& insertion_point);
void ListParsedFiles(vector<const FileDescriptor*>* output) {
@@ -270,7 +279,8 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
class CommandLineInterface::MemoryOutputStream
: public io::ZeroCopyOutputStream {
public:
- MemoryOutputStream(GeneratorContextImpl* directory, const string& filename);
+ MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
+ bool append_mode);
MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
const string& insertion_point);
virtual ~MemoryOutputStream();
@@ -289,8 +299,11 @@ class CommandLineInterface::MemoryOutputStream
// The string we're building.
string data_;
+ // Whether we should append the output stream to the existing file.
+ bool append_mode_;
+
// StringOutputStream writing to data_.
- scoped_ptr<io::StringOutputStream> inner_;
+ google::protobuf::scoped_ptr<io::StringOutputStream> inner_;
};
// -------------------------------------------------------------------
@@ -335,7 +348,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
if (file_descriptor < 0) {
int error = errno;
- cerr << filename << ": " << strerror(error);
+ std::cerr << filename << ": " << strerror(error);
return false;
}
@@ -359,9 +372,9 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
if (write_result < 0) {
int error = errno;
- cerr << filename << ": write: " << strerror(error);
+ std::cerr << filename << ": write: " << strerror(error);
} else {
- cerr << filename << ": write() returned zero?" << endl;
+ std::cerr << filename << ": write() returned zero?" << std::endl;
}
return false;
}
@@ -372,7 +385,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
if (close(file_descriptor) != 0) {
int error = errno;
- cerr << filename << ": close: " << strerror(error);
+ std::cerr << filename << ": close: " << strerror(error);
return false;
}
}
@@ -395,7 +408,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
if (file_descriptor < 0) {
int error = errno;
- cerr << filename << ": " << strerror(error);
+ std::cerr << filename << ": " << strerror(error);
return false;
}
@@ -411,11 +424,11 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
zip_writer.WriteDirectory();
if (stream.GetErrno() != 0) {
- cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
+ std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
}
if (!stream.Close()) {
- cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
+ std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
}
return true;
@@ -431,9 +444,23 @@ void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
}
}
+void CommandLineInterface::GeneratorContextImpl::GetOutputFilenames(
+ vector<string>* output_filenames) {
+ for (map<string, string*>::iterator iter = files_.begin();
+ iter != files_.end(); ++iter) {
+ output_filenames->push_back(iter->first);
+ }
+}
+
io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
const string& filename) {
- return new MemoryOutputStream(this, filename);
+ return new MemoryOutputStream(this, filename, false);
+}
+
+io::ZeroCopyOutputStream*
+CommandLineInterface::GeneratorContextImpl::OpenForAppend(
+ const string& filename) {
+ return new MemoryOutputStream(this, filename, true);
}
io::ZeroCopyOutputStream*
@@ -445,9 +472,10 @@ CommandLineInterface::GeneratorContextImpl::OpenForInsert(
// -------------------------------------------------------------------
CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
- GeneratorContextImpl* directory, const string& filename)
+ GeneratorContextImpl* directory, const string& filename, bool append_mode)
: directory_(directory),
filename_(filename),
+ append_mode_(append_mode),
inner_(new io::StringOutputStream(&data_)) {
}
@@ -470,8 +498,13 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
if (insertion_point_.empty()) {
// This was just a regular Open().
if (*map_slot != NULL) {
- cerr << filename_ << ": Tried to write the same file twice." << endl;
- directory_->had_error_ = true;
+ if (append_mode_) {
+ (*map_slot)->append(data_);
+ } else {
+ std::cerr << filename_ << ": Tried to write the same file twice."
+ << std::endl;
+ directory_->had_error_ = true;
+ }
return;
}
@@ -487,8 +520,9 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
// Find the file we are going to insert into.
if (*map_slot == NULL) {
- cerr << filename_ << ": Tried to insert into file that doesn't exist."
- << endl;
+ std::cerr << filename_
+ << ": Tried to insert into file that doesn't exist."
+ << std::endl;
directory_->had_error_ = true;
return;
}
@@ -500,8 +534,8 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
string::size_type pos = target->find(magic_string);
if (pos == string::npos) {
- cerr << filename_ << ": insertion point \"" << insertion_point_
- << "\" not found." << endl;
+ std::cerr << filename_ << ": insertion point \"" << insertion_point_
+ << "\" not found." << std::endl;
directory_->had_error_ = true;
return;
}
@@ -564,8 +598,10 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
CommandLineInterface::CommandLineInterface()
: mode_(MODE_COMPILE),
+ print_mode_(PRINT_NONE),
error_format_(ERROR_FORMAT_GCC),
imports_in_descriptor_set_(false),
+ source_info_in_descriptor_set_(false),
disallow_services_(false),
inputs_are_proto_path_relative_(false) {}
CommandLineInterface::~CommandLineInterface() {}
@@ -574,9 +610,23 @@ void CommandLineInterface::RegisterGenerator(const string& flag_name,
CodeGenerator* generator,
const string& help_text) {
GeneratorInfo info;
+ info.flag_name = flag_name;
+ info.generator = generator;
+ info.help_text = help_text;
+ generators_by_flag_name_[flag_name] = info;
+}
+
+void CommandLineInterface::RegisterGenerator(const string& flag_name,
+ const string& option_flag_name,
+ CodeGenerator* generator,
+ const string& help_text) {
+ GeneratorInfo info;
+ info.flag_name = flag_name;
+ info.option_flag_name = option_flag_name;
info.generator = generator;
info.help_text = help_text;
- generators_[flag_name] = info;
+ generators_by_flag_name_[flag_name] = info;
+ generators_by_option_name_[option_flag_name] = info;
}
void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) {
@@ -585,7 +635,14 @@ void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) {
int CommandLineInterface::Run(int argc, const char* const argv[]) {
Clear();
- if (!ParseArguments(argc, argv)) return 1;
+ switch (ParseArguments(argc, argv)) {
+ case PARSE_ARGUMENT_DONE_AND_EXIT:
+ return 0;
+ case PARSE_ARGUMENT_FAIL:
+ return 1;
+ case PARSE_ARGUMENT_DONE_AND_CONTINUE:
+ break;
+ }
// Set up the source tree.
DiskSourceTree source_tree;
@@ -609,7 +666,9 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
// Parse each file.
for (int i = 0; i < input_files_.size(); i++) {
// Import the file.
+ importer.AddUnusedImportTrackFile(input_files_[i]);
const FileDescriptor* parsed_file = importer.Import(input_files_[i]);
+ importer.ClearUnusedImportTrackFiles();
if (parsed_file == NULL) return 1;
parsed_files.push_back(parsed_file);
@@ -624,7 +683,6 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
// We construct a separate GeneratorContext for each output location. Note
// that two code generators may output to the same location, in which case
// they should share a single GeneratorContext so that OpenForInsert() works.
- typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
GeneratorContextMap output_directories;
// Generate output.
@@ -671,6 +729,13 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
}
}
+ if (!dependency_out_name_.empty()) {
+ if (!GenerateDependencyManifestFile(parsed_files, output_directories,
+ &source_tree)) {
+ return 1;
+ }
+ }
+
STLDeleteValues(&output_directories);
if (!descriptor_set_name_.empty()) {
@@ -698,6 +763,25 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
}
}
+ if (mode_ == MODE_PRINT) {
+ switch (print_mode_) {
+ case PRINT_FREE_FIELDS:
+ for (int i = 0; i < parsed_files.size(); ++i) {
+ const FileDescriptor* fd = parsed_files[i];
+ for (int j = 0; j < fd->message_type_count(); ++j) {
+ PrintFreeFieldNumbers(fd->message_type(j));
+ }
+ }
+ break;
+ case PRINT_NONE:
+ GOOGLE_LOG(ERROR) << "If the code reaches here, it usually means a bug of "
+ "flag parsing in the CommonadLineInterface.";
+ return 1;
+
+ // Do not add a default case.
+ }
+ }
+
return 0;
}
@@ -710,9 +794,12 @@ void CommandLineInterface::Clear() {
output_directives_.clear();
codec_type_.clear();
descriptor_set_name_.clear();
+ dependency_out_name_.clear();
mode_ = MODE_COMPILE;
+ print_mode_ = PRINT_NONE;
imports_in_descriptor_set_ = false;
+ source_info_in_descriptor_set_ = false;
disallow_services_ = false;
}
@@ -726,27 +813,31 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative(
input_files_[i] = virtual_file;
break;
case DiskSourceTree::SHADOWED:
- cerr << input_files_[i] << ": Input is shadowed in the --proto_path "
- "by \"" << shadowing_disk_file << "\". Either use the latter "
- "file as your input or reorder the --proto_path so that the "
- "former file's location comes first." << endl;
+ std::cerr << input_files_[i]
+ << ": Input is shadowed in the --proto_path by \""
+ << shadowing_disk_file
+ << "\". Either use the latter file as your input or reorder "
+ "the --proto_path so that the former file's location "
+ "comes first." << std::endl;
return false;
case DiskSourceTree::CANNOT_OPEN:
- cerr << input_files_[i] << ": " << strerror(errno) << endl;
+ std::cerr << input_files_[i] << ": " << strerror(errno) << std::endl;
return false;
case DiskSourceTree::NO_MAPPING:
// First check if the file exists at all.
if (access(input_files_[i].c_str(), F_OK) < 0) {
// File does not even exist.
- cerr << input_files_[i] << ": " << strerror(ENOENT) << endl;
+ std::cerr << input_files_[i] << ": " << strerror(ENOENT) << std::endl;
} else {
- cerr << input_files_[i] << ": File does not reside within any path "
- "specified using --proto_path (or -I). You must specify a "
- "--proto_path which encompasses this file. Note that the "
- "proto_path must be an exact prefix of the .proto file "
- "names -- protoc is too dumb to figure out when two paths "
- "(e.g. absolute and relative) are equivalent (it's harder "
- "than you think)." << endl;
+ std::cerr
+ << input_files_[i]
+ << ": File does not reside within any path "
+ "specified using --proto_path (or -I). You must specify a "
+ "--proto_path which encompasses this file. Note that the "
+ "proto_path must be an exact prefix of the .proto file "
+ "names -- protoc is too dumb to figure out when two paths "
+ "(e.g. absolute and relative) are equivalent (it's harder "
+ "than you think)." << std::endl;
}
return false;
}
@@ -755,7 +846,8 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative(
return true;
}
-bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
+CommandLineInterface::ParseArgumentStatus
+CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
executable_name_ = argv[0];
// Iterate through all arguments and parse them.
@@ -765,45 +857,65 @@ bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
if (ParseArgument(argv[i], &name, &value)) {
// Returned true => Use the next argument as the flag value.
if (i + 1 == argc || argv[i+1][0] == '-') {
- cerr << "Missing value for flag: " << name << endl;
+ std::cerr << "Missing value for flag: " << name << std::endl;
if (name == "--decode") {
- cerr << "To decode an unknown message, use --decode_raw." << endl;
+ std::cerr << "To decode an unknown message, use --decode_raw."
+ << std::endl;
}
- return false;
+ return PARSE_ARGUMENT_FAIL;
} else {
++i;
value = argv[i];
}
}
- if (!InterpretArgument(name, value)) return false;
+ ParseArgumentStatus status = InterpretArgument(name, value);
+ if (status != PARSE_ARGUMENT_DONE_AND_CONTINUE)
+ return status;
}
// If no --proto_path was given, use the current working directory.
if (proto_path_.empty()) {
- proto_path_.push_back(make_pair<string, string>("", "."));
+ // Don't use make_pair as the old/default standard library on Solaris
+ // doesn't support it without explicit template parameters, which are
+ // incompatible with C++0x's make_pair.
+ proto_path_.push_back(pair<string, string>("", "."));
}
// Check some errror cases.
bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
if (decoding_raw && !input_files_.empty()) {
- cerr << "When using --decode_raw, no input files should be given." << endl;
- return false;
+ std::cerr << "When using --decode_raw, no input files should be given."
+ << std::endl;
+ return PARSE_ARGUMENT_FAIL;
} else if (!decoding_raw && input_files_.empty()) {
- cerr << "Missing input file." << endl;
- return false;
+ std::cerr << "Missing input file." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
if (mode_ == MODE_COMPILE && output_directives_.empty() &&
descriptor_set_name_.empty()) {
- cerr << "Missing output directives." << endl;
- return false;
+ std::cerr << "Missing output directives." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ if (mode_ != MODE_COMPILE && !dependency_out_name_.empty()) {
+ cerr << "Can only use --dependency_out=FILE when generating code." << endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ if (!dependency_out_name_.empty() && input_files_.size() > 1) {
+ cerr << "Can only process one input file when using --dependency_out=FILE."
+ << endl;
+ return PARSE_ARGUMENT_FAIL;
}
if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
- cerr << "--include_imports only makes sense when combined with "
- "--descriptor_set_out." << endl;
+ std::cerr << "--include_imports only makes sense when combined with "
+ "--descriptor_set_out." << std::endl;
+ }
+ if (source_info_in_descriptor_set_ && descriptor_set_name_.empty()) {
+ std::cerr << "--include_source_info only makes sense when combined with "
+ "--descriptor_set_out." << std::endl;
}
- return true;
+ return PARSE_ARGUMENT_DONE_AND_CONTINUE;
}
bool CommandLineInterface::ParseArgument(const char* arg,
@@ -853,8 +965,10 @@ bool CommandLineInterface::ParseArgument(const char* arg,
if (*name == "-h" || *name == "--help" ||
*name == "--disallow_services" ||
*name == "--include_imports" ||
+ *name == "--include_source_info" ||
*name == "--version" ||
- *name == "--decode_raw") {
+ *name == "--decode_raw" ||
+ *name == "--print_free_field_numbers") {
// HACK: These are the only flags that don't take a value.
// They probably should not be hard-coded like this but for now it's
// not worth doing better.
@@ -865,16 +979,19 @@ bool CommandLineInterface::ParseArgument(const char* arg,
return true;
}
-bool CommandLineInterface::InterpretArgument(const string& name,
- const string& value) {
+CommandLineInterface::ParseArgumentStatus
+CommandLineInterface::InterpretArgument(const string& name,
+ const string& value) {
if (name.empty()) {
// Not a flag. Just a filename.
if (value.empty()) {
- cerr << "You seem to have passed an empty string as one of the "
- "arguments to " << executable_name_ << ". This is actually "
- "sort of hard to do. Congrats. Unfortunately it is not valid "
- "input so the program is going to die now." << endl;
- return false;
+ std::cerr
+ << "You seem to have passed an empty string as one of the "
+ "arguments to " << executable_name_
+ << ". This is actually "
+ "sort of hard to do. Congrats. Unfortunately it is not valid "
+ "input so the program is going to die now." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
input_files_.push_back(value);
@@ -883,14 +1000,14 @@ bool CommandLineInterface::InterpretArgument(const string& name,
// Java's -classpath (and some other languages) delimits path components
// with colons. Let's accept that syntax too just to make things more
// intuitive.
- vector<string> parts;
- SplitStringUsing(value, kPathSeparator, &parts);
+ vector<string> parts = Split(
+ value, kPathSeparator, true);
for (int i = 0; i < parts.size(); i++) {
string virtual_path;
string disk_path;
- int equals_pos = parts[i].find_first_of('=');
+ string::size_type equals_pos = parts[i].find_first_of('=');
if (equals_pos == string::npos) {
virtual_path = "";
disk_path = parts[i];
@@ -900,54 +1017,78 @@ bool CommandLineInterface::InterpretArgument(const string& name,
}
if (disk_path.empty()) {
- cerr << "--proto_path passed empty directory name. (Use \".\" for "
- "current directory.)" << endl;
- return false;
+ std::cerr
+ << "--proto_path passed empty directory name. (Use \".\" for "
+ "current directory.)" << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
// Make sure disk path exists, warn otherwise.
if (access(disk_path.c_str(), F_OK) < 0) {
- cerr << disk_path << ": warning: directory does not exist." << endl;
+ std::cerr << disk_path << ": warning: directory does not exist."
+ << std::endl;
}
- proto_path_.push_back(make_pair<string, string>(virtual_path, disk_path));
+ // Don't use make_pair as the old/default standard library on Solaris
+ // doesn't support it without explicit template parameters, which are
+ // incompatible with C++0x's make_pair.
+ proto_path_.push_back(pair<string, string>(virtual_path, disk_path));
}
} else if (name == "-o" || name == "--descriptor_set_out") {
if (!descriptor_set_name_.empty()) {
- cerr << name << " may only be passed once." << endl;
- return false;
+ std::cerr << name << " may only be passed once." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
if (value.empty()) {
- cerr << name << " requires a non-empty value." << endl;
- return false;
+ std::cerr << name << " requires a non-empty value." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
if (mode_ != MODE_COMPILE) {
- cerr << "Cannot use --encode or --decode and generate descriptors at the "
- "same time." << endl;
- return false;
+ std::cerr
+ << "Cannot use --encode or --decode and generate descriptors at the "
+ "same time." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
descriptor_set_name_ = value;
+ } else if (name == "--dependency_out") {
+ if (!dependency_out_name_.empty()) {
+ cerr << name << " may only be passed once." << endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ if (value.empty()) {
+ cerr << name << " requires a non-empty value." << endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ dependency_out_name_ = value;
+
} else if (name == "--include_imports") {
if (imports_in_descriptor_set_) {
- cerr << name << " may only be passed once." << endl;
- return false;
+ std::cerr << name << " may only be passed once." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
imports_in_descriptor_set_ = true;
+ } else if (name == "--include_source_info") {
+ if (source_info_in_descriptor_set_) {
+ std::cerr << name << " may only be passed once." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ source_info_in_descriptor_set_ = true;
+
} else if (name == "-h" || name == "--help") {
PrintHelpText();
- return false; // Exit without running compiler.
+ return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
} else if (name == "--version") {
if (!version_info_.empty()) {
- cout << version_info_ << endl;
+ std::cout << version_info_ << std::endl;
}
cout << "libprotoc "
<< protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
<< endl;
- return false; // Exit without running compiler.
+ return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
} else if (name == "--disallow_services") {
disallow_services_ = true;
@@ -955,26 +1096,29 @@ bool CommandLineInterface::InterpretArgument(const string& name,
} else if (name == "--encode" || name == "--decode" ||
name == "--decode_raw") {
if (mode_ != MODE_COMPILE) {
- cerr << "Only one of --encode and --decode can be specified." << endl;
- return false;
+ std::cerr << "Only one of --encode and --decode can be specified."
+ << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
- cerr << "Cannot use " << name
- << " and generate code or descriptors at the same time." << endl;
- return false;
+ std::cerr << "Cannot use " << name
+ << " and generate code or descriptors at the same time."
+ << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
if (value.empty() && name != "--decode_raw") {
- cerr << "Type name for " << name << " cannot be blank." << endl;
+ std::cerr << "Type name for " << name << " cannot be blank." << std::endl;
if (name == "--decode") {
- cerr << "To decode an unknown message, use --decode_raw." << endl;
+ std::cerr << "To decode an unknown message, use --decode_raw."
+ << std::endl;
}
- return false;
+ return PARSE_ARGUMENT_FAIL;
} else if (!value.empty() && name == "--decode_raw") {
- cerr << "--decode_raw does not take a parameter." << endl;
- return false;
+ std::cerr << "--decode_raw does not take a parameter." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
codec_type_ = value;
@@ -985,17 +1129,17 @@ bool CommandLineInterface::InterpretArgument(const string& name,
} else if (value == "msvs") {
error_format_ = ERROR_FORMAT_MSVS;
} else {
- cerr << "Unknown error format: " << value << endl;
- return false;
+ std::cerr << "Unknown error format: " << value << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
} else if (name == "--plugin") {
if (plugin_prefix_.empty()) {
- cerr << "This compiler does not support plugins." << endl;
- return false;
+ std::cerr << "This compiler does not support plugins." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
}
- string name;
+ string plugin_name;
string path;
string::size_type equals_pos = value.find_first_of('=');
@@ -1003,62 +1147,88 @@ bool CommandLineInterface::InterpretArgument(const string& name,
// Use the basename of the file.
string::size_type slash_pos = value.find_last_of('/');
if (slash_pos == string::npos) {
- name = value;
+ plugin_name = value;
} else {
- name = value.substr(slash_pos + 1);
+ plugin_name = value.substr(slash_pos + 1);
}
path = value;
} else {
- name = value.substr(0, equals_pos);
+ plugin_name = value.substr(0, equals_pos);
path = value.substr(equals_pos + 1);
}
- plugins_[name] = path;
+ plugins_[plugin_name] = path;
+ } else if (name == "--print_free_field_numbers") {
+ if (mode_ != MODE_COMPILE) {
+ std::cerr << "Cannot use " << name
+ << " and use --encode, --decode or print "
+ << "other info at the same time." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
+ std::cerr << "Cannot use " << name
+ << " and generate code or descriptors at the same time."
+ << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ mode_ = MODE_PRINT;
+ print_mode_ = PRINT_FREE_FIELDS;
} else {
// Some other flag. Look it up in the generators list.
- const GeneratorInfo* generator_info = FindOrNull(generators_, name);
+ const GeneratorInfo* generator_info =
+ FindOrNull(generators_by_flag_name_, name);
if (generator_info == NULL &&
(plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
- cerr << "Unknown flag: " << name << endl;
- return false;
- }
+ // Check if it's a generator option flag.
+ generator_info = FindOrNull(generators_by_option_name_, name);
+ if (generator_info == NULL) {
+ std::cerr << "Unknown flag: " << name << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ } else {
+ string* parameters = &generator_parameters_[generator_info->flag_name];
+ if (!parameters->empty()) {
+ parameters->append(",");
+ }
+ parameters->append(value);
+ }
+ } else {
+ // It's an output flag. Add it to the output directives.
+ if (mode_ != MODE_COMPILE) {
+ std::cerr << "Cannot use --encode, --decode or print .proto info and "
+ "generate code at the same time." << std::endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
- // It's an output flag. Add it to the output directives.
- if (mode_ != MODE_COMPILE) {
- cerr << "Cannot use --encode or --decode and generate code at the "
- "same time." << endl;
- return false;
- }
+ OutputDirective directive;
+ directive.name = name;
+ if (generator_info == NULL) {
+ directive.generator = NULL;
+ } else {
+ directive.generator = generator_info->generator;
+ }
- OutputDirective directive;
- directive.name = name;
- if (generator_info == NULL) {
- directive.generator = NULL;
- } else {
- directive.generator = generator_info->generator;
- }
+ // Split value at ':' to separate the generator parameter from the
+ // filename. However, avoid doing this if the colon is part of a valid
+ // Windows-style absolute path.
+ string::size_type colon_pos = value.find_first_of(':');
+ if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) {
+ directive.output_location = value;
+ } else {
+ directive.parameter = value.substr(0, colon_pos);
+ directive.output_location = value.substr(colon_pos + 1);
+ }
- // Split value at ':' to separate the generator parameter from the
- // filename. However, avoid doing this if the colon is part of a valid
- // Windows-style absolute path.
- string::size_type colon_pos = value.find_first_of(':');
- if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) {
- directive.output_location = value;
- } else {
- directive.parameter = value.substr(0, colon_pos);
- directive.output_location = value.substr(colon_pos + 1);
+ output_directives_.push_back(directive);
}
-
- output_directives_.push_back(directive);
}
- return true;
+ return PARSE_ARGUMENT_DONE_AND_CONTINUE;
}
void CommandLineInterface::PrintHelpText() {
// Sorry for indentation here; line wrapping would be uglier.
- cerr <<
+ std::cerr <<
"Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n"
"Parse PROTO_FILES and generate output based on the options given:\n"
" -IPATH, --proto_path=PATH Specify the directory in which to search for\n"
@@ -1086,11 +1256,25 @@ void CommandLineInterface::PrintHelpText() {
" --include_imports When using --descriptor_set_out, also include\n"
" all dependencies of the input files in the\n"
" set, so that the set is self-contained.\n"
+" --include_source_info When using --descriptor_set_out, do not strip\n"
+" SourceCodeInfo from the FileDescriptorProto.\n"
+" This results in vastly larger descriptors that\n"
+" include information about the original\n"
+" location of each decl in the source file as\n"
+" well as surrounding comments.\n"
+" --dependency_out=FILE Write a dependency output file in the format\n"
+" expected by make. This writes the transitive\n"
+" set of input file paths to FILE\n"
" --error_format=FORMAT Set the format in which to print errors.\n"
" FORMAT may be 'gcc' (the default) or 'msvs'\n"
-" (Microsoft Visual Studio format)." << endl;
+" (Microsoft Visual Studio format).\n"
+" --print_free_field_numbers Print the free field numbers of the messages\n"
+" defined in the given proto files. Groups share\n"
+" the same field number space with the parent \n"
+" message. Extension ranges are counted as \n"
+" occupied fields numbers." << std::endl;
if (!plugin_prefix_.empty()) {
- cerr <<
+ std::cerr <<
" --plugin=EXECUTABLE Specifies a plugin executable to use.\n"
" Normally, protoc searches the PATH for\n"
" plugins, but you may specify additional\n"
@@ -1098,17 +1282,17 @@ void CommandLineInterface::PrintHelpText() {
" Additionally, EXECUTABLE may be of the form\n"
" NAME=PATH, in which case the given plugin name\n"
" is mapped to the given executable even if\n"
-" the executable's own name differs." << endl;
+" the executable's own name differs." << std::endl;
}
- for (GeneratorMap::iterator iter = generators_.begin();
- iter != generators_.end(); ++iter) {
+ for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
+ iter != generators_by_flag_name_.end(); ++iter) {
// FIXME(kenton): If the text is long enough it will wrap, which is ugly,
// but fixing this nicely (e.g. splitting on spaces) is probably more
// trouble than it's worth.
- cerr << " " << iter->first << "=OUT_DIR "
- << string(19 - iter->first.size(), ' ') // Spaces for alignment.
- << iter->second.help_text << endl;
+ std::cerr << " " << iter->first << "=OUT_DIR "
+ << string(19 - iter->first.size(), ' ') // Spaces for alignment.
+ << iter->second.help_text << std::endl;
}
}
@@ -1131,18 +1315,24 @@ bool CommandLineInterface::GenerateOutput(
if (!GeneratePluginOutput(parsed_files, plugin_name,
output_directive.parameter,
generator_context, &error)) {
- cerr << output_directive.name << ": " << error << endl;
+ std::cerr << output_directive.name << ": " << error << std::endl;
return false;
}
} else {
// Regular generator.
+ string parameters = output_directive.parameter;
+ if (!generator_parameters_[output_directive.name].empty()) {
+ if (!parameters.empty()) {
+ parameters.append(",");
+ }
+ parameters.append(generator_parameters_[output_directive.name]);
+ }
for (int i = 0; i < parsed_files.size(); i++) {
- if (!output_directive.generator->Generate(
- parsed_files[i], output_directive.parameter,
- generator_context, &error)) {
+ if (!output_directive.generator->Generate(parsed_files[i], parameters,
+ generator_context, &error)) {
// Generator returned an error.
- cerr << output_directive.name << ": " << parsed_files[i]->name() << ": "
- << error << endl;
+ std::cerr << output_directive.name << ": " << parsed_files[i]->name()
+ << ": " << error << std::endl;
return false;
}
}
@@ -1151,6 +1341,76 @@ bool CommandLineInterface::GenerateOutput(
return true;
}
+bool CommandLineInterface::GenerateDependencyManifestFile(
+ const vector<const FileDescriptor*>& parsed_files,
+ const GeneratorContextMap& output_directories,
+ DiskSourceTree* source_tree) {
+ FileDescriptorSet file_set;
+
+ set<const FileDescriptor*> already_seen;
+ for (int i = 0; i < parsed_files.size(); i++) {
+ GetTransitiveDependencies(parsed_files[i],
+ false,
+ &already_seen,
+ file_set.mutable_file());
+ }
+
+ vector<string> output_filenames;
+ for (GeneratorContextMap::const_iterator iter = output_directories.begin();
+ iter != output_directories.end(); ++iter) {
+ const string& location = iter->first;
+ GeneratorContextImpl* directory = iter->second;
+ vector<string> relative_output_filenames;
+ directory->GetOutputFilenames(&relative_output_filenames);
+ for (int i = 0; i < relative_output_filenames.size(); i++) {
+ string output_filename = location + relative_output_filenames[i];
+ if (output_filename.compare(0, 2, "./") == 0) {
+ output_filename = output_filename.substr(2);
+ }
+ output_filenames.push_back(output_filename);
+ }
+ }
+
+ int fd;
+ do {
+ fd = open(dependency_out_name_.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ } while (fd < 0 && errno == EINTR);
+
+ if (fd < 0) {
+ perror(dependency_out_name_.c_str());
+ return false;
+ }
+
+ io::FileOutputStream out(fd);
+ io::Printer printer(&out, '$');
+
+ for (int i = 0; i < output_filenames.size(); i++) {
+ printer.Print(output_filenames[i].c_str());
+ if (i == output_filenames.size() - 1) {
+ printer.Print(":");
+ } else {
+ printer.Print(" \\\n");
+ }
+ }
+
+ for (int i = 0; i < file_set.file_size(); i++) {
+ const FileDescriptorProto& file = file_set.file(i);
+ const string& virtual_file = file.name();
+ string disk_file;
+ if (source_tree &&
+ source_tree->VirtualFileToDiskFile(virtual_file, &disk_file)) {
+ printer.Print(" $disk_file$", "disk_file", disk_file);
+ if (i < file_set.file_size() - 1) printer.Print("\\\n");
+ } else {
+ cerr << "Unable to identify path for file " << virtual_file << endl;
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool CommandLineInterface::GeneratePluginOutput(
const vector<const FileDescriptor*>& parsed_files,
const string& plugin_name,
@@ -1168,8 +1428,9 @@ bool CommandLineInterface::GeneratePluginOutput(
set<const FileDescriptor*> already_seen;
for (int i = 0; i < parsed_files.size(); i++) {
request.add_file_to_generate(parsed_files[i]->name());
- GetTransitiveDependencies(parsed_files[i], &already_seen,
- request.mutable_proto_file());
+ GetTransitiveDependencies(parsed_files[i],
+ true, // Include source code info.
+ &already_seen, request.mutable_proto_file());
}
// Invoke the plugin.
@@ -1189,7 +1450,7 @@ bool CommandLineInterface::GeneratePluginOutput(
// Write the files. We do this even if there was a generator error in order
// to match the behavior of a compiled-in generator.
- scoped_ptr<io::ZeroCopyOutputStream> current_output;
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> current_output;
for (int i = 0; i < response.file_size(); i++) {
const CodeGeneratorResponse::File& output_file = response.file(i);
@@ -1233,12 +1494,12 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
// Look up the type.
const Descriptor* type = pool->FindMessageTypeByName(codec_type_);
if (type == NULL) {
- cerr << "Type not defined: " << codec_type_ << endl;
+ std::cerr << "Type not defined: " << codec_type_ << std::endl;
return false;
}
DynamicMessageFactory dynamic_factory(pool);
- scoped_ptr<Message> message(dynamic_factory.GetPrototype(type)->New());
+ google::protobuf::scoped_ptr<Message> message(dynamic_factory.GetPrototype(type)->New());
if (mode_ == MODE_ENCODE) {
SetFdToTextMode(STDIN_FILENO);
@@ -1259,32 +1520,32 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
parser.AllowPartialMessage(true);
if (!parser.Parse(&in, message.get())) {
- cerr << "Failed to parse input." << endl;
+ std::cerr << "Failed to parse input." << std::endl;
return false;
}
} else {
// Input is binary.
if (!message->ParsePartialFromZeroCopyStream(&in)) {
- cerr << "Failed to parse input." << endl;
+ std::cerr << "Failed to parse input." << std::endl;
return false;
}
}
if (!message->IsInitialized()) {
- cerr << "warning: Input message is missing required fields: "
- << message->InitializationErrorString() << endl;
+ std::cerr << "warning: Input message is missing required fields: "
+ << message->InitializationErrorString() << std::endl;
}
if (mode_ == MODE_ENCODE) {
// Output is binary.
if (!message->SerializePartialToZeroCopyStream(&out)) {
- cerr << "output: I/O error." << endl;
+ std::cerr << "output: I/O error." << std::endl;
return false;
}
} else {
// Output is text.
if (!TextFormat::Print(*message, &out)) {
- cerr << "output: I/O error." << endl;
+ std::cerr << "output: I/O error." << std::endl;
return false;
}
}
@@ -1299,12 +1560,17 @@ bool CommandLineInterface::WriteDescriptorSet(
if (imports_in_descriptor_set_) {
set<const FileDescriptor*> already_seen;
for (int i = 0; i < parsed_files.size(); i++) {
- GetTransitiveDependencies(
- parsed_files[i], &already_seen, file_set.mutable_file());
+ GetTransitiveDependencies(parsed_files[i],
+ source_info_in_descriptor_set_,
+ &already_seen, file_set.mutable_file());
}
} else {
for (int i = 0; i < parsed_files.size(); i++) {
- parsed_files[i]->CopyTo(file_set.add_file());
+ FileDescriptorProto* file_proto = file_set.add_file();
+ parsed_files[i]->CopyTo(file_proto);
+ if (source_info_in_descriptor_set_) {
+ parsed_files[i]->CopySourceCodeInfoTo(file_proto);
+ }
}
}
@@ -1321,12 +1587,14 @@ bool CommandLineInterface::WriteDescriptorSet(
io::FileOutputStream out(fd);
if (!file_set.SerializeToZeroCopyStream(&out)) {
- cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
+ std::cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno())
+ << std::endl;
out.Close();
return false;
}
if (!out.Close()) {
- cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
+ std::cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno())
+ << std::endl;
return false;
}
@@ -1334,7 +1602,7 @@ bool CommandLineInterface::WriteDescriptorSet(
}
void CommandLineInterface::GetTransitiveDependencies(
- const FileDescriptor* file,
+ const FileDescriptor* file, bool include_source_code_info,
set<const FileDescriptor*>* already_seen,
RepeatedPtrField<FileDescriptorProto>* output) {
if (!already_seen->insert(file).second) {
@@ -1344,14 +1612,126 @@ void CommandLineInterface::GetTransitiveDependencies(
// Add all dependencies.
for (int i = 0; i < file->dependency_count(); i++) {
- GetTransitiveDependencies(file->dependency(i), already_seen, output);
+ GetTransitiveDependencies(file->dependency(i), include_source_code_info,
+ already_seen, output);
}
// Add this file.
- file->CopyTo(output->Add());
+ FileDescriptorProto* new_descriptor = output->Add();
+ file->CopyTo(new_descriptor);
+ if (include_source_code_info) {
+ file->CopySourceCodeInfoTo(new_descriptor);
+ }
+}
+
+namespace {
+
+// Utility function for PrintFreeFieldNumbers.
+// Stores occupied ranges into the ranges parameter, and next level of sub
+// message types into the nested_messages parameter. The FieldRange is left
+// inclusive, right exclusive. i.e. [a, b).
+//
+// Nested Messages:
+// Note that it only stores the nested message type, iff the nested type is
+// either a direct child of the given descriptor, or the nested type is a
+// decendent of the given descriptor and all the nodes between the
+// nested type and the given descriptor are group types. e.g.
+//
+// message Foo {
+// message Bar {
+// message NestedBar {}
+// }
+// group Baz = 1 {
+// group NestedBazGroup = 2 {
+// message Quz {
+// message NestedQuz {}
+// }
+// }
+// message NestedBaz {}
+// }
+// }
+//
+// In this case, Bar, Quz and NestedBaz will be added into the nested types.
+// Since free field numbers of group types will not be printed, this makes sure
+// the nested message types in groups will not be dropped. The nested_messages
+// parameter will contain the direct children (when groups are ignored in the
+// tree) of the given descriptor for the caller to traverse. The declaration
+// order of the nested messages is also preserved.
+typedef pair<int, int> FieldRange;
+void GatherOccupiedFieldRanges(const Descriptor* descriptor,
+ set<FieldRange>* ranges,
+ vector<const Descriptor*>* nested_messages) {
+ set<const Descriptor*> groups;
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ const FieldDescriptor* fd = descriptor->field(i);
+ ranges->insert(FieldRange(fd->number(), fd->number() + 1));
+ if (fd->type() == FieldDescriptor::TYPE_GROUP) {
+ groups.insert(fd->message_type());
+ }
+ }
+ for (int i = 0; i < descriptor->extension_range_count(); ++i) {
+ ranges->insert(FieldRange(descriptor->extension_range(i)->start,
+ descriptor->extension_range(i)->end));
+ }
+ // Handle the nested messages/groups in declaration order to make it
+ // post-order strict.
+ for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+ const Descriptor* nested_desc = descriptor->nested_type(i);
+ if (groups.find(nested_desc) != groups.end()) {
+ GatherOccupiedFieldRanges(nested_desc, ranges, nested_messages);
+ } else {
+ nested_messages->push_back(nested_desc);
+ }
+ }
+}
+
+// Utility function for PrintFreeFieldNumbers.
+// Actually prints the formatted free field numbers for given message name and
+// occupied ranges.
+void FormatFreeFieldNumbers(const string& name,
+ const set<FieldRange>& ranges) {
+ string output;
+ StringAppendF(&output, "%-35s free:", name.c_str());
+ int next_free_number = 1;
+ for (set<FieldRange>::const_iterator i = ranges.begin();
+ i != ranges.end(); ++i) {
+ // This happens when groups re-use parent field numbers, in which
+ // case we skip the FieldRange entirely.
+ if (next_free_number >= i->second) continue;
+
+ if (next_free_number < i->first) {
+ if (next_free_number + 1 == i->first) {
+ // Singleton
+ StringAppendF(&output, " %d", next_free_number);
+ } else {
+ // Range
+ StringAppendF(&output, " %d-%d", next_free_number, i->first - 1);
+ }
+ }
+ next_free_number = i->second;
+ }
+ if (next_free_number <= FieldDescriptor::kMaxNumber) {
+ StringAppendF(&output, " %d-INF", next_free_number);
+ }
+ std::cout << output << std::endl;
+}
+
+} // namespace
+
+void CommandLineInterface::PrintFreeFieldNumbers(
+ const Descriptor* descriptor) {
+ set<FieldRange> ranges;
+ vector<const Descriptor*> nested_messages;
+ GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages);
+
+ for (int i = 0; i < nested_messages.size(); ++i) {
+ PrintFreeFieldNumbers(nested_messages[i]);
+ }
+ FormatFreeFieldNumbers(descriptor->full_name(), ranges);
}
+
} // namespace compiler
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index 0b507d80..7e611c44 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -39,6 +39,7 @@
#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/hash.h>
#include <string>
#include <vector>
#include <map>
@@ -48,8 +49,9 @@
namespace google {
namespace protobuf {
-class FileDescriptor; // descriptor.h
+class Descriptor; // descriptor.h
class DescriptorPool; // descriptor.h
+class FileDescriptor; // descriptor.h
class FileDescriptorProto; // descriptor.pb.h
template<typename T> class RepeatedPtrField; // repeated_field.h
@@ -112,6 +114,19 @@ class LIBPROTOC_EXPORT CommandLineInterface {
CodeGenerator* generator,
const string& help_text);
+ // Register a code generator for a language.
+ // Besides flag_name you can specify another option_flag_name that could be
+ // used to pass extra parameters to the registered code generator.
+ // Suppose you have registered a generator by calling:
+ // command_line_interface.RegisterGenerator("--foo_out", "--foo_opt", ...)
+ // Then you could invoke the compiler with a command like:
+ // protoc --foo_out=enable_bar:outdir --foo_opt=enable_baz
+ // This will pass "enable_bar,enable_baz" as the parameter to the generator.
+ void RegisterGenerator(const string& flag_name,
+ const string& option_flag_name,
+ CodeGenerator* generator,
+ const string& help_text);
+
// Enables "plugins". In this mode, if a command-line flag ends with "_out"
// but does not match any registered generator, the compiler will attempt to
// find a "plugin" to implement the generator. Plugins are just executables.
@@ -176,6 +191,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
class ErrorPrinter;
class GeneratorContextImpl;
class MemoryOutputStream;
+ typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
// Clear state from previous Run().
void Clear();
@@ -186,14 +202,21 @@ class LIBPROTOC_EXPORT CommandLineInterface {
bool MakeInputsBeProtoPathRelative(
DiskSourceTree* source_tree);
+ // Return status for ParseArguments() and InterpretArgument().
+ enum ParseArgumentStatus {
+ PARSE_ARGUMENT_DONE_AND_CONTINUE,
+ PARSE_ARGUMENT_DONE_AND_EXIT,
+ PARSE_ARGUMENT_FAIL
+ };
+
// Parse all command-line arguments.
- bool ParseArguments(int argc, const char* const argv[]);
+ ParseArgumentStatus ParseArguments(int argc, const char* const argv[]);
// Parses a command-line argument into a name/value pair. Returns
// true if the next argument in the argv should be used as the value,
// false otherwise.
//
- // Exmaples:
+ // Examples:
// "-Isrc/protos" ->
// name = "-I", value = "src/protos"
// "--cpp_out=src/foo.pb2.cc" ->
@@ -203,7 +226,8 @@ class LIBPROTOC_EXPORT CommandLineInterface {
bool ParseArgument(const char* arg, string* name, string* value);
// Interprets arguments parsed with ParseArgument.
- bool InterpretArgument(const string& name, const string& value);
+ ParseArgumentStatus InterpretArgument(const string& name,
+ const string& value);
// Print the --help text to stderr.
void PrintHelpText();
@@ -225,17 +249,41 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// Implements the --descriptor_set_out option.
bool WriteDescriptorSet(const vector<const FileDescriptor*> parsed_files);
+ // Implements the --dependency_out option
+ bool GenerateDependencyManifestFile(
+ const vector<const FileDescriptor*>& parsed_files,
+ const GeneratorContextMap& output_directories,
+ DiskSourceTree* source_tree);
+
// Get all transitive dependencies of the given file (including the file
// itself), adding them to the given list of FileDescriptorProtos. The
// protos will be ordered such that every file is listed before any file that
// depends on it, so that you can call DescriptorPool::BuildFile() on them
// in order. Any files in *already_seen will not be added, and each file
- // added will be inserted into *already_seen.
+ // added will be inserted into *already_seen. If include_source_code_info is
+ // true then include the source code information in the FileDescriptorProtos.
static void GetTransitiveDependencies(
const FileDescriptor* file,
+ bool include_source_code_info,
set<const FileDescriptor*>* already_seen,
RepeatedPtrField<FileDescriptorProto>* output);
+ // Implements the --print_free_field_numbers. This function prints free field
+ // numbers into stdout for the message and it's nested message types in
+ // post-order, i.e. nested types first. Printed range are left-right
+ // inclusive, i.e. [a, b].
+ //
+ // Groups:
+ // For historical reasons, groups are considered to share the same
+ // field number space with the parent message, thus it will not print free
+ // field numbers for groups. The field numbers used in the groups are
+ // excluded in the free field numbers of the parent message.
+ //
+ // Extension Ranges:
+ // Extension ranges are considered ocuppied field numbers and they will not be
+ // listed as free numbers in the output.
+ void PrintFreeFieldNumbers(const Descriptor* descriptor);
+
// -----------------------------------------------------------------
// The name of the executable as invoked (i.e. argv[0]).
@@ -244,13 +292,21 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// Version info set with SetVersionInfo().
string version_info_;
- // Map from flag names to registered generators.
+ // Registered generators.
struct GeneratorInfo {
+ string flag_name;
+ string option_flag_name;
CodeGenerator* generator;
string help_text;
};
typedef map<string, GeneratorInfo> GeneratorMap;
- GeneratorMap generators_;
+ GeneratorMap generators_by_flag_name_;
+ GeneratorMap generators_by_option_name_;
+ // A map from generator names to the parameters specified using the option
+ // flag. For example, if the user invokes the compiler with:
+ // protoc --foo_out=outputdir --foo_opt=enable_bar ...
+ // Then there will be an entry ("--foo_out", "enable_bar") in this map.
+ map<string, string> generator_parameters_;
// See AllowPlugins(). If this is empty, plugins aren't allowed.
string plugin_prefix_;
@@ -264,11 +320,19 @@ class LIBPROTOC_EXPORT CommandLineInterface {
enum Mode {
MODE_COMPILE, // Normal mode: parse .proto files and compile them.
MODE_ENCODE, // --encode: read text from stdin, write binary to stdout.
- MODE_DECODE // --decode: read binary from stdin, write text to stdout.
+ MODE_DECODE, // --decode: read binary from stdin, write text to stdout.
+ MODE_PRINT, // Print mode: print info of the given .proto files and exit.
};
Mode mode_;
+ enum PrintMode {
+ PRINT_NONE, // Not in MODE_PRINT
+ PRINT_FREE_FIELDS, // --print_free_fields
+ };
+
+ PrintMode print_mode_;
+
enum ErrorFormat {
ERROR_FORMAT_GCC, // GCC error output format (default).
ERROR_FORMAT_MSVS // Visual Studio output (--error_format=msvs).
@@ -297,11 +361,19 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// FileDescriptorSet should be written. Otherwise, empty.
string descriptor_set_name_;
+ // If --dependency_out was given, this is the path to the file where the
+ // dependency file will be written. Otherwise, empty.
+ string dependency_out_name_;
+
// True if --include_imports was given, meaning that we should
// write all transitive dependencies to the DescriptorSet. Otherwise, only
// the .proto files listed on the command-line are added.
bool imports_in_descriptor_set_;
+ // True if --include_source_info was given, meaning that we should not strip
+ // SourceCodeInfo from the DescriptorSet.
+ bool source_info_in_descriptor_set_;
+
// Was the --disallow_services flag used?
bool disallow_services_;
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index d5b3a1dc..a2cbbdc6 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -40,6 +40,10 @@
#else
#include <unistd.h>
#endif
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <vector>
#include <google/protobuf/descriptor.pb.h>
@@ -47,6 +51,7 @@
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/testing/file.h>
#include <google/protobuf/compiler/mock_code_generator.h>
#include <google/protobuf/compiler/subprocess.h>
#include <google/protobuf/io/printer.h>
@@ -58,6 +63,10 @@
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
+
+// Disable the whole test when we use tcmalloc for "draconian" heap checks, in
+// which case tcmalloc will print warnings that fail the plugin tests.
+#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
namespace google {
namespace protobuf {
namespace compiler {
@@ -76,6 +85,10 @@ namespace compiler {
namespace {
+bool FileExists(const string& path) {
+ return File::Exists(path);
+}
+
class CommandLineInterfaceTest : public testing::Test {
protected:
virtual void SetUp();
@@ -102,6 +115,11 @@ class CommandLineInterfaceTest : public testing::Test {
// Create a subdirectory within temp_directory_.
void CreateTempDir(const string& name);
+ // Change working directory to temp directory.
+ void SwitchToTempDirectory() {
+ File::ChangeWorkingDirectory(temp_directory_);
+ }
+
void SetInputsAreProtoPathRelative(bool enable) {
cli_.SetInputsAreProtoPathRelative(enable);
}
@@ -122,6 +140,13 @@ class CommandLineInterfaceTest : public testing::Test {
// substring.
void ExpectErrorSubstring(const string& expected_substring);
+ // Like ExpectErrorSubstring, but checks that Run() returned zero.
+ void ExpectErrorSubstringWithZeroReturnCode(
+ const string& expected_substring);
+
+ // Checks that the captured stdout is the same as the expected_text.
+ void ExpectCapturedStdout(const string& expected_text);
+
// Returns true if ExpectErrorSubstring(expected_substring) would pass, but
// does not fail otherwise.
bool HasAlternateErrorSubstring(const string& expected_substring);
@@ -159,6 +184,9 @@ class CommandLineInterfaceTest : public testing::Test {
void ReadDescriptorSet(const string& filename,
FileDescriptorSet* descriptor_set);
+ void ExpectFileContent(const string& filename,
+ const string& content);
+
private:
// The object we are testing.
CommandLineInterface cli_;
@@ -178,6 +206,9 @@ class CommandLineInterfaceTest : public testing::Test {
// The captured stderr output.
string error_text_;
+ // The captured stdout.
+ string captured_stdout_;
+
// Pointers which need to be deleted later.
vector<CodeGenerator*> mock_generators_to_delete_;
@@ -215,17 +246,17 @@ 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);
}
// Create the temp directory.
- GOOGLE_CHECK(File::CreateDir(temp_directory_.c_str(), DEFAULT_FILE_MODE));
+ GOOGLE_CHECK_OK(File::CreateDir(temp_directory_, 0777));
// Register generators.
CodeGenerator* generator = new MockCodeGenerator("test_generator");
mock_generators_to_delete_.push_back(generator);
- cli_.RegisterGenerator("--test_out", generator, "Test output.");
+ cli_.RegisterGenerator("--test_out", "--test_opt", generator, "Test output.");
cli_.RegisterGenerator("-t", generator, "Test output.");
generator = new MockCodeGenerator("alt_generator");
@@ -241,7 +272,9 @@ void CommandLineInterfaceTest::SetUp() {
void CommandLineInterfaceTest::TearDown() {
// Delete the temp directory.
- File::DeleteRecursively(temp_directory_, NULL, NULL);
+ if (FileExists(temp_directory_)) {
+ File::DeleteRecursively(temp_directory_, NULL, NULL);
+ }
// Delete all the MockCodeGenerators.
for (int i = 0; i < mock_generators_to_delete_.size(); i++) {
@@ -251,8 +284,7 @@ void CommandLineInterfaceTest::TearDown() {
}
void CommandLineInterfaceTest::Run(const string& command) {
- vector<string> args;
- SplitStringUsing(command, " ", &args);
+ vector<string> args = Split(command, " ", true);
if (!disallow_plugins_) {
cli_.AllowPlugins("prefix-");
@@ -291,18 +323,27 @@ void CommandLineInterfaceTest::Run(const string& command) {
}
}
- scoped_array<const char*> argv(new const char*[args.size()]);
+ google::protobuf::scoped_array<const char * > argv(new const char* [args.size()]);
for (int i = 0; i < args.size(); i++) {
args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true);
argv[i] = args[i].c_str();
}
+ // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and
+ // stdout at the same time. Need to figure out why and add this capture back
+ // for Cygwin.
+#if !defined(__CYGWIN__)
+ CaptureTestStdout();
+#endif
CaptureTestStderr();
return_code_ = cli_.Run(args.size(), argv.get());
error_text_ = GetCapturedTestStderr();
+#if !defined(__CYGWIN__)
+ captured_stdout_ = GetCapturedTestStdout();
+#endif
}
// -------------------------------------------------------------------
@@ -314,16 +355,20 @@ void CommandLineInterfaceTest::CreateTempFile(
string::size_type slash_pos = name.find_last_of('/');
if (slash_pos != string::npos) {
string dir = name.substr(0, slash_pos);
- File::RecursivelyCreateDir(temp_directory_ + "/" + dir, 0777);
+ if (!FileExists(temp_directory_ + "/" + dir)) {
+ GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + dir,
+ 0777));
+ }
}
// Write file.
string full_name = temp_directory_ + "/" + name;
- File::WriteStringToFileOrDie(contents, full_name);
+ GOOGLE_CHECK_OK(File::SetContents(full_name, contents, true));
}
void CommandLineInterfaceTest::CreateTempDir(const string& name) {
- File::RecursivelyCreateDir(temp_directory_ + "/" + name, 0777);
+ GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + name,
+ 0777));
}
// -------------------------------------------------------------------
@@ -345,6 +390,12 @@ void CommandLineInterfaceTest::ExpectErrorSubstring(
EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
}
+void CommandLineInterfaceTest::ExpectErrorSubstringWithZeroReturnCode(
+ const string& expected_substring) {
+ EXPECT_EQ(0, return_code_);
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
+}
+
bool CommandLineInterfaceTest::HasAlternateErrorSubstring(
const string& expected_substring) {
EXPECT_NE(0, return_code_);
@@ -404,14 +455,29 @@ void CommandLineInterfaceTest::ReadDescriptorSet(
const string& filename, FileDescriptorSet* descriptor_set) {
string path = temp_directory_ + "/" + filename;
string file_contents;
- if (!File::ReadFileToString(path, &file_contents)) {
- FAIL() << "File not found: " << path;
- }
+ GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
+
if (!descriptor_set->ParseFromString(file_contents)) {
FAIL() << "Could not parse file contents: " << path;
}
}
+void CommandLineInterfaceTest::ExpectCapturedStdout(
+ const string& expected_text) {
+ EXPECT_EQ(expected_text, captured_stdout_);
+}
+
+
+void CommandLineInterfaceTest::ExpectFileContent(
+ const string& filename, const string& content) {
+ string path = temp_directory_ + "/" + filename;
+ string file_contents;
+ GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
+
+ EXPECT_EQ(StringReplace(content, "$tmpdir", temp_directory_, true),
+ file_contents);
+}
+
// ===================================================================
TEST_F(CommandLineInterfaceTest, BasicOutput) {
@@ -544,6 +610,32 @@ TEST_F(CommandLineInterfaceTest, GeneratorParameters) {
ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo");
}
+TEST_F(CommandLineInterfaceTest, ExtraGeneratorParameters) {
+ // Test that generator parameters specified with the option flag are
+ // correctly passed to the code generator.
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ // Create the "a" and "b" sub-directories.
+ CreateTempDir("a");
+ CreateTempDir("b");
+
+ Run("protocol_compiler "
+ "--test_opt=foo1 "
+ "--test_out=bar:$tmpdir/a "
+ "--test_opt=foo2 "
+ "--test_out=baz:$tmpdir/b "
+ "--test_opt=foo3 "
+ "--proto_path=$tmpdir foo.proto");
+
+ ExpectNoErrors();
+ ExpectGenerated(
+ "test_generator", "bar,foo1,foo2,foo3", "foo.proto", "Foo", "a");
+ ExpectGenerated(
+ "test_generator", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b");
+}
+
TEST_F(CommandLineInterfaceTest, Insert) {
// Test running a generator that inserts code into another's output.
@@ -655,7 +747,7 @@ TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) {
#endif
Run("protocol_compiler --test_out=$tmpdir "
- "--proto_path=$tmpdir/a"PATH_SEPARATOR"$tmpdir/b foo.proto");
+ "--proto_path=$tmpdir/a" PATH_SEPARATOR "$tmpdir/b foo.proto");
#undef PATH_SEPARATOR
@@ -777,8 +869,35 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) {
FileDescriptorSet descriptor_set;
ReadDescriptorSet("descriptor_set", &descriptor_set);
if (HasFatalFailure()) return;
- ASSERT_EQ(1, descriptor_set.file_size());
+ EXPECT_EQ(1, descriptor_set.file_size());
+ EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
+ // Descriptor set should not have source code info.
+ EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+}
+
+TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ CreateTempFile("bar.proto",
+ "syntax = \"proto2\";\n"
+ "import \"foo.proto\";\n"
+ "message Bar {\n"
+ " optional Foo foo = 1;\n"
+ "}\n");
+
+ Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
+ "--include_source_info --proto_path=$tmpdir bar.proto");
+
+ ExpectNoErrors();
+
+ FileDescriptorSet descriptor_set;
+ ReadDescriptorSet("descriptor_set", &descriptor_set);
+ if (HasFatalFailure()) return;
+ EXPECT_EQ(1, descriptor_set.file_size());
EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
+ // Source code info included.
+ EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
}
TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
@@ -800,13 +919,112 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
FileDescriptorSet descriptor_set;
ReadDescriptorSet("descriptor_set", &descriptor_set);
if (HasFatalFailure()) return;
- ASSERT_EQ(2, descriptor_set.file_size());
+ EXPECT_EQ(2, descriptor_set.file_size());
+ if (descriptor_set.file(0).name() == "bar.proto") {
+ std::swap(descriptor_set.mutable_file()->mutable_data()[0],
+ descriptor_set.mutable_file()->mutable_data()[1]);
+ }
+ EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
+ EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
+ // Descriptor set should not have source code info.
+ EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+ EXPECT_FALSE(descriptor_set.file(1).has_source_code_info());
+}
+
+TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ CreateTempFile("bar.proto",
+ "syntax = \"proto2\";\n"
+ "import \"foo.proto\";\n"
+ "message Bar {\n"
+ " optional Foo foo = 1;\n"
+ "}\n");
+
+ Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
+ "--include_imports --include_source_info --proto_path=$tmpdir bar.proto");
+
+ ExpectNoErrors();
+
+ FileDescriptorSet descriptor_set;
+ ReadDescriptorSet("descriptor_set", &descriptor_set);
+ if (HasFatalFailure()) return;
+ EXPECT_EQ(2, descriptor_set.file_size());
if (descriptor_set.file(0).name() == "bar.proto") {
std::swap(descriptor_set.mutable_file()->mutable_data()[0],
descriptor_set.mutable_file()->mutable_data()[1]);
}
EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
+ // Source code info included.
+ EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
+ EXPECT_TRUE(descriptor_set.file(1).has_source_code_info());
+}
+
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileGivenTwoInputs) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ CreateTempFile("bar.proto",
+ "syntax = \"proto2\";\n"
+ "import \"foo.proto\";\n"
+ "message Bar {\n"
+ " optional Foo foo = 1;\n"
+ "}\n");
+
+ Run("protocol_compiler --dependency_out=$tmpdir/manifest "
+ "--test_out=$tmpdir --proto_path=$tmpdir bar.proto foo.proto");
+
+ ExpectErrorText(
+ "Can only process one input file when using --dependency_out=FILE.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ CreateTempFile("bar.proto",
+ "syntax = \"proto2\";\n"
+ "import \"foo.proto\";\n"
+ "message Bar {\n"
+ " optional Foo foo = 1;\n"
+ "}\n");
+
+ string current_working_directory = getcwd(NULL, 0);
+ SwitchToTempDirectory();
+
+ Run("protocol_compiler --dependency_out=manifest --test_out=. "
+ "bar.proto");
+
+ ExpectNoErrors();
+
+ ExpectFileContent("manifest",
+ "bar.proto.MockCodeGenerator.test_generator: "
+ "foo.proto\\\n bar.proto");
+
+ File::ChangeWorkingDirectory(current_working_directory);
+}
+
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ CreateTempFile("bar.proto",
+ "syntax = \"proto2\";\n"
+ "import \"foo.proto\";\n"
+ "message Bar {\n"
+ " optional Foo foo = 1;\n"
+ "}\n");
+
+ Run("protocol_compiler --dependency_out=$tmpdir/manifest "
+ "--test_out=$tmpdir --proto_path=$tmpdir bar.proto");
+
+ ExpectNoErrors();
+
+ ExpectFileContent("manifest",
+ "$tmpdir/bar.proto.MockCodeGenerator.test_generator: "
+ "$tmpdir/foo.proto\\\n $tmpdir/bar.proto");
}
// -------------------------------------------------------------------
@@ -1129,6 +1347,17 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) {
#endif
}
+TEST_F(CommandLineInterfaceTest, PluginReceivesSourceCodeInfo) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message MockCodeGenerator_HasSourceCodeInfo {}\n");
+
+ Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
+
+ ExpectErrorSubstring(
+ "Saw message type MockCodeGenerator_HasSourceCodeInfo: 1.");
+}
+
TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
// Test what happens if the plugin isn't found.
@@ -1171,11 +1400,11 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) {
TEST_F(CommandLineInterfaceTest, HelpText) {
Run("test_exec_name --help");
- ExpectErrorSubstring("Usage: test_exec_name ");
- ExpectErrorSubstring("--test_out=OUT_DIR");
- ExpectErrorSubstring("Test output.");
- ExpectErrorSubstring("--alt_out=OUT_DIR");
- ExpectErrorSubstring("Alt output.");
+ ExpectErrorSubstringWithZeroReturnCode("Usage: test_exec_name ");
+ ExpectErrorSubstringWithZeroReturnCode("--test_out=OUT_DIR");
+ ExpectErrorSubstringWithZeroReturnCode("Test output.");
+ ExpectErrorSubstringWithZeroReturnCode("--alt_out=OUT_DIR");
+ ExpectErrorSubstringWithZeroReturnCode("Alt output.");
}
TEST_F(CommandLineInterfaceTest, GccFormatErrors) {
@@ -1285,6 +1514,76 @@ TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) {
ExpectErrorText("Missing value for flag: --test_out\n");
}
+TEST_F(CommandLineInterfaceTest, PrintFreeFieldNumbers) {
+ CreateTempFile(
+ "foo.proto",
+ "syntax = \"proto2\";\n"
+ "package foo;\n"
+ "message Foo {\n"
+ " optional int32 a = 2;\n"
+ " optional string b = 4;\n"
+ " optional string c = 5;\n"
+ " optional int64 d = 8;\n"
+ " optional double e = 10;\n"
+ "}\n");
+ CreateTempFile(
+ "bar.proto",
+ "syntax = \"proto2\";\n"
+ "message Bar {\n"
+ " optional int32 a = 2;\n"
+ " extensions 4 to 5;\n"
+ " optional int64 d = 8;\n"
+ " extensions 10;\n"
+ "}\n");
+ CreateTempFile(
+ "baz.proto",
+ "syntax = \"proto2\";\n"
+ "message Baz {\n"
+ " optional int32 a = 2;\n"
+ " optional int64 d = 8;\n"
+ " extensions 15 to max;\n" // unordered.
+ " extensions 13;\n"
+ " extensions 10 to 12;\n"
+ " extensions 5;\n"
+ " extensions 4;\n"
+ "}\n");
+ CreateTempFile(
+ "quz.proto",
+ "syntax = \"proto2\";\n"
+ "message Quz {\n"
+ " message Foo {}\n" // nested message
+ " optional int32 a = 2;\n"
+ " optional group C = 4 {\n"
+ " optional int32 d = 5;\n"
+ " }\n"
+ " extensions 8 to 10;\n"
+ " optional group E = 11 {\n"
+ " optional int32 f = 9;\n" // explicitly reuse extension range 8-10
+ " optional group G = 15 {\n" // nested group
+ " message Foo {}\n" // nested message inside nested group
+ " }\n"
+ " }\n"
+ "}\n");
+
+ Run("protocol_compiler --print_free_field_numbers --proto_path=$tmpdir "
+ "foo.proto bar.proto baz.proto quz.proto");
+
+ ExpectNoErrors();
+
+ // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and
+ // stdout at the same time. Need to figure out why and add this test back
+ // for Cygwin.
+#if !defined(__CYGWIN__)
+ ExpectCapturedStdout(
+ "foo.Foo free: 1 3 6-7 9 11-INF\n"
+ "Bar free: 1 3 6-7 9 11-INF\n"
+ "Baz free: 1 3 6-7 9 14\n"
+ "Quz.Foo free: 1-INF\n"
+ "Quz.E.G.Foo free: 1-INF\n"
+ "Quz free: 1 3 6-7 12-14 16-INF\n");
+#endif
+}
+
// ===================================================================
// Test for --encode and --decode. Note that it would be easier to do this
@@ -1304,7 +1603,7 @@ class EncodeDecodeTest : public testing::Test {
void RedirectStdinFromText(const string& input) {
string filename = TestTempDir() + "/test_stdin";
- File::WriteStringToFileOrDie(input, filename);
+ GOOGLE_CHECK_OK(File::SetContents(filename, input, true));
GOOGLE_CHECK(RedirectStdinFromFile(filename));
}
@@ -1338,7 +1637,7 @@ class EncodeDecodeTest : public testing::Test {
SplitStringUsing(command, " ", &args);
args.push_back("--proto_path=" + TestSourceDir());
- scoped_array<const char*> argv(new const char*[args.size()]);
+ google::protobuf::scoped_array<const char * > argv(new const char* [args.size()]);
for (int i = 0; i < args.size(); i++) {
argv[i] = args[i].c_str();
}
@@ -1359,7 +1658,7 @@ class EncodeDecodeTest : public testing::Test {
void ExpectStdoutMatchesBinaryFile(const string& filename) {
string expected_output;
- ASSERT_TRUE(File::ReadFileToString(filename, &expected_output));
+ GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
// Don't use EXPECT_EQ because we don't want to print raw binary data to
// stdout on failure.
@@ -1368,7 +1667,7 @@ class EncodeDecodeTest : public testing::Test {
void ExpectStdoutMatchesTextFile(const string& filename) {
string expected_output;
- ASSERT_TRUE(File::ReadFileToString(filename, &expected_output));
+ GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
ExpectStdoutMatchesText(expected_output);
}
@@ -1388,22 +1687,23 @@ class EncodeDecodeTest : public testing::Test {
};
TEST_F(EncodeDecodeTest, Encode) {
- RedirectStdinFromFile(TestSourceDir() +
- "/google/protobuf/testdata/text_format_unittest_data.txt");
+ RedirectStdinFromFile(TestSourceDir() + "/google/protobuf/"
+ "testdata/text_format_unittest_data_oneof_implemented.txt");
EXPECT_TRUE(Run("google/protobuf/unittest.proto "
"--encode=protobuf_unittest.TestAllTypes"));
ExpectStdoutMatchesBinaryFile(TestSourceDir() +
- "/google/protobuf/testdata/golden_message");
+ "/google/protobuf/testdata/golden_message_oneof_implemented");
ExpectStderrMatchesText("");
}
TEST_F(EncodeDecodeTest, Decode) {
RedirectStdinFromFile(TestSourceDir() +
- "/google/protobuf/testdata/golden_message");
+ "/google/protobuf/testdata/golden_message_oneof_implemented");
EXPECT_TRUE(Run("google/protobuf/unittest.proto "
"--decode=protobuf_unittest.TestAllTypes"));
ExpectStdoutMatchesTextFile(TestSourceDir() +
- "/google/protobuf/testdata/text_format_unittest_data.txt");
+ "/google/protobuf/"
+ "testdata/text_format_unittest_data_oneof_implemented.txt");
ExpectStderrMatchesText("");
}
@@ -1449,4 +1749,6 @@ TEST_F(EncodeDecodeTest, ProtoParseError) {
} // namespace compiler
} // namespace protobuf
+
+#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index bcfa5020..13ed0b64 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -48,8 +48,8 @@
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
-#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
@@ -93,12 +93,13 @@ class MockGeneratorContext : public GeneratorContext {
<< "Generator failed to generate file: " << virtual_filename;
string actual_contents;
- File::ReadFileToStringOrDie(
- TestSourceDir() + "/" + physical_filename,
- &actual_contents);
+ GOOGLE_CHECK_OK(
+ File::GetContents(TestSourceDir() + "/" + physical_filename,
+ &actual_contents, true));
EXPECT_TRUE(actual_contents == *expected_contents)
<< physical_filename << " needs to be regenerated. Please run "
- "generate_descriptor_proto.sh and add this file "
+ "google/protobuf/compiler/release_compiler.sh and "
+ "generate_descriptor_proto.sh. Then add this file "
"to your CL.";
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 76d2b798..3eb20ab1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -45,11 +45,27 @@ namespace protobuf {
namespace compiler {
namespace cpp {
+namespace {
+// The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
+// is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
+// generation of the GOOGLE_ARRAYSIZE constant.
+bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
+ int32 max_value = descriptor->value(0)->number();
+ for (int i = 0; i < descriptor->value_count(); i++) {
+ if (descriptor->value(i)->number() > max_value) {
+ max_value = descriptor->value(i)->number();
+ }
+ }
+ return max_value != ::google::protobuf::kint32max;
+}
+} // namespace
+
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
- const string& dllexport_decl)
+ const Options& options)
: descriptor_(descriptor),
classname_(ClassName(descriptor, false)),
- dllexport_decl_(dllexport_decl) {
+ options_(options),
+ generate_array_size_(ShouldGenerateArraySize(descriptor)) {
}
EnumGenerator::~EnumGenerator() {}
@@ -66,11 +82,15 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
const EnumValueDescriptor* max_value = descriptor_->value(0);
for (int i = 0; i < descriptor_->value_count(); i++) {
- vars["name"] = descriptor_->value(i)->name();
- vars["number"] = SimpleItoa(descriptor_->value(i)->number());
+ vars["name"] = EnumValueName(descriptor_->value(i));
+ // In C++, an value of -2147483648 gets interpreted as the negative of
+ // 2147483648, and since 2147483648 can't fit in an integer, this produces a
+ // compiler warning. This works around that issue.
+ vars["number"] = Int32ToString(descriptor_->value(i)->number());
vars["prefix"] = (descriptor_->containing_type() == NULL) ?
"" : classname_ + "_";
+
if (i > 0) printer->Print(",\n");
printer->Print(vars, "$prefix$$name$ = $number$");
@@ -82,24 +102,37 @@ 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_ = ::google::protobuf::kint32min,\n"
+ "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max");
+ }
+
printer->Outdent();
printer->Print("\n};\n");
- vars["min_name"] = min_value->name();
- vars["max_name"] = max_value->name();
+ vars["min_name"] = EnumValueName(min_value);
+ vars["max_name"] = EnumValueName(max_value);
- if (dllexport_decl_.empty()) {
+ if (options_.dllexport_decl.empty()) {
vars["dllexport"] = "";
} else {
- vars["dllexport"] = dllexport_decl_ + " ";
+ vars["dllexport"] = options_.dllexport_decl + " ";
}
printer->Print(vars,
"$dllexport$bool $classname$_IsValid(int value);\n"
"const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n"
- "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n"
- "const int $prefix$$short_name$_ARRAYSIZE = $prefix$$short_name$_MAX + 1;\n"
- "\n");
+ "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n");
+
+ if (generate_array_size_) {
+ printer->Print(vars,
+ "const int $prefix$$short_name$_ARRAYSIZE = "
+ "$prefix$$short_name$_MAX + 1;\n\n");
+ }
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(vars,
@@ -121,6 +154,10 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
void EnumGenerator::
GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
+ printer->Print(
+ "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type "
+ "{};\n",
+ "classname", ClassName(descriptor_, true));
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(
"template <>\n"
@@ -138,7 +175,7 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
printer->Print(vars, "typedef $classname$ $nested_name$;\n");
for (int j = 0; j < descriptor_->value_count(); j++) {
- vars["tag"] = descriptor_->value(j)->name();
+ vars["tag"] = EnumValueName(descriptor_->value(j));
printer->Print(vars,
"static const $nested_name$ $tag$ = $classname$_$tag$;\n");
}
@@ -150,9 +187,12 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
"static const $nested_name$ $nested_name$_MIN =\n"
" $classname$_$nested_name$_MIN;\n"
"static const $nested_name$ $nested_name$_MAX =\n"
- " $classname$_$nested_name$_MAX;\n"
- "static const int $nested_name$_ARRAYSIZE =\n"
- " $classname$_$nested_name$_ARRAYSIZE;\n");
+ " $classname$_$nested_name$_MAX;\n");
+ if (generate_array_size_) {
+ printer->Print(vars,
+ "static const int $nested_name$_ARRAYSIZE =\n"
+ " $classname$_$nested_name$_ARRAYSIZE;\n");
+ }
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(vars,
@@ -218,7 +258,7 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
iter != numbers.end(); ++iter) {
printer->Print(
" case $number$:\n",
- "number", SimpleItoa(*iter));
+ "number", Int32ToString(*iter));
}
printer->Print(vars,
@@ -239,14 +279,17 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
vars["parent"] = ClassName(descriptor_->containing_type(), false);
vars["nested_name"] = descriptor_->name();
for (int i = 0; i < descriptor_->value_count(); i++) {
- vars["value"] = descriptor_->value(i)->name();
+ vars["value"] = EnumValueName(descriptor_->value(i));
printer->Print(vars,
"const $classname$ $parent$::$value$;\n");
}
printer->Print(vars,
"const $classname$ $parent$::$nested_name$_MIN;\n"
- "const $classname$ $parent$::$nested_name$_MAX;\n"
- "const int $parent$::$nested_name$_ARRAYSIZE;\n");
+ "const $classname$ $parent$::$nested_name$_MAX;\n");
+ if (generate_array_size_) {
+ printer->Print(vars,
+ "const int $parent$::$nested_name$_ARRAYSIZE;\n");
+ }
printer->Print("#endif // _MSC_VER\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index 58f7721e..1ebd7cf7 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -36,8 +36,10 @@
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
#include <string>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
#include <google/protobuf/descriptor.h>
+
namespace google {
namespace protobuf {
namespace io {
@@ -53,7 +55,7 @@ class EnumGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit EnumGenerator(const EnumDescriptor* descriptor,
- const string& dllexport_decl);
+ const Options& options);
~EnumGenerator();
// Header stuff.
@@ -86,7 +88,9 @@ class EnumGenerator {
private:
const EnumDescriptor* descriptor_;
string classname_;
- string dllexport_decl_;
+ Options options_;
+ // whether to generate the *_ARRAYSIZE constant.
+ bool generate_array_size_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index a369f417..74989703 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,11 +46,13 @@ namespace cpp {
namespace {
void SetEnumVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
- SetCommonFieldVariables(descriptor, variables);
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
const EnumValueDescriptor* default_value = descriptor->default_value_enum();
(*variables)["type"] = ClassName(descriptor->enum_type(), true);
- (*variables)["default"] = SimpleItoa(default_value->number());
+ (*variables)["default"] = Int32ToString(default_value->number());
+ (*variables)["full_name"] = descriptor->full_name();
}
} // namespace
@@ -58,9 +60,10 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
// ===================================================================
EnumFieldGenerator::
-EnumFieldGenerator(const FieldDescriptor* descriptor)
+EnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetEnumVariables(descriptor, &variables_);
+ SetEnumVariables(descriptor, &variables_, options);
}
EnumFieldGenerator::~EnumFieldGenerator() {}
@@ -73,20 +76,29 @@ GeneratePrivateMembers(io::Printer* printer) const {
void EnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline $type$ $name$() const$deprecation$;\n"
- "inline void set_$name$($type$ value)$deprecation$;\n");
+ "$type$ $name$() const$deprecation$;\n"
+ "void set_$name$($type$ value)$deprecation$;\n");
}
void EnumFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
" return static_cast< $type$ >($name$_);\n"
"}\n"
- "inline void $classname$::set_$name$($type$ value) {\n"
- " GOOGLE_DCHECK($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");
}
@@ -116,16 +128,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 (HasUnknownFields(descriptor_->file())) {
+ " input, &value)));\n");
+ if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ printer->Print(variables_,
+ "set_$name$(static_cast< $type$ >(value));\n");
+ } else {
+ 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_,
- "} else {\n"
- " mutable_unknown_fields()->AddVarint($number$, value);\n");
+ "}\n");
}
- printer->Print(variables_,
- "}\n");
}
void EnumFieldGenerator::
@@ -151,10 +174,66 @@ GenerateByteSize(io::Printer* printer) const {
// ===================================================================
+EnumOneofFieldGenerator::
+EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
+ : EnumFieldGenerator(descriptor, options) {
+ SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
+
+void EnumOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ 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");
+ 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");
+}
+
+void EnumOneofFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
+}
+
+void EnumOneofFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void EnumOneofFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ " $classname$_default_oneof_instance_->$name$_ = $default$;\n");
+}
+
+// ===================================================================
+
RepeatedEnumFieldGenerator::
-RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
+RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetEnumVariables(descriptor, &variables_);
+ SetEnumVariables(descriptor, &variables_, options);
}
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
@@ -163,7 +242,8 @@ void RepeatedEnumFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField<int> $name$_;\n");
- if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
+ if (descriptor_->options().packed()
+ && HasGeneratedMethods(descriptor_->file())) {
printer->Print(variables_,
"mutable int _$name$_cached_byte_size_;\n");
}
@@ -172,35 +252,51 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline $type$ $name$(int index) const$deprecation$;\n"
- "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
- "inline void add_$name$($type$ value)$deprecation$;\n");
+ "$type$ $name$(int index) const$deprecation$;\n"
+ "void set_$name$(int index, $type$ value)$deprecation$;\n"
+ "void add_$name$($type$ value)$deprecation$;\n");
printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
- "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
+ "const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
+ "::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
}
void RepeatedEnumFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$(int index) const {\n"
+ " // @@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"
- " GOOGLE_DCHECK($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"
- " GOOGLE_DCHECK($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");
- printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedField<int>&\n"
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::RepeatedField<int>&\n"
"$classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline ::google::protobuf::RepeatedField<int>*\n"
+ "$inline$ ::google::protobuf::RepeatedField<int>*\n"
"$classname$::mutable_$name$() {\n"
+ " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
"}\n");
}
@@ -217,7 +313,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::
@@ -232,27 +328,59 @@ 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 (HasUnknownFields(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(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::
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
if (!descriptor_->options().packed()) {
- // We use a non-inlined implementation in this case, since this path will
- // rarely be executed.
- printer->Print(variables_,
- "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n"
- " input,\n"
- " &$type$_IsValid,\n"
- " this->mutable_$name$())));\n");
+ // This path is rarely executed, so we use a non-inlined implementation.
+ if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ printer->Print(variables_,
+ "DO_((::google::protobuf::internal::"
+ "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
+ " input,\n"
+ " $number$,\n"
+ " NULL,\n"
+ " NULL,\n"
+ " this->mutable_$name$())));\n");
+ } else if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(variables_,
+ "DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n"
+ " input,\n"
+ " $number$,\n"
+ " $type$_IsValid,\n"
+ " mutable_unknown_fields(),\n"
+ " this->mutable_$name$())));\n");
+ } else {
+ printer->Print(variables_,
+ "DO_((::google::protobuf::internal::"
+ "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
+ " input,\n"
+ " $number$,\n"
+ " $type$_IsValid,\n"
+ " &unknown_fields_stream,\n"
+ " this->mutable_$name$())));\n");
+ }
} else {
printer->Print(variables_,
"::google::protobuf::uint32 length;\n"
@@ -263,10 +391,27 @@ 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"
+ " } else {\n");
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(variables_,
+ " mutable_unknown_fields()->AddVarint($number$, value);\n");
+ } else {
+ printer->Print(variables_,
+ " unknown_fields_stream.WriteVarint32(tag);\n"
+ " unknown_fields_stream.WriteVarint32(value);\n");
+ }
+ printer->Print(
+ " }\n");
+ }
+ printer->Print(variables_,
"}\n"
"input->PopLimit(limit);\n");
}
@@ -345,7 +490,9 @@ GenerateByteSize(io::Printer* printer) const {
" total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
"}\n"
+ "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
"_$name$_cached_byte_size_ = data_size;\n"
+ "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
"total_size += data_size;\n");
} else {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
index 0793430c..5b1d01ea 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,13 +46,15 @@ namespace cpp {
class EnumFieldGenerator : public FieldGenerator {
public:
- explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
+ explicit EnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~EnumFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
@@ -62,22 +64,42 @@ class EnumFieldGenerator : public FieldGenerator {
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
- private:
+ protected:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
+ private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
};
+class EnumOneofFieldGenerator : public EnumFieldGenerator {
+ public:
+ explicit EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
+ ~EnumOneofFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
+ void GenerateConstructorCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator);
+};
+
class RepeatedEnumFieldGenerator : public FieldGenerator {
public:
- explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
+ explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~RepeatedEnumFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 658a7077..468ca484 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -57,9 +57,9 @@ string ExtendeeClassName(const FieldDescriptor* descriptor) {
} // anonymous namespace
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
- const string& dllexport_decl)
+ const Options& options)
: descriptor_(descriptor),
- dllexport_decl_(dllexport_decl) {
+ options_(options) {
// Construct type_traits_.
if (descriptor_->is_repeated()) {
type_traits_ = "Repeated";
@@ -106,8 +106,8 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
// export/import specifier.
if (descriptor_->extension_scope() == NULL) {
vars["qualifier"] = "extern";
- if (!dllexport_decl_.empty()) {
- vars["qualifier"] = dllexport_decl_ + " " + vars["qualifier"];
+ if (!options_.dllexport_decl.empty()) {
+ vars["qualifier"] = options_.dllexport_decl + " " + vars["qualifier"];
}
} else {
vars["qualifier"] = "static";
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h
index 3068b091..1c1caf1f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.h
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -37,6 +37,7 @@
#include <string>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
@@ -57,7 +58,7 @@ class ExtensionGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit ExtensionGenerator(const FieldDescriptor* descriptor,
- const string& dllexport_decl);
+ const Options& options);
~ExtensionGenerator();
// Header stuff.
@@ -72,7 +73,7 @@ class ExtensionGenerator {
private:
const FieldDescriptor* descriptor_;
string type_traits_;
- string dllexport_decl_;
+ Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index 103cac4a..43df1d88 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,10 +33,16 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
#include <google/protobuf/compiler/cpp/cpp_string_field.h>
#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
+#include <google/protobuf/compiler/cpp/cpp_map_field.h>
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/wire_format.h>
@@ -52,18 +58,49 @@ namespace cpp {
using internal::WireFormat;
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
+ map<string, string>* variables,
+ const Options& options) {
(*variables)["name"] = FieldName(descriptor);
(*variables)["index"] = SimpleItoa(descriptor->index());
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
+ // non_null_ptr_to_name is usable only if has_$name$ is true. It yields a
+ // pointer that will not be NULL. Subclasses of FieldGenerator may set
+ // (*variables)["non_null_ptr_to_name"] differently.
+ (*variables)["non_null_ptr_to_name"] =
+ StrCat("&this->", FieldName(descriptor), "()");
+
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
(*variables)["deprecation"] = descriptor->options().deprecated()
? " 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,
+ map<string, string>* variables) {
+ const string prefix = descriptor->containing_oneof()->name() + "_.";
+ (*variables)["oneof_prefix"] = prefix;
+ (*variables)["oneof_name"] = descriptor->containing_oneof()->name();
+ (*variables)["non_null_ptr_to_name"] =
+ StrCat(prefix, (*variables)["name"], "_");
}
FieldGenerator::~FieldGenerator() {}
@@ -80,46 +117,67 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
}
-FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
- : descriptor_(descriptor),
- field_generators_(
- new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
+ const Options& options)
+ : descriptor_(descriptor),
+ field_generators_(
+ new google::protobuf::scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
// Construct all the FieldGenerators.
for (int i = 0; i < descriptor->field_count(); i++) {
- field_generators_[i].reset(MakeGenerator(descriptor->field(i)));
+ field_generators_[i].reset(MakeGenerator(descriptor->field(i), options));
}
}
-FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) {
+FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
+ const Options& options) {
if (field->is_repeated()) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
- return new RepeatedMessageFieldGenerator(field);
+ if (field->is_map()) {
+ return new MapFieldGenerator(field, options);
+ } else {
+ return new RepeatedMessageFieldGenerator(field, options);
+ }
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: // RepeatedStringFieldGenerator handles unknown ctypes.
case FieldOptions::STRING:
- return new RepeatedStringFieldGenerator(field);
+ return new RepeatedStringFieldGenerator(field, options);
+ }
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return new RepeatedEnumFieldGenerator(field, options);
+ default:
+ return new RepeatedPrimitiveFieldGenerator(field, options);
+ }
+ } else if (field->containing_oneof()) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return new MessageOneofFieldGenerator(field, options);
+ case FieldDescriptor::CPPTYPE_STRING:
+ switch (field->options().ctype()) {
+ default: // StringOneofFieldGenerator handles unknown ctypes.
+ case FieldOptions::STRING:
+ return new StringOneofFieldGenerator(field, options);
}
case FieldDescriptor::CPPTYPE_ENUM:
- return new RepeatedEnumFieldGenerator(field);
+ return new EnumOneofFieldGenerator(field, options);
default:
- return new RepeatedPrimitiveFieldGenerator(field);
+ return new PrimitiveOneofFieldGenerator(field, options);
}
} else {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
- return new MessageFieldGenerator(field);
+ return new MessageFieldGenerator(field, options);
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: // StringFieldGenerator handles unknown ctypes.
case FieldOptions::STRING:
- return new StringFieldGenerator(field);
+ return new StringFieldGenerator(field, options);
}
case FieldDescriptor::CPPTYPE_ENUM:
- return new EnumFieldGenerator(field);
+ return new EnumFieldGenerator(field, options);
default:
- return new PrimitiveFieldGenerator(field);
+ return new PrimitiveFieldGenerator(field, options);
}
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index c303a337..cd2b6b75 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -36,10 +36,14 @@
#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
-#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
@@ -57,7 +61,11 @@ namespace cpp {
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
// 'deprecation'].
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables);
+ map<string, string>* variables,
+ const Options& options);
+
+void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables);
class FieldGenerator {
public:
@@ -69,6 +77,11 @@ class FieldGenerator {
// class.
virtual void GeneratePrivateMembers(io::Printer* printer) const = 0;
+ // Generate static default variable for this field. These are placed inside
+ // the message class. Most field types don't need this, so the default
+ // implementation is empty.
+ virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {}
+
// Generate prototypes for all of the accessor functions related to this
// field. These are placed inside the class definition.
virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0;
@@ -76,13 +89,13 @@ class FieldGenerator {
// Generate inline definitions of accessor functions for this field.
// These are placed inside the header after all class definitions.
virtual void GenerateInlineAccessorDefinitions(
- io::Printer* printer) const = 0;
+ io::Printer* printer, bool is_inline) const = 0;
// Generate definitions of accessors that aren't inlined. These are
// placed somewhere in the .cc file.
// Most field types don't need this, so the default implementation is empty.
virtual void GenerateNonInlineAccessorDefinitions(
- io::Printer* printer) const {}
+ io::Printer* /*printer*/) const {}
// Generate lines of code (statements, not declarations) which clear the
// field. This is used to define the clear_$name$() method as well as
@@ -112,7 +125,25 @@ class FieldGenerator {
// Generate any code that needs to go in the class's SharedDtor() method,
// invoked by the destructor.
// Most field types don't need this, so the default implementation is empty.
- virtual void GenerateDestructorCode(io::Printer* printer) const {}
+ 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 {}
+
+ // Generate code that should be run when ShutdownProtobufLibrary() is called,
+ // to delete all dynamically-allocated objects.
+ virtual void GenerateShutdownCode(io::Printer* /*printer*/) const {}
// Generate lines to decode this field, which will be placed inside the
// message's MergeFromCodedStream() method.
@@ -144,16 +175,17 @@ class FieldGenerator {
// Convenience class which constructs FieldGenerators for a Descriptor.
class FieldGeneratorMap {
public:
- explicit FieldGeneratorMap(const Descriptor* descriptor);
+ explicit FieldGeneratorMap(const Descriptor* descriptor, const Options& options);
~FieldGeneratorMap();
const FieldGenerator& get(const FieldDescriptor* field) const;
private:
const Descriptor* descriptor_;
- scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<FieldGenerator> > field_generators_;
- static FieldGenerator* MakeGenerator(const FieldDescriptor* field);
+ static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
+ const Options& options);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 312ebc86..a98c7d92 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,6 +33,12 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_file.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <set>
+
#include <google/protobuf/compiler/cpp/cpp_enum.h>
#include <google/protobuf/compiler/cpp/cpp_service.h>
#include <google/protobuf/compiler/cpp/cpp_extension.h>
@@ -50,37 +56,36 @@ namespace cpp {
// ===================================================================
-FileGenerator::FileGenerator(const FileDescriptor* file,
- const string& dllexport_decl)
- : file_(file),
- message_generators_(
- new scoped_ptr<MessageGenerator>[file->message_type_count()]),
- enum_generators_(
- new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
- service_generators_(
- new scoped_ptr<ServiceGenerator>[file->service_count()]),
- extension_generators_(
- new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
- dllexport_decl_(dllexport_decl) {
+FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
+ : file_(file),
+ message_generators_(
+ new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]),
+ enum_generators_(
+ new google::protobuf::scoped_ptr<EnumGenerator>[file->enum_type_count()]),
+ service_generators_(
+ new google::protobuf::scoped_ptr<ServiceGenerator>[file->service_count()]),
+ extension_generators_(
+ new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]),
+ options_(options) {
for (int i = 0; i < file->message_type_count(); i++) {
message_generators_[i].reset(
- new MessageGenerator(file->message_type(i), dllexport_decl));
+ new MessageGenerator(file->message_type(i), options));
}
for (int i = 0; i < file->enum_type_count(); i++) {
enum_generators_[i].reset(
- new EnumGenerator(file->enum_type(i), dllexport_decl));
+ new EnumGenerator(file->enum_type(i), options));
}
for (int i = 0; i < file->service_count(); i++) {
service_generators_[i].reset(
- new ServiceGenerator(file->service(i), dllexport_decl));
+ new ServiceGenerator(file->service(i), options));
}
for (int i = 0; i < file->extension_count(); i++) {
extension_generators_[i].reset(
- new ExtensionGenerator(file->extension(i), dllexport_decl));
+ new ExtensionGenerator(file->extension(i), options));
}
SplitStringUsing(file_->package(), ".", &package_parts_);
@@ -104,6 +109,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"filename", file_->name(),
"filename_identifier", filename_identifier);
+
printer->Print(
"#include <google/protobuf/stubs/common.h>\n"
"\n");
@@ -128,13 +134,45 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
// OK, it's now safe to #include other files.
printer->Print(
- "#include <google/protobuf/generated_message_util.h>\n"
+ "#include <google/protobuf/arena.h>\n"
+ "#include <google/protobuf/arenastring.h>\n"
+ "#include <google/protobuf/generated_message_util.h>\n");
+ if (UseUnknownFieldSet(file_)) {
+ printer->Print(
+ "#include <google/protobuf/metadata.h>\n");
+ }
+ if (file_->message_type_count() > 0) {
+ if (HasDescriptorMethods(file_)) {
+ printer->Print(
+ "#include <google/protobuf/message.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/message_lite.h>\n");
+ }
+ }
+ printer->Print(
"#include <google/protobuf/repeated_field.h>\n"
"#include <google/protobuf/extension_set.h>\n");
-
- if (HasDescriptorMethods(file_)) {
+ if (HasMapFields(file_)) {
printer->Print(
- "#include <google/protobuf/generated_message_reflection.h>\n");
+ "#include <google/protobuf/map.h>\n");
+ if (HasDescriptorMethods(file_)) {
+ printer->Print(
+ "#include <google/protobuf/map_field_inl.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/map_field_lite.h>\n");
+ }
+ }
+
+ if (HasEnumDefinitions(file_)) {
+ if (HasDescriptorMethods(file_)) {
+ printer->Print(
+ "#include <google/protobuf/generated_enum_reflection.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/generated_enum_util.h>\n");
+ }
}
if (HasGenericServices(file_)) {
@@ -142,16 +180,33 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"#include <google/protobuf/service.h>\n");
}
+ if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
+ printer->Print(
+ "#include <google/protobuf/unknown_field_set.h>\n");
+ }
+
+
+ set<string> public_import_names;
+ for (int i = 0; i < file_->public_dependency_count(); i++) {
+ public_import_names.insert(file_->public_dependency(i)->name());
+ }
for (int i = 0; i < file_->dependency_count(); i++) {
+ const string& name = file_->dependency(i)->name();
+ bool public_import = (public_import_names.count(name) != 0);
+
+
printer->Print(
- "#include \"$dependency$.pb.h\"\n",
- "dependency", StripProto(file_->dependency(i)->name()));
+ "#include \"$dependency$.pb.h\"$iwyu$\n",
+ "dependency", StripProto(name),
+ "iwyu", (public_import) ? " // IWYU pragma: export" : "");
}
printer->Print(
"// @@protoc_insertion_point(includes)\n");
+
+
// Open namespace.
GenerateNamespaceOpeners(printer);
@@ -160,9 +215,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", 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
@@ -230,14 +286,17 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
printer->Print(kThickSeparator);
printer->Print("\n");
+ printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
// Generate class inline methods.
for (int i = 0; i < file_->message_type_count(); i++) {
if (i > 0) {
printer->Print(kThinSeparator);
printer->Print("\n");
}
- message_generators_[i]->GenerateInlineMethods(printer);
+ message_generators_[i]->GenerateInlineMethods(printer,
+ /* is_inline = */ true);
}
+ printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
printer->Print(
"\n"
@@ -247,7 +306,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
GenerateNamespaceClosers(printer);
// Emit GetEnumDescriptor specializations into google::protobuf namespace:
- if (HasDescriptorMethods(file_)) {
+ if (HasEnumDefinitions(file_)) {
// The SWIG conditional is to avoid a null-pointer dereference
// (bug 1984964) in swig-1.3.21 resulting from the following syntax:
// namespace X { void Y<Z::W>(); }
@@ -265,7 +324,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");
}
@@ -282,6 +341,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
void FileGenerator::GenerateSource(io::Printer* printer) {
printer->Print(
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
"\n"
// The generated code calls accessors that might be deprecated. We don't
@@ -291,14 +351,23 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
"\n"
"#include <algorithm>\n" // for swap()
"\n"
+ "#include <google/protobuf/stubs/common.h>\n"
"#include <google/protobuf/stubs/once.h>\n"
"#include <google/protobuf/io/coded_stream.h>\n"
"#include <google/protobuf/wire_format_lite_inl.h>\n",
+ "filename", file_->name(),
"basename", StripProto(file_->name()));
+ // Unknown fields implementation in lite mode uses StringOutputStream
+ if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
+ printer->Print(
+ "#include <google/protobuf/io/zero_copy_stream_impl_lite.h>\n");
+ }
+
if (HasDescriptorMethods(file_)) {
printer->Print(
"#include <google/protobuf/descriptor.h>\n"
+ "#include <google/protobuf/generated_message_reflection.h>\n"
"#include <google/protobuf/reflection_ops.h>\n"
"#include <google/protobuf/wire_format.h>\n");
}
@@ -347,10 +416,29 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
// Generate classes.
for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i == 0 && HasGeneratedMethods(file_)) {
+ printer->Print(
+ "\n"
+ "namespace {\n"
+ "\n"
+ "static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;\n"
+ "static void MergeFromFail(int line) {\n"
+ " GOOGLE_CHECK(false) << __FILE__ << \":\" << line;\n"
+ "}\n"
+ "\n"
+ "} // namespace\n"
+ "\n");
+ }
printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
message_generators_[i]->GenerateClassMethods(printer);
+
+ printer->Print("#if PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+ // Generate class inline methods.
+ message_generators_[i]->GenerateInlineMethods(printer,
+ /* is_inline = */ false);
+ printer->Print("#endif // PROTOBUF_INLINE_NOT_IN_HEADERS\n");
}
if (HasGenericServices(file_)) {
@@ -381,11 +469,12 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// AddDescriptors() is a file-level procedure which adds the encoded
- // FileDescriptorProto for this .proto file to the global DescriptorPool
- // for generated files (DescriptorPool::generated_pool()). It always runs
- // at static initialization time, so all files will be registered before
- // main() starts. This procedure also constructs default instances and
- // registers extensions.
+ // FileDescriptorProto for this .proto file to the global DescriptorPool for
+ // generated files (DescriptorPool::generated_pool()). It either runs at
+ // static initialization time (by default) or when default_instance() is
+ // called for the first time (in LITE_RUNTIME mode with
+ // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER flag enabled). This procedure also
+ // constructs default instances and registers extensions.
//
// Its sibling, AssignDescriptors(), actually pulls the compiled
// FileDescriptor from the DescriptorPool and uses it to populate all of
@@ -489,22 +578,29 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
printer->Outdent();
printer->Print(
- "}\n");
+ "}\n\n");
// -----------------------------------------------------------------
// Now generate the AddDescriptors() function.
- printer->Print(
- "\n"
+ PrintHandlingOptionalStaticInitializers(
+ file_, printer,
+ // With static initializers.
+ // Note that we don't need any special synchronization in the following code
+ // because it is called at static init time before any threads exist.
"void $adddescriptorsname$() {\n"
- // We don't need any special synchronization here because this code is
- // called at static init time before any threads exist.
" static bool already_here = false;\n"
" if (already_here) return;\n"
" already_here = true;\n"
" GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
"\n",
+ // Without.
+ "void $adddescriptorsname$_impl() {\n"
+ " GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
+ "\n",
+ // Vars.
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
+
printer->Indent();
// Call the AddDescriptors() methods for all of our dependencies, to make
@@ -512,17 +608,12 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
for (int i = 0; i < file_->dependency_count(); i++) {
const FileDescriptor* dependency = file_->dependency(i);
// Print the namespace prefix for the dependency.
- vector<string> dependency_package_parts;
- SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
- printer->Print("::");
- for (int i = 0; i < dependency_package_parts.size(); i++) {
- printer->Print("$name$::",
- "name", dependency_package_parts[i]);
- }
+ string add_desc_name = QualifiedFileLevelSymbol(
+ dependency->package(), GlobalAddDescriptorsName(dependency->name()));
// Call its AddDescriptors function.
printer->Print(
"$name$();\n",
- "name", GlobalAddDescriptorsName(dependency->name()));
+ "name", add_desc_name);
}
if (HasDescriptorMethods(file_)) {
@@ -541,10 +632,12 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
static const int kBytesPerLine = 40;
for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
printer->Print("\n \"$data$\"",
- "data", EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
+ "data",
+ EscapeTrigraphs(
+ CEscape(file_data.substr(i, kBytesPerLine))));
}
printer->Print(
- ", $size$);\n",
+ ", $size$);\n",
"size", SimpleItoa(file_data.size()));
// Call MessageFactory::InternalRegisterGeneratedFile().
@@ -572,17 +665,26 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
"shutdownfilename", GlobalShutdownFileName(file_->name()));
printer->Outdent();
-
printer->Print(
"}\n"
- "\n"
+ "\n");
+
+ PrintHandlingOptionalStaticInitializers(
+ file_, printer,
+ // With static initializers.
"// Force AddDescriptors() to be called at static initialization time.\n"
"struct StaticDescriptorInitializer_$filename$ {\n"
" StaticDescriptorInitializer_$filename$() {\n"
" $adddescriptorsname$();\n"
" }\n"
- "} static_descriptor_initializer_$filename$_;\n"
- "\n",
+ "} static_descriptor_initializer_$filename$_;\n",
+ // Without.
+ "GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n"
+ "void $adddescriptorsname$() {\n"
+ " ::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n"
+ " &$adddescriptorsname$_impl);\n"
+ "}\n",
+ // Vars.
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
"filename", FilenameIdentifier(file_->name()));
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index b4e01285..0e06547d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,10 +35,15 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
@@ -61,7 +66,7 @@ class FileGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit FileGenerator(const FileDescriptor* file,
- const string& dllexport_decl);
+ const Options& options);
~FileGenerator();
void GenerateHeader(io::Printer* printer);
@@ -77,15 +82,14 @@ class FileGenerator {
const FileDescriptor* file_;
- scoped_array<scoped_ptr<MessageGenerator> > message_generators_;
- scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
- scoped_array<scoped_ptr<ServiceGenerator> > service_generators_;
- scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<ServiceGenerator> > service_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
// E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
vector<string> package_parts_;
-
- string dllexport_decl_;
+ const Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index bb84e2ab..c999b93f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,6 +35,10 @@
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <vector>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <utility>
#include <google/protobuf/compiler/cpp/cpp_file.h>
@@ -78,11 +82,13 @@ bool CppGenerator::Generate(const FileDescriptor* file,
// }
// FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
// __declspec(dllimport) depending on what is being compiled.
- string dllexport_decl;
+ Options file_options;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "dllexport_decl") {
- dllexport_decl = options[i].second;
+ file_options.dllexport_decl = options[i].second;
+ } else if (options[i].first == "safe_boundary_check") {
+ file_options.safe_boundary_check = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
@@ -95,20 +101,20 @@ bool CppGenerator::Generate(const FileDescriptor* file,
string basename = StripProto(file->name());
basename.append(".pb");
- FileGenerator file_generator(file, dllexport_decl);
+ FileGenerator file_generator(file, file_options);
// Generate header.
{
- scoped_ptr<io::ZeroCopyOutputStream> output(
- generator_context->Open(basename + ".h"));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(basename + ".h"));
io::Printer printer(output.get(), '$');
file_generator.GenerateHeader(&printer);
}
// Generate cc file.
{
- scoped_ptr<io::ZeroCopyOutputStream> output(
- generator_context->Open(basename + ".cc"));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(basename + ".cc"));
io::Printer printer(output.get(), '$');
file_generator.GenerateSource(&printer);
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.h b/src/google/protobuf/compiler/cpp/cpp_generator.h
index a90e84d7..3d517cf4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.h
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 25b05a85..4e7155c3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,10 +33,12 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <limits>
+#include <map>
#include <vector>
#include <google/protobuf/stubs/hash.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
@@ -58,16 +60,17 @@ string DotsToColons(const string& name) {
}
const char* const kKeywordList[] = {
- "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case",
- "catch", "char", "class", "compl", "const", "const_cast", "continue",
- "default", "delete", "do", "double", "dynamic_cast", "else", "enum",
- "explicit", "extern", "false", "float", "for", "friend", "goto", "if",
- "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq",
- "operator", "or", "or_eq", "private", "protected", "public", "register",
- "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
- "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
- "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
- "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
+ "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
+ "bool", "break", "case", "catch", "char", "class", "compl", "const",
+ "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
+ "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false",
+ "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
+ "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or",
+ "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
+ "return", "short", "signed", "sizeof", "static", "static_assert",
+ "static_cast", "struct", "switch", "template", "this", "thread_local",
+ "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
+ "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
};
hash_set<string> MakeKeywordsMap() {
@@ -80,6 +83,22 @@ hash_set<string> MakeKeywordsMap() {
hash_set<string> kKeywords = MakeKeywordsMap();
+// Returns whether the provided descriptor has an extension. This includes its
+// nested types.
+bool HasExtension(const Descriptor* descriptor) {
+ if (descriptor->extension_count() > 0) {
+ return true;
+ }
+ for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+ if (HasExtension(descriptor->nested_type(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
string result;
// Note: I distrust ctype.h due to locales.
@@ -105,8 +124,6 @@ string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
return result;
}
-} // namespace
-
const char kThickSeparator[] =
"// ===================================================================\n";
const char kThinSeparator[] =
@@ -132,7 +149,7 @@ string ClassName(const Descriptor* descriptor, bool qualified) {
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
if (enum_descriptor->containing_type() == NULL) {
if (qualified) {
- return DotsToColons(enum_descriptor->full_name());
+ return "::" + DotsToColons(enum_descriptor->full_name());
} else {
return enum_descriptor->name();
}
@@ -159,6 +176,14 @@ string FieldName(const FieldDescriptor* field) {
return result;
}
+string EnumValueName(const EnumValueDescriptor* enum_value) {
+ string result = enum_value->name();
+ if (kKeywords.count(result) > 0) {
+ result.append("_");
+ }
+ return result;
+}
+
string FieldConstantName(const FieldDescriptor *field) {
string field_name = UnderscoresToCamelCase(field->name(), true);
string result = "k" + field_name + "FieldNumber";
@@ -240,14 +265,35 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
return "";
}
+string Int32ToString(int number) {
+ // gcc rejects the decimal form of kint32min.
+ if (number == kint32min) {
+ GOOGLE_COMPILE_ASSERT(kint32min == (~0x7fffffff), kint32min_value_error);
+ return "(~0x7fffffff)";
+ } else {
+ return SimpleItoa(number);
+ }
+}
+
+string Int64ToString(int64 number) {
+ // gcc rejects the decimal form of kint64min
+ if (number == kint64min) {
+ // Make sure we are in a 2's complement system.
+ GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(~0x7fffffffffffffff),
+ kint64min_value_error);
+ return "GOOGLE_LONGLONG(~0x7fffffffffffffff)";
+ }
+ return "GOOGLE_LONGLONG(" + SimpleItoa(number) + ")";
+}
+
string DefaultValue(const FieldDescriptor* field) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
- return SimpleItoa(field->default_value_int32());
+ return Int32ToString(field->default_value_int32());
case FieldDescriptor::CPPTYPE_UINT32:
return SimpleItoa(field->default_value_uint32()) + "u";
case FieldDescriptor::CPPTYPE_INT64:
- return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")";
+ return Int64ToString(field->default_value_int64());
case FieldDescriptor::CPPTYPE_UINT64:
return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
case FieldDescriptor::CPPTYPE_DOUBLE: {
@@ -290,10 +336,11 @@ string DefaultValue(const FieldDescriptor* field) {
return strings::Substitute(
"static_cast< $0 >($1)",
ClassName(field->enum_type(), true),
- field->default_value_enum()->number());
+ Int32ToString(field->default_value_enum()->number()));
case FieldDescriptor::CPPTYPE_STRING:
- return "\"" + EscapeTrigraphs(CEscape(field->default_value_string())) +
- "\"";
+ return "\"" + EscapeTrigraphs(
+ CEscape(field->default_value_string())) +
+ "\"";
case FieldDescriptor::CPPTYPE_MESSAGE:
return FieldMessageTypeName(field) + "::default_instance()";
}
@@ -313,9 +360,7 @@ string FilenameIdentifier(const string& filename) {
} else {
// Not alphanumeric. To avoid any possibility of name conflicts we
// use the hex code for the character.
- result.push_back('_');
- char buffer[kFastToBufferSize];
- result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer));
+ StrAppend(&result, "_", ToHex(static_cast<uint8>(filename[i])));
}
}
return result;
@@ -336,11 +381,146 @@ string GlobalShutdownFileName(const string& filename) {
return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
}
+// Return the qualified C++ name for a file level symbol.
+string QualifiedFileLevelSymbol(const string& package, const string& name) {
+ if (package.empty()) {
+ return StrCat("::", name);
+ }
+ return StrCat("::", DotsToColons(package), "::", name);
+}
+
// Escape C++ trigraphs by escaping question marks to \?
string EscapeTrigraphs(const string& to_escape) {
return StringReplace(to_escape, "?", "\\?", true);
}
+// Escaped function name to eliminate naming conflict.
+string SafeFunctionName(const Descriptor* descriptor,
+ const FieldDescriptor* field,
+ const string& prefix) {
+ // Do not use FieldName() since it will escape keywords.
+ string name = field->name();
+ LowerString(&name);
+ string function_name = prefix + name;
+ if (descriptor->FindFieldByName(function_name)) {
+ // Single underscore will also make it conflicting with the private data
+ // member. We use double underscore to escape function names.
+ function_name.append("__");
+ } else if (kKeywords.count(name) > 0) {
+ // If the field name is a keyword, we append the underscore back to keep it
+ // consistent with other function names.
+ function_name.append("_");
+ }
+ return function_name;
+}
+
+bool StaticInitializersForced(const FileDescriptor* file) {
+ if (HasDescriptorMethods(file) || file->extension_count() > 0) {
+ return true;
+ }
+ for (int i = 0; i < file->message_type_count(); ++i) {
+ if (HasExtension(file->message_type(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void PrintHandlingOptionalStaticInitializers(
+ const FileDescriptor* file, io::Printer* printer,
+ const char* with_static_init, const char* without_static_init,
+ const char* var1, const string& val1,
+ const char* var2, const string& val2) {
+ map<string, string> vars;
+ if (var1) {
+ vars[var1] = val1;
+ }
+ if (var2) {
+ vars[var2] = val2;
+ }
+ PrintHandlingOptionalStaticInitializers(
+ vars, file, printer, with_static_init, without_static_init);
+}
+
+void PrintHandlingOptionalStaticInitializers(
+ const map<string, string>& vars, const FileDescriptor* file,
+ io::Printer* printer, const char* with_static_init,
+ const char* without_static_init) {
+ if (StaticInitializersForced(file)) {
+ printer->Print(vars, with_static_init);
+ } else {
+ printer->Print(vars, (string(
+ "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n") +
+ without_static_init +
+ "#else\n" +
+ with_static_init +
+ "#endif\n").c_str());
+ }
+}
+
+
+static bool HasMapFields(const Descriptor* descriptor) {
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ if (descriptor->field(i)->is_map()) {
+ return true;
+ }
+ }
+ for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+ if (HasMapFields(descriptor->nested_type(i))) return true;
+ }
+ return false;
+}
+
+bool HasMapFields(const FileDescriptor* file) {
+ for (int i = 0; i < file->message_type_count(); ++i) {
+ if (HasMapFields(file->message_type(i))) return true;
+ }
+ return false;
+}
+
+static bool HasEnumDefinitions(const Descriptor* message_type) {
+ if (message_type->enum_type_count() > 0) return true;
+ for (int i = 0; i < message_type->nested_type_count(); ++i) {
+ if (HasEnumDefinitions(message_type->nested_type(i))) return true;
+ }
+ return false;
+}
+
+bool HasEnumDefinitions(const FileDescriptor* file) {
+ if (file->enum_type_count() > 0) return true;
+ for (int i = 0; i < file->message_type_count(); ++i) {
+ if (HasEnumDefinitions(file->message_type(i))) return true;
+ }
+ return false;
+}
+
+bool IsStringOrMessage(const FieldDescriptor* field) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ case FieldDescriptor::CPPTYPE_INT64:
+ case FieldDescriptor::CPPTYPE_UINT32:
+ case FieldDescriptor::CPPTYPE_UINT64:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ case FieldDescriptor::CPPTYPE_BOOL:
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return false;
+ case FieldDescriptor::CPPTYPE_STRING:
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return true;
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return false;
+}
+
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) {
+ GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
+ // Open-source protobuf release only supports STRING ctype.
+ return FieldOptions::STRING;
+
+}
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index b13d53be..284fa2c1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,12 +35,18 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
+#include <map>
#include <string>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
namespace google {
namespace protobuf {
+
+namespace io {
+class Printer;
+}
+
namespace compiler {
namespace cpp {
@@ -68,6 +74,9 @@ string SuperClassName(const Descriptor* descriptor);
// anyway, so normally this just returns field->name().
string FieldName(const FieldDescriptor* field);
+// Get the sanitized name that should be used for the given enum in C++ code.
+string EnumValueName(const EnumValueDescriptor* enum_value);
+
// Get the unqualified name that should be used for a field's field
// number constant.
string FieldConstantName(const FieldDescriptor *field);
@@ -97,6 +106,12 @@ const char* PrimitiveTypeName(FieldDescriptor::CppType type);
// methods of WireFormat. For example, TYPE_INT32 becomes "Int32".
const char* DeclaredTypeMethodName(FieldDescriptor::Type type);
+// Return the code that evaluates to the number when compiled.
+string Int32ToString(int number);
+
+// Return the code that evaluates to the number when compiled.
+string Int64ToString(int64 number);
+
// Get code that evaluates to the field's default value.
string DefaultValue(const FieldDescriptor* field);
@@ -109,30 +124,54 @@ string GlobalAddDescriptorsName(const string& filename);
// Return the name of the AssignDescriptors() function for a given file.
string GlobalAssignDescriptorsName(const string& filename);
+// Return the qualified C++ name for a file level symbol.
+string QualifiedFileLevelSymbol(const string& package, const string& name);
+
// Return the name of the ShutdownFile() function for a given file.
string GlobalShutdownFileName(const string& filename);
// Escape C++ trigraphs by escaping question marks to \?
string EscapeTrigraphs(const string& to_escape);
-// Do message classes in this file keep track of unknown fields?
-inline bool HasUnknownFields(const FileDescriptor *file) {
+// Escaped function name to eliminate naming conflict.
+string SafeFunctionName(const Descriptor* descriptor,
+ const FieldDescriptor* field,
+ const string& prefix);
+
+// 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;
}
+
+// Does the file have any map fields, necessitating the file to include
+// map_field_inl.h and map.h.
+bool HasMapFields(const FileDescriptor* file);
+
+// Does this file have any enum type definitions?
+bool HasEnumDefinitions(const FileDescriptor* file);
+
// Does this file have generated parsing, serialization, and other
// standard methods for which reflection-based fallback implementations exist?
-inline bool HasGeneratedMethods(const FileDescriptor *file) {
+inline bool HasGeneratedMethods(const FileDescriptor* file) {
return file->options().optimize_for() != FileOptions::CODE_SIZE;
}
-// Do message classes in this file have descriptor and refelction methods?
-inline bool HasDescriptorMethods(const FileDescriptor *file) {
+// Do message classes in this file have descriptor and reflection methods?
+inline bool HasDescriptorMethods(const FileDescriptor* file) {
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
}
// Should we generate generic services for this file?
-inline bool HasGenericServices(const FileDescriptor *file) {
+inline bool HasGenericServices(const FileDescriptor* file) {
return file->service_count() > 0 &&
file->options().optimize_for() != FileOptions::LITE_RUNTIME &&
file->options().cc_generic_services();
@@ -150,6 +189,58 @@ inline bool HasFastArraySerialization(const FileDescriptor* file) {
return file->options().optimize_for() == FileOptions::SPEED;
}
+// Returns whether we have to generate code with static initializers.
+bool StaticInitializersForced(const FileDescriptor* file);
+
+// Prints 'with_static_init' if static initializers have to be used for the
+// provided file. Otherwise emits both 'with_static_init' and
+// 'without_static_init' using #ifdef.
+void PrintHandlingOptionalStaticInitializers(
+ const FileDescriptor* file, io::Printer* printer,
+ const char* with_static_init, const char* without_static_init,
+ const char* var1 = NULL, const string& val1 = "",
+ const char* var2 = NULL, const string& val2 = "");
+
+void PrintHandlingOptionalStaticInitializers(
+ const map<string, string>& vars, const FileDescriptor* file,
+ io::Printer* printer, const char* with_static_init,
+ const char* without_static_init);
+
+
+inline bool IsMapEntryMessage(const Descriptor* descriptor) {
+ return descriptor->options().map_entry();
+}
+
+// Returns true if the field's CPPTYPE is string or message.
+bool IsStringOrMessage(const FieldDescriptor* field);
+
+// For a string field, returns the effective ctype. If the actual ctype is
+// not supported, returns the default of STRING.
+FieldOptions::CType EffectiveStringCType(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 file->options().cc_enable_arenas();
+}
+
+inline bool SupportsArenas(const Descriptor* desc) {
+ return SupportsArenas(desc->file());
+}
+
+inline bool SupportsArenas(const FieldDescriptor* field) {
+ return SupportsArenas(field->file());
+}
} // namespace cpp
} // namespace compiler
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
new file mode 100644
index 00000000..8c38db2b
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -0,0 +1,345 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/cpp/cpp_map_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+bool IsProto3Field(const FieldDescriptor* field_descriptor) {
+ const FileDescriptor* file_descriptor = field_descriptor->file();
+ return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
+ (*variables)["type"] = FieldMessageTypeName(descriptor);
+ (*variables)["stream_writer"] = (*variables)["declared_type"] +
+ (HasFastArraySerialization(descriptor->message_type()->file()) ?
+ "MaybeToArray" :
+ "");
+ (*variables)["full_name"] = descriptor->full_name();
+
+ const FieldDescriptor* key =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* val =
+ descriptor->message_type()->FindFieldByName("value");
+ (*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type());
+ switch (val->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ (*variables)["val_cpp"] = FieldMessageTypeName(val);
+ (*variables)["wrapper"] = "EntryWrapper";
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ (*variables)["val_cpp"] = ClassName(val->enum_type(), false);
+ (*variables)["wrapper"] = "EnumEntryWrapper";
+ break;
+ default:
+ (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
+ (*variables)["wrapper"] = "EntryWrapper";
+ }
+ (*variables)["key_wire_type"] =
+ "::google::protobuf::internal::WireFormatLite::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(key->type()));
+ (*variables)["val_wire_type"] =
+ "::google::protobuf::internal::WireFormatLite::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(val->type()));
+ (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+
+ if (HasDescriptorMethods(descriptor->file())) {
+ (*variables)["lite"] = "";
+ } else {
+ (*variables)["lite"] = "Lite";
+ }
+
+ if (!IsProto3Field(descriptor) &&
+ val->type() == FieldDescriptor::TYPE_ENUM) {
+ const EnumValueDescriptor* default_value = val->default_value_enum();
+ (*variables)["default_enum_value"] = Int32ToString(default_value->number());
+ } else {
+ (*variables)["default_enum_value"] = "0";
+ }
+}
+
+MapFieldGenerator::
+MapFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
+ : descriptor_(descriptor) {
+ SetMessageVariables(descriptor, &variables_, options);
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "typedef ::google::protobuf::internal::MapEntryLite<\n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ >\n"
+ " $map_classname$;\n"
+ "::google::protobuf::internal::MapField$lite$<\n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ > $name$_;\n");
+}
+
+void MapFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_,
+ "const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+ " $name$() const$deprecation$;\n"
+ "::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+ " mutable_$name$()$deprecation$;\n");
+}
+
+void MapFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+ "$classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_map:$full_name$)\n"
+ " return $name$_.GetMap();\n"
+ "}\n"
+ "$inline$ ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+ "$classname$::mutable_$name$() {\n"
+ " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
+ " return $name$_.MutableMap();\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Clear();\n");
+}
+
+void MapFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
+}
+
+void MapFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+}
+
+void MapFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+ if (HasDescriptorMethods(descriptor_->file())) {
+ printer->Print(variables_,
+ "$name$_.SetAssignDescriptorCallback(\n"
+ " protobuf_AssignDescriptorsOnce);\n"
+ "$name$_.SetEntryDescriptor(\n"
+ " &$type$_descriptor_);\n");
+ }
+}
+
+void MapFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ const FieldDescriptor* value_field =
+ descriptor_->message_type()->FindFieldByName("value");
+ printer->Print(variables_,
+ "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
+
+ if (IsProto3Field(descriptor_) ||
+ value_field->type() != FieldDescriptor::TYPE_ENUM) {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
+ " input, entry.get()));\n");
+ switch (value_field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ printer->Print(variables_,
+ "(*mutable_$name$())[entry->key()].Swap("
+ "entry->mutable_value());\n");
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ printer->Print(variables_,
+ "(*mutable_$name$())[entry->key()] =\n"
+ " static_cast<$val_cpp$>(*entry->mutable_value());\n");
+ break;
+ default:
+ printer->Print(variables_,
+ "(*mutable_$name$())[entry->key()] = *entry->mutable_value();\n");
+ break;
+ }
+ } else {
+ printer->Print(variables_,
+ "{\n"
+ " ::std::string data;\n"
+ " DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n"
+ " DO_(entry->ParseFromString(data));\n"
+ " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
+ " (*mutable_$name$())[entry->key()] =\n"
+ " static_cast<$val_cpp$>(*entry->mutable_value());\n"
+ " } else {\n");
+ if (HasDescriptorMethods(descriptor_->file())) {
+ printer->Print(variables_,
+ " mutable_unknown_fields()"
+ "->AddLengthDelimited($number$, data);\n");
+ } else {
+ printer->Print(variables_,
+ " unknown_fields_stream.WriteVarint32($tag$);\n"
+ " unknown_fields_stream.WriteVarint32(data.size());\n"
+ " unknown_fields_stream.WriteString(data);\n");
+ }
+
+
+ printer->Print(variables_,
+ " }\n"
+ "}\n");
+ }
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "if (entry->GetArena() != NULL) entry.release();\n");
+ }
+}
+
+void MapFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "{\n"
+ " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+ " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+ " it = $name$().begin(); it != $name$().end(); ++it) {\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print(variables_,
+ " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
+ " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
+ " $number$, *entry, output);\n"
+ " }\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print("}\n");
+}
+
+void MapFieldGenerator::
+GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
+ printer->Print(variables_,
+ "{\n"
+ " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+ " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+ " it = $name$().begin(); it != $name$().end(); ++it) {\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print(variables_,
+ " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
+ " target = ::google::protobuf::internal::WireFormatLite::\n"
+ " Write$declared_type$NoVirtualToArray(\n"
+ " $number$, *entry, target);\n"
+ " }\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print("}\n");
+}
+
+void MapFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ printer->Print(variables_,
+ "total_size += $tag_size$ * this->$name$_size();\n"
+ "{\n"
+ " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+ " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+ " it = $name$().begin(); it != $name$().end(); ++it) {\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print(variables_,
+ " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
+ " total_size += ::google::protobuf::internal::WireFormatLite::\n"
+ " $declared_type$SizeNoVirtual(*entry);\n"
+ " }\n");
+
+ // If entry is allocated by arena, its desctructor should be avoided.
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ " }\n");
+ }
+
+ printer->Print("}\n");
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h
new file mode 100644
index 00000000..d27d4851
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h
@@ -0,0 +1,76 @@
+// 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_CPP_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/cpp/cpp_message_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class MapFieldGenerator : public FieldGenerator {
+ public:
+ explicit MapFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
+ ~MapFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
+ void GenerateConstructorCode(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index c4e6fb2c..bafa36f5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,6 +35,11 @@
#include <algorithm>
#include <google/protobuf/stubs/hash.h>
#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <set>
#include <utility>
#include <vector>
#include <google/protobuf/compiler/cpp/cpp_message.h>
@@ -48,6 +53,7 @@
#include <google/protobuf/wire_format.h>
#include <google/protobuf/descriptor.pb.h>
+
namespace google {
namespace protobuf {
namespace compiler {
@@ -73,15 +79,6 @@ struct FieldOrderingByNumber {
}
};
-const char* kWireTypeNames[] = {
- "VARINT",
- "FIXED64",
- "LENGTH_DELIMITED",
- "START_GROUP",
- "END_GROUP",
- "FIXED32",
-};
-
// Sort the fields of the given Descriptor by number into a new[]'d array
// and return it.
const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
@@ -90,8 +87,8 @@ const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
for (int i = 0; i < descriptor->field_count(); i++) {
fields[i] = descriptor->field(i);
}
- sort(fields, fields + descriptor->field_count(),
- FieldOrderingByNumber());
+ std::sort(fields, fields + descriptor->field_count(),
+ FieldOrderingByNumber());
return fields;
}
@@ -103,6 +100,13 @@ struct ExtensionRangeSorter {
}
};
+// Returns true if the "required" restriction check should be ignored for the
+// given field.
+inline static bool ShouldIgnoreRequiredFieldCheck(
+ const FieldDescriptor* field) {
+ return false;
+}
+
// Returns true if the message type has any required fields. If it doesn't,
// we can optimize out calls to its IsInitialized() method.
//
@@ -129,7 +133,8 @@ static bool HasRequiredFields(
if (field->is_required()) {
return true;
}
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ !ShouldIgnoreRequiredFieldCheck(field)) {
if (HasRequiredFields(field->message_type(), already_seen)) {
return true;
}
@@ -246,8 +251,9 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) {
aligned_to_4.push_back(field_group);
}
// Sort by preferred location to keep fields as close to their original
- // location as possible.
- sort(aligned_to_4.begin(), aligned_to_4.end());
+ // location as possible. Using stable_sort ensures that the output is
+ // consistent across runs.
+ std::stable_sort(aligned_to_4.begin(), aligned_to_4.end());
// Now group fields aligned to 4 bytes (or the 4-field groups created above)
// into pairs, and treat those like a single field aligned to 8 bytes.
@@ -262,9 +268,8 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) {
}
aligned_to_8.push_back(field_group);
}
- // Sort by preferred location to keep fields as close to their original
- // location as possible.
- sort(aligned_to_8.begin(), aligned_to_8.end());
+ // Sort by preferred location.
+ std::stable_sort(aligned_to_8.begin(), aligned_to_8.end());
// Now pull out all the FieldDescriptors in order.
fields->clear();
@@ -275,36 +280,127 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) {
}
}
+// 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;
}
+// Collects map entry message type information.
+void CollectMapInfo(const Descriptor* descriptor,
+ map<string, string>* variables) {
+ GOOGLE_CHECK(IsMapEntryMessage(descriptor));
+ const FieldDescriptor* key = descriptor->FindFieldByName("key");
+ const FieldDescriptor* val = descriptor->FindFieldByName("value");
+ (*variables)["key"] = PrimitiveTypeName(key->cpp_type());
+ switch (val->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ (*variables)["val"] = FieldMessageTypeName(val);
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ (*variables)["val"] = ClassName(val->enum_type(), false);
+ break;
+ default:
+ (*variables)["val"] = PrimitiveTypeName(val->cpp_type());
+ }
+ (*variables)["key_wire_type"] =
+ "::google::protobuf::internal::WireFormatLite::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(key->type()));
+ (*variables)["val_wire_type"] =
+ "::google::protobuf::internal::WireFormatLite::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(val->type()));
+}
+
+// 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,
- const string& dllexport_decl)
- : descriptor_(descriptor),
- classname_(ClassName(descriptor, false)),
- dllexport_decl_(dllexport_decl),
- field_generators_(descriptor),
- nested_generators_(new scoped_ptr<MessageGenerator>[
- descriptor->nested_type_count()]),
- enum_generators_(new scoped_ptr<EnumGenerator>[
- descriptor->enum_type_count()]),
- extension_generators_(new scoped_ptr<ExtensionGenerator>[
- descriptor->extension_count()]) {
+ const Options& options)
+ : descriptor_(descriptor),
+ classname_(ClassName(descriptor, false)),
+ options_(options),
+ field_generators_(descriptor, options),
+ nested_generators_(new google::protobuf::scoped_ptr<
+ MessageGenerator>[descriptor->nested_type_count()]),
+ enum_generators_(
+ new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
+ extension_generators_(new google::protobuf::scoped_ptr<
+ ExtensionGenerator>[descriptor->extension_count()]) {
for (int i = 0; i < descriptor->nested_type_count(); i++) {
nested_generators_[i].reset(
- new MessageGenerator(descriptor->nested_type(i), dllexport_decl));
+ new MessageGenerator(descriptor->nested_type(i), options));
}
for (int i = 0; i < descriptor->enum_type_count(); i++) {
enum_generators_[i].reset(
- new EnumGenerator(descriptor->enum_type(i), dllexport_decl));
+ new EnumGenerator(descriptor->enum_type(i), options));
}
for (int i = 0; i < descriptor->extension_count(); i++) {
extension_generators_[i].reset(
- new ExtensionGenerator(descriptor->extension(i), dllexport_decl));
+ 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_;
+ }
}
}
@@ -316,6 +412,10 @@ GenerateForwardDeclaration(io::Printer* printer) {
"classname", classname_);
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need forward declaration. Since map entry
+ // message cannot be a top level class, we just need to avoid calling
+ // GenerateForwardDeclaration here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateForwardDeclaration(printer);
}
}
@@ -349,16 +449,21 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
PrintFieldComment(printer, field);
map<string, string> vars;
- SetCommonFieldVariables(field, &vars);
+ SetCommonFieldVariables(field, &vars, options_);
vars["constant_name"] = FieldConstantName(field);
if (field->is_repeated()) {
- printer->Print(vars, "inline int $name$_size() const$deprecation$;\n");
- } else {
- printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n");
+ printer->Print(vars, "int $name$_size() const$deprecation$;\n");
+ } else if (HasHasMethod(field)) {
+ printer->Print(vars, "bool has_$name$() const$deprecation$;\n");
+ } else if (HasPrivateHasMethod(field)) {
+ printer->Print(vars,
+ "private:\n"
+ "bool has_$name$() const$deprecation$;\n"
+ "public:\n");
}
- printer->Print(vars, "inline void clear_$name$()$deprecation$;\n");
+ printer->Print(vars, "void clear_$name$()$deprecation$;\n");
printer->Print(vars, "static const int $constant_name$ = $number$;\n");
// Generate type-specific accessor declarations.
@@ -374,10 +479,18 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
"GOOGLE_PROTOBUF_EXTENSION_ACCESSORS($classname$)\n",
"classname", classname_);
}
+
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "$camel_oneof_name$Case $oneof_name$_case() const;\n",
+ "camel_oneof_name",
+ UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true),
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ }
}
void MessageGenerator::
-GenerateFieldAccessorDefinitions(io::Printer* printer) {
+GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
printer->Print("// $classname$\n\n", "classname", classname_);
for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -386,57 +499,161 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
PrintFieldComment(printer, field);
map<string, string> vars;
- SetCommonFieldVariables(field, &vars);
+ SetCommonFieldVariables(field, &vars, options_);
+ vars["inline"] = is_inline ? "inline" : "";
// Generate has_$name$() or $name$_size().
if (field->is_repeated()) {
printer->Print(vars,
- "inline int $classname$::$name$_size() const {\n"
+ "$inline$ int $classname$::$name$_size() const {\n"
" return $name$_.size();\n"
"}\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");
+ 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 !_is_default_instance_ && $name$_ != NULL;\n"
+ "}\n");
+ }
+ }
+ }
}
// Generate clear_$name$()
printer->Print(vars,
- "inline void $classname$::clear_$name$() {\n");
+ "$inline$ void $classname$::clear_$name$() {\n");
printer->Indent();
- field_generators_.get(field).GenerateClearingCode(printer);
- printer->Outdent();
- if (!field->is_repeated()) {
+ if (field->containing_oneof()) {
+ // Clear this field only if it is the active field in this oneof,
+ // otherwise ignore
printer->Print(vars,
- " clear_has_$name$();\n");
+ "if (has_$name$()) {\n");
+ printer->Indent();
+ field_generators_.get(field).GenerateClearingCode(printer);
+ printer->Print(vars,
+ "clear_has_$oneof_name$();\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else {
+ field_generators_.get(field).GenerateClearingCode(printer);
+ if (HasFieldPresence(descriptor_->file())) {
+ if (!field->is_repeated()) {
+ printer->Print(vars,
+ "clear_has_$name$();\n");
+ }
+ }
}
+ printer->Outdent();
printer->Print("}\n");
// Generate type-specific accessors.
- field_generators_.get(field).GenerateInlineAccessorDefinitions(printer);
+ field_generators_.get(field).GenerateInlineAccessorDefinitions(printer,
+ is_inline);
printer->Print("\n");
}
+
+ // Generate has_$name$() and clear_has_$name$() functions for oneofs
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ map<string, string> vars;
+ vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
+ vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+ vars["cap_oneof_name"] =
+ ToUpper(descriptor_->oneof_decl(i)->name());
+ vars["classname"] = classname_;
+ vars["inline"] = is_inline ? "inline" : "";
+ printer->Print(
+ vars,
+ "$inline$ bool $classname$::has_$oneof_name$() const {\n"
+ " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
+ "}\n"
+ "$inline$ void $classname$::clear_has_$oneof_name$() {\n"
+ " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
+ "}\n");
+ }
+}
+
+// Helper for the code that emits the Clear() method.
+static bool CanClearByZeroing(const FieldDescriptor* field) {
+ if (field->is_repeated() || field->is_extension()) return false;
+ switch (field->cpp_type()) {
+ case internal::WireFormatLite::CPPTYPE_ENUM:
+ return field->default_value_enum()->number() == 0;
+ case internal::WireFormatLite::CPPTYPE_INT32:
+ return field->default_value_int32() == 0;
+ case internal::WireFormatLite::CPPTYPE_INT64:
+ return field->default_value_int64() == 0;
+ case internal::WireFormatLite::CPPTYPE_UINT32:
+ return field->default_value_uint32() == 0;
+ case internal::WireFormatLite::CPPTYPE_UINT64:
+ return field->default_value_uint64() == 0;
+ case internal::WireFormatLite::CPPTYPE_FLOAT:
+ return field->default_value_float() == 0;
+ case internal::WireFormatLite::CPPTYPE_DOUBLE:
+ return field->default_value_double() == 0;
+ case internal::WireFormatLite::CPPTYPE_BOOL:
+ return field->default_value_bool() == false;
+ default:
+ return false;
+ }
}
void MessageGenerator::
GenerateClassDefinition(io::Printer* printer) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need class definition. Since map entry message
+ // cannot be a top level class, we just need to avoid calling
+ // GenerateClassDefinition here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateClassDefinition(printer);
printer->Print("\n");
printer->Print(kThinSeparator);
@@ -446,10 +663,11 @@ GenerateClassDefinition(io::Printer* printer) {
map<string, string> vars;
vars["classname"] = classname_;
vars["field_count"] = SimpleItoa(descriptor_->field_count());
- if (dllexport_decl_.empty()) {
+ vars["oneof_decl_count"] = SimpleItoa(descriptor_->oneof_decl_count());
+ if (options_.dllexport_decl.empty()) {
vars["dllexport"] = "";
} else {
- vars["dllexport"] = dllexport_decl_ + " ";
+ vars["dllexport"] = options_.dllexport_decl + " ";
}
vars["superclass"] = SuperClassName(descriptor_);
@@ -470,16 +688,41 @@ GenerateClassDefinition(io::Printer* printer) {
"}\n"
"\n");
- if (HasUnknownFields(descriptor_->file())) {
+ 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 ::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");
+ "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.
@@ -493,13 +736,60 @@ GenerateClassDefinition(io::Printer* printer) {
"static const $classname$& default_instance();\n"
"\n");
+ // Generate enum values for every field in oneofs. One list is generated for
+ // each oneof with an additional *_NOT_SET value.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "enum $camel_oneof_name$Case {\n",
+ "camel_oneof_name",
+ UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true));
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ printer->Print(
+ "k$field_name$ = $field_number$,\n",
+ "field_name",
+ UnderscoresToCamelCase(
+ descriptor_->oneof_decl(i)->field(j)->name(), true),
+ "field_number",
+ SimpleItoa(descriptor_->oneof_decl(i)->field(j)->number()));
+ }
+ printer->Print(
+ "$cap_oneof_name$_NOT_SET = 0,\n",
+ "cap_oneof_name",
+ ToUpper(descriptor_->oneof_decl(i)->name()));
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "\n");
+ }
+
+ if (!StaticInitializersForced(descriptor_->file())) {
+ printer->Print(vars,
+ "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"
+ "// Returns the internal default instance pointer. This function can\n"
+ "// return NULL thus should not be used by the user. This is intended\n"
+ "// for Protobuf internal code. Please use default_instance() declared\n"
+ "// above instead.\n"
+ "static inline const $classname$* internal_default_instance() {\n"
+ " return default_instance_;\n"
+ "}\n"
+ "#endif\n"
+ "\n");
+ }
+
+ 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())) {
@@ -522,20 +812,84 @@ GenerateClassDefinition(io::Printer* printer) {
" ::google::protobuf::io::CodedInputStream* input);\n"
"void SerializeWithCachedSizes(\n"
" ::google::protobuf::io::CodedOutputStream* output) const;\n");
+ // DiscardUnknownFields() is implemented in message.cc using reflections. We
+ // need to implement this function in generated code for messages.
+ if (!UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ "void DiscardUnknownFields();\n");
+ }
if (HasFastArraySerialization(descriptor_->file())) {
printer->Print(
"::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n");
}
}
- printer->Print(vars,
+ // Check all FieldDescriptors including those in oneofs to estimate
+ // whether ::std::string is likely to be used, and depending on that
+ // estimate, set uses_string_ to true or false. That contols
+ // whether to force initialization of empty_string_ in SharedCtor().
+ // It's often advantageous to do so to keep "is empty_string_
+ // inited?" code from appearing all over the place.
+ vector<const FieldDescriptor*> descriptors;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ descriptors.push_back(descriptor_->field(i));
+ }
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ descriptors.push_back(descriptor_->oneof_decl(i)->field(j));
+ }
+ }
+ uses_string_ = false;
+ for (int i = 0; i < descriptors.size(); i++) {
+ const FieldDescriptor* field = descriptors[i];
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+ switch (field->options().ctype()) {
+ default: uses_string_ = true; break;
+ }
+ }
+ }
+
+ printer->Print(
"int GetCachedSize() const { return _cached_size_; }\n"
"private:\n"
"void SharedCtor();\n"
"void SharedDtor();\n"
"void SetCachedSize(int size) const;\n"
- "public:\n"
- "\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(
@@ -554,9 +908,11 @@ GenerateClassDefinition(io::Printer* printer) {
// Import all nested message classes into this class's scope with typedefs.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
const Descriptor* nested_type = descriptor_->nested_type(i);
- printer->Print("typedef $nested_full_name$ $nested_name$;\n",
- "nested_name", nested_type->name(),
- "nested_full_name", ClassName(nested_type, false));
+ if (!IsMapEntryMessage(nested_type)) {
+ printer->Print("typedef $nested_full_name$ $nested_name$;\n",
+ "nested_name", nested_type->name(),
+ "nested_full_name", ClassName(nested_type, false));
+ }
}
if (descriptor_->nested_type_count() > 0) {
@@ -592,18 +948,66 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print(" private:\n");
printer->Indent();
+
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)));
- printer->Print(
- "inline void clear_has_$name$();\n",
- "name", FieldName(descriptor_->field(i)));
+ // 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)));
+ }
}
}
printer->Print("\n");
+ // Generate oneof function declarations
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "inline bool has_$oneof_name$() const;\n"
+ "void clear_$oneof_name$();\n"
+ "inline void clear_has_$oneof_name$();\n\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ }
+
+ if (HasGeneratedMethods(descriptor_->file()) &&
+ !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.
+
+ bool need_to_emit_cached_size = true;
+ // TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it.
+ const string cached_size_decl = "mutable int _cached_size_;\n";
+
+ // TODO(jieluo) - Optimize _has_bits_ for repeated and oneof fields.
+ size_t sizeof_has_bits = (descriptor_->field_count() + 31) / 32 * 4;
+ if (descriptor_->field_count() == 0) {
+ // Zero-size arrays aren't technically allowed, and MSVC in particular
+ // doesn't like them. We still need to declare these arrays to make
+ // other code compile. Since this is an uncommon case, we'll just declare
+ // them with size 1 and waste some space. Oh well.
+ sizeof_has_bits = 4;
+ }
+ const string has_bits_decl = sizeof_has_bits == 0 ? "" :
+ "::google::protobuf::uint32 _has_bits_[" + SimpleItoa(sizeof_has_bits / 4) + "];\n";
+
+
// To minimize padding, data members are divided into three sections:
// (1) members assumed to align to 8 bytes
// (2) members corresponding to message fields, re-ordered to optimize
@@ -618,53 +1022,137 @@ GenerateClassDefinition(io::Printer* printer) {
"\n");
}
- if (HasUnknownFields(descriptor_->file())) {
+ if (UseUnknownFieldSet(descriptor_->file())) {
printer->Print(
- "::google::protobuf::UnknownFieldSet _unknown_fields_;\n"
+ "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n");
+ } else {
+ printer->Print(
+ "::std::string _unknown_fields_;\n"
+ "::google::protobuf::Arena* _arena_ptr_;\n"
"\n");
}
+ 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;
+ }
+ } else {
+ // Without field presence, we need another way to disambiguate the default
+ // instance, because the default instance's submessage fields (if any) store
+ // pointers to the default instances of the submessages even when they
+ // aren't present. Alternatives to this approach might be to (i) use a
+ // tagged pointer on all message fields, setting a tag bit for "not really
+ // present, just default instance"; or (ii) comparing |this| against the
+ // return value from GeneratedMessageFactory::GetPrototype() in all
+ // has_$field$() calls. However, both of these options are much more
+ // expensive (in code size and CPU overhead) than just checking a field in
+ // the message. Long-term, the best solution would be to rearchitect the
+ // default instance design not to store pointers to submessage default
+ // instances, and have reflection get those some other way; but that change
+ // would have too much impact on proto2.
+ printer->Print(
+ "bool _is_default_instance_;\n");
+ }
+
// Field members:
+ // List fields which doesn't belong to any oneof
vector<const FieldDescriptor*> fields;
+ hash_map<string, int> fieldname_to_chunk;
for (int i = 0; i < descriptor_->field_count(); i++) {
- fields.push_back(descriptor_->field(i));
+ if (!descriptor_->field(i)->containing_oneof()) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ fields.push_back(field);
+ fieldname_to_chunk[FieldName(field)] = i / 8;
+ }
}
OptimizePadding(&fields);
+ // Emit some private and static members
+ runs_of_fields_ = vector< vector<string> >(1);
for (int i = 0; i < fields.size(); ++i) {
- field_generators_.get(fields[i]).GeneratePrivateMembers(printer);
+ const FieldDescriptor* field = fields[i];
+ const FieldGenerator& generator = field_generators_.get(field);
+ generator.GenerateStaticMembers(printer);
+ generator.GeneratePrivateMembers(printer);
+ if (CanClearByZeroing(field)) {
+ const string& fieldname = FieldName(field);
+ if (!runs_of_fields_.back().empty() &&
+ (fieldname_to_chunk[runs_of_fields_.back().back()] !=
+ fieldname_to_chunk[fieldname])) {
+ runs_of_fields_.push_back(vector<string>());
+ }
+ runs_of_fields_.back().push_back(fieldname);
+ } else if (!runs_of_fields_.back().empty()) {
+ runs_of_fields_.push_back(vector<string>());
+ }
+ }
+
+ // For each oneof generate a union
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "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();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ field_generators_.get(descriptor_->oneof_decl(i)->
+ field(j)).GeneratePrivateMembers(printer);
+ }
+ printer->Outdent();
+ printer->Print(
+ "} $oneof_name$_;\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ field_generators_.get(descriptor_->oneof_decl(i)->
+ field(j)).GenerateStaticMembers(printer);
+ }
}
// Members assumed to align to 4 bytes:
- // TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it.
- printer->Print(
- "\n"
- "mutable int _cached_size_;\n");
+ if (need_to_emit_cached_size) {
+ printer->Print(cached_size_decl.c_str());
+ need_to_emit_cached_size = false;
+ }
- // Generate _has_bits_.
- if (descriptor_->field_count() > 0) {
+ // Generate _oneof_case_.
+ if (descriptor_->oneof_decl_count() > 0) {
printer->Print(vars,
- "::google::protobuf::uint32 _has_bits_[($field_count$ + 31) / 32];\n"
- "\n");
- } else {
- // Zero-size arrays aren't technically allowed, and MSVC in particular
- // doesn't like them. We still need to declare these arrays to make
- // other code compile. Since this is an uncommon case, we'll just declare
- // them with size 1 and waste some space. Oh well.
- printer->Print(
- "::google::protobuf::uint32 _has_bits_[1];\n"
+ "::google::protobuf::uint32 _oneof_case_[$oneof_decl_count$];\n"
"\n");
}
// Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as
// friends so that they can access private static variables like
// default_instance_ and reflection_.
- printer->Print(
+ PrintHandlingOptionalStaticInitializers(
+ descriptor_->file(), printer,
+ // With static initializers.
"friend void $dllexport_decl$ $adddescriptorsname$();\n",
- "dllexport_decl", dllexport_decl_,
+ // Without.
+ "friend void $dllexport_decl$ $adddescriptorsname$_impl();\n",
+ // Vars.
+ "dllexport_decl", options_.dllexport_decl,
"adddescriptorsname",
- GlobalAddDescriptorsName(descriptor_->file()->name()));
+ GlobalAddDescriptorsName(descriptor_->file()->name()));
+
printer->Print(
"friend void $assigndescriptorsname$();\n"
"friend void $shutdownfilename$();\n"
@@ -680,26 +1168,76 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Outdent();
printer->Print(vars, "};");
+ GOOGLE_DCHECK(!need_to_emit_cached_size);
}
void MessageGenerator::
-GenerateInlineMethods(io::Printer* printer) {
+GenerateInlineMethods(io::Printer* printer, bool is_inline) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
- nested_generators_[i]->GenerateInlineMethods(printer);
+ // map entry message doesn't need inline methods. Since map entry message
+ // cannot be a top level class, we just need to avoid calling
+ // GenerateInlineMethods here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
+ nested_generators_[i]->GenerateInlineMethods(printer, is_inline);
printer->Print(kThinSeparator);
printer->Print("\n");
}
- GenerateFieldAccessorDefinitions(printer);
+ GenerateFieldAccessorDefinitions(printer, is_inline);
+
+ // Generate oneof_case() functions.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ map<string, string> vars;
+ vars["class_name"] = classname_;
+ vars["camel_oneof_name"] = UnderscoresToCamelCase(
+ descriptor_->oneof_decl(i)->name(), true);
+ vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
+ vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+ vars["inline"] = is_inline ? "inline " : "";
+ printer->Print(
+ vars,
+ "$inline$$class_name$::$camel_oneof_name$Case $class_name$::"
+ "$oneof_name$_case() const {\n"
+ " return $class_name$::$camel_oneof_name$Case("
+ "_oneof_case_[$oneof_index$]);\n"
+ "}\n");
+ }
}
void MessageGenerator::
GenerateDescriptorDeclarations(io::Printer* printer) {
- printer->Print(
- "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n"
- "const ::google::protobuf::internal::GeneratedMessageReflection*\n"
- " $name$_reflection_ = NULL;\n",
- "name", classname_);
+ if (!IsMapEntryMessage(descriptor_)) {
+ printer->Print(
+ "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n"
+ "const ::google::protobuf::internal::GeneratedMessageReflection*\n"
+ " $name$_reflection_ = NULL;\n",
+ "name", classname_);
+ } else {
+ printer->Print(
+ "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n",
+ "name", classname_);
+ }
+
+ // Generate oneof default instance for reflection usage.
+ if (descriptor_->oneof_decl_count() > 0) {
+ printer->Print("struct $name$OneofInstance {\n",
+ "name", classname_);
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(" ");
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+ (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+ EffectiveStringCType(field) != FieldOptions::STRING)) {
+ printer->Print("const ");
+ }
+ field_generators_.get(field).GeneratePrivateMembers(printer);
+ }
+ }
+
+ printer->Print("}* $name$_default_oneof_instance_ = NULL;\n",
+ "name", classname_);
+ }
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
nested_generators_[i]->GenerateDescriptorDeclarations(printer);
@@ -731,19 +1269,44 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
"$parent$_descriptor_->nested_type($index$);\n");
}
+ if (IsMapEntryMessage(descriptor_)) return;
+
// Generate the offsets.
GenerateOffsets(printer);
+ const bool pass_pool_and_factory = false;
+ vars["fn"] = pass_pool_and_factory ?
+ "new ::google::protobuf::internal::GeneratedMessageReflection" :
+ "::google::protobuf::internal::GeneratedMessageReflection"
+ "::NewGeneratedMessageReflection";
// Construct the reflection object.
printer->Print(vars,
"$classname$_reflection_ =\n"
- " new ::google::protobuf::internal::GeneratedMessageReflection(\n"
+ " $fn$(\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("
@@ -753,10 +1316,47 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
printer->Print(vars,
" -1,\n");
}
+
+ if (descriptor_->oneof_decl_count() > 0) {
+ printer->Print(vars,
+ " $classname$_default_oneof_instance_,\n"
+ " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "$classname$, _oneof_case_[0]),\n");
+ }
+
+ if (pass_pool_and_factory) {
+ printer->Print(
+ " ::google::protobuf::DescriptorPool::generated_pool(),\n");
+ printer->Print(vars,
+ " ::google::protobuf::MessageFactory::generated_factory(),\n");
+ }
+
printer->Print(vars,
- " ::google::protobuf::DescriptorPool::generated_pool(),\n"
- " ::google::protobuf::MessageFactory::generated_factory(),\n"
- " 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");
+ }
+
+ // is_default_instance_ offset.
+ if (HasFieldPresence(descriptor_->file())) {
+ printer->Print(vars,
+ " -1);\n");
+ } else {
+ printer->Print(vars,
+ " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "$classname$, _is_default_instance_));\n");
+ }
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -771,10 +1371,37 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
void MessageGenerator::
GenerateTypeRegistrations(io::Printer* printer) {
// Register this message type with the message factory.
- printer->Print(
- "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
- " $classname$_descriptor_, &$classname$::default_instance());\n",
- "classname", classname_);
+ if (!IsMapEntryMessage(descriptor_)) {
+ printer->Print(
+ "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
+ " $classname$_descriptor_, &$classname$::default_instance());\n",
+ "classname", classname_);
+ }
+ else {
+ map<string, string> vars;
+ CollectMapInfo(descriptor_, &vars);
+ vars["classname"] = classname_;
+
+ const FieldDescriptor* val = descriptor_->FindFieldByName("value");
+ if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO2 &&
+ val->type() == FieldDescriptor::TYPE_ENUM) {
+ const EnumValueDescriptor* default_value = val->default_value_enum();
+ vars["default_enum_value"] = Int32ToString(default_value->number());
+ } else {
+ vars["default_enum_value"] = "0";
+ }
+
+ printer->Print(vars,
+ "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
+ " $classname$_descriptor_,\n"
+ " ::google::protobuf::internal::MapEntry<\n"
+ " $key$,\n"
+ " $val$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$>::CreateDefaultInstance(\n"
+ " $classname$_descriptor_));\n");
+ }
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -784,6 +1411,15 @@ GenerateTypeRegistrations(io::Printer* printer) {
void MessageGenerator::
GenerateDefaultInstanceAllocator(io::Printer* printer) {
+ // Construct the default instances of all fields, as they will be used
+ // when creating the default instance of the entire message.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateDefaultInstanceAllocator(printer);
+ }
+
+ if (IsMapEntryMessage(descriptor_)) return;
+
// Construct the default instance. We can't call InitAsDefaultInstance() yet
// because we need to make sure all default instances that this one might
// depend on are constructed first.
@@ -791,6 +1427,13 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) {
"$classname$::default_instance_ = new $classname$();\n",
"classname", classname_);
+ if ((descriptor_->oneof_decl_count() > 0) &&
+ HasDescriptorMethods(descriptor_->file())) {
+ printer->Print(
+ "$classname$_default_oneof_instance_ = new $classname$OneofInstance();\n",
+ "classname", classname_);
+ }
+
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
nested_generators_[i]->GenerateDefaultInstanceAllocator(printer);
@@ -811,6 +1454,10 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need to initialize default instance manually.
+ // Since map entry message cannot be a top level class, we just need to
+ // avoid calling DefaultInstanceInitializer here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateDefaultInstanceInitializer(printer);
}
}
@@ -822,13 +1469,25 @@ GenerateShutdownCode(io::Printer* printer) {
"classname", classname_);
if (HasDescriptorMethods(descriptor_->file())) {
+ if (descriptor_->oneof_decl_count() > 0) {
+ printer->Print(
+ "delete $classname$_default_oneof_instance_;\n",
+ "classname", classname_);
+ }
printer->Print(
"delete $classname$_reflection_;\n",
"classname", classname_);
}
+ // Handle default instances of fields.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateShutdownCode(printer);
+ }
+
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateShutdownCode(printer);
}
}
@@ -840,6 +1499,10 @@ GenerateClassMethods(io::Printer* printer) {
}
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need class methods. Since map entry message
+ // cannot be a top level class, we just need to avoid calling
+ // GenerateClassMethods here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateClassMethods(printer);
printer->Print("\n");
printer->Print(kThinSeparator);
@@ -873,6 +1536,11 @@ GenerateClassMethods(io::Printer* printer) {
GenerateStructors(printer);
printer->Print("\n");
+ if (descriptor_->oneof_decl_count() > 0) {
+ GenerateOneofClear(printer);
+ printer->Print("\n");
+ }
+
if (HasGeneratedMethods(descriptor_->file())) {
GenerateClear(printer);
printer->Print("\n");
@@ -932,15 +1600,33 @@ GenerateOffsets(io::Printer* printer) {
printer->Print(
"static const int $classname$_offsets_[$field_count$] = {\n",
"classname", classname_,
- "field_count", SimpleItoa(max(1, descriptor_->field_count())));
+ "field_count", SimpleItoa(max(
+ 1, descriptor_->field_count() + descriptor_->oneof_decl_count())));
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
+ if (field->containing_oneof()) {
+ printer->Print(
+ "PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET("
+ "$classname$_default_oneof_instance_, $name$_),\n",
+ "classname", classname_,
+ "name", FieldName(field));
+ } else {
+ printer->Print(
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "$name$_),\n",
+ "classname", classname_,
+ "name", FieldName(field));
+ }
+ }
+
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
printer->Print(
"GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n",
"classname", classname_,
- "name", FieldName(field));
+ "name", oneof->name());
}
printer->Outdent();
@@ -954,16 +1640,32 @@ GenerateSharedConstructorCode(io::Printer* printer) {
"classname", classname_);
printer->Indent();
- printer->Print(
- "_cached_size_ = 0;\n");
+ if (!HasFieldPresence(descriptor_->file())) {
+ printer->Print(
+ " _is_default_instance_ = false;\n");
+ }
+
+ printer->Print(StrCat(
+ uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "",
+ "_cached_size_ = 0;\n").c_str());
for (int i = 0; i < descriptor_->field_count(); i++) {
- field_generators_.get(descriptor_->field(i))
- .GenerateConstructorCode(printer);
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateConstructorCode(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(
+ "clear_has_$oneof_name$();\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ }
printer->Outdent();
printer->Print("}\n\n");
@@ -975,14 +1677,37 @@ GenerateSharedDestructorCode(io::Printer* printer) {
"void $classname$::SharedDtor() {\n",
"classname", classname_);
printer->Indent();
- // Write the destructors for each field.
+ 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++) {
- field_generators_.get(descriptor_->field(i))
- .GenerateDestructorCode(printer);
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateDestructorCode(printer);
+ }
}
- printer->Print(
- "if (this != default_instance_) {\n");
+ // Generate code to destruct oneofs. Clearing should do the work.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "if (has_$oneof_name$()) {\n"
+ " clear_$oneof_name$();\n"
+ "}\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ }
+
+ PrintHandlingOptionalStaticInitializers(
+ descriptor_->file(), printer,
+ // With static initializers.
+ "if (this != default_instance_) {\n",
+ // Without.
+ "if (this != &default_instance()) {\n");
// We need to delete all embedded messages.
// TODO(kenton): If we make unset messages point at default instances
@@ -993,8 +1718,12 @@ GenerateSharedDestructorCode(io::Printer* printer) {
if (!field->is_repeated() &&
field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- printer->Print(" delete $name$_;\n",
- "name", FieldName(field));
+ // Skip oneof members
+ if (!field->containing_oneof()) {
+ printer->Print(
+ " delete $name$_;\n",
+ "name", FieldName(field));
+ }
}
}
@@ -1006,23 +1735,118 @@ GenerateSharedDestructorCode(io::Printer* printer) {
}
void MessageGenerator::
+GenerateArenaDestructorCode(io::Printer* printer) {
+ // Generate the ArenaDtor() method. Track whether any fields actually produced
+ // code that needs to be called.
+ printer->Print(
+ "void $classname$::ArenaDtor(void* object) {\n",
+ "classname", classname_);
+ printer->Indent();
+
+ // This code is placed inside a static method, rather than an ordinary one,
+ // since that simplifies Arena's destructor list (ordinary function pointers
+ // rather than member function pointers). _this is the object being
+ // destructed.
+ printer->Print(
+ "$classname$* _this = reinterpret_cast< $classname$* >(object);\n"
+ // avoid an "unused variable" warning in case no fields have dtor code.
+ "(void)_this;\n",
+ "classname", classname_);
+
+ bool need_registration = false;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (field_generators_.get(descriptor_->field(i))
+ .GenerateArenaDestructorCode(printer)) {
+ need_registration = true;
+ }
+ }
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+
+ if (need_registration) {
+ printer->Print(
+ "inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
+ " if (arena != NULL) {"
+ " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
+ " }\n"
+ "}\n",
+ "classname", classname_);
+ } else {
+ printer->Print(
+ "void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
+ "}\n",
+ "classname", classname_);
+ }
+}
+
+void MessageGenerator::
GenerateStructors(io::Printer* printer) {
string superclass = SuperClassName(descriptor_);
+ string initializer_with_arena;
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ initializer_with_arena = "_internal_metadata_(arena)";
+ } else {
+ initializer_with_arena = "_arena_ptr_(arena)";
+ }
+ if (descriptor_->extension_range_count() > 0) {
+ initializer_with_arena = string("\n _extensions_(arena)") +
+ (!initializer_with_arena.empty() ? ", " : "") + initializer_with_arena;
+ } else {
+ initializer_with_arena = "\n " + initializer_with_arena;
+ }
+
+ // Initialize member variables with arena constructor.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ bool has_arena_constructor = descriptor_->field(i)->is_repeated();
+ if (has_arena_constructor) {
+ initializer_with_arena += string(",\n ") +
+ FieldName(descriptor_->field(i)) + string("_(arena)");
+ }
+ }
+ initializer_with_arena = superclass + "()" +
+ (!initializer_with_arena.empty() ? "," : " ") + initializer_with_arena;
+
+ string initializer_null;
+ initializer_null = (UseUnknownFieldSet(descriptor_->file()) ?
+ ", _internal_metadata_(NULL) " : ", _arena_ptr_(NULL)");
- // Generate the default constructor.
printer->Print(
- "$classname$::$classname$()\n"
- " : $superclass$() {\n"
- " SharedCtor();\n"
- "}\n",
- "classname", classname_,
- "superclass", superclass);
+ "$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"
"void $classname$::InitAsDefaultInstance() {\n",
"classname", classname_);
+ if (!HasFieldPresence(descriptor_->file())) {
+ printer->Print(
+ " _is_default_instance_ = true;\n");
+ }
+
// The default instance needs all of its embedded message pointers
// cross-linked to other default instances. We can't do this initialization
// in the constructor because some other default instances may not have been
@@ -1033,11 +1857,28 @@ GenerateStructors(io::Printer* printer) {
const FieldDescriptor* field = descriptor_->field(i);
if (!field->is_repeated() &&
- field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- printer->Print(
- " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n",
- "name", FieldName(field),
- "type", FieldMessageTypeName(field));
+ field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ (field->containing_oneof() == NULL ||
+ HasDescriptorMethods(descriptor_->file()))) {
+ string name;
+ if (field->containing_oneof()) {
+ name = classname_ + "_default_oneof_instance_->";
+ }
+ name += FieldName(field);
+ PrintHandlingOptionalStaticInitializers(
+ descriptor_->file(), printer,
+ // With static initializers.
+ " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n",
+ // Without.
+ " $name$_ = const_cast< $type$*>(\n"
+ " $type$::internal_default_instance());\n",
+ // Vars.
+ "name", name,
+ "type", FieldMessageTypeName(field));
+ } else if (field->containing_oneof() &&
+ HasDescriptorMethods(descriptor_->file())) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateConstructorCode(printer);
}
}
printer->Print(
@@ -1047,13 +1888,25 @@ 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"
"}\n"
"\n",
"classname", classname_,
- "superclass", superclass);
+ "superclass", superclass,
+ "full_name", descriptor_->full_name());
// Generate the shared constructor code.
GenerateSharedConstructorCode(printer);
@@ -1061,14 +1914,21 @@ GenerateStructors(io::Printer* printer) {
// Generate the destructor.
printer->Print(
"$classname$::~$classname$() {\n"
+ " // @@protoc_insertion_point(destructor:$full_name$)\n"
" SharedDtor();\n"
"}\n"
"\n",
- "classname", classname_);
+ "classname", classname_,
+ "full_name", descriptor_->full_name());
// 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"
@@ -1093,86 +1953,196 @@ GenerateStructors(io::Printer* printer) {
}
printer->Print(
- "const $classname$& $classname$::default_instance() {\n"
- " if (default_instance_ == NULL) $adddescriptorsname$();"
+ "const $classname$& $classname$::default_instance() {\n",
+ "classname", classname_);
+
+ PrintHandlingOptionalStaticInitializers(
+ descriptor_->file(), printer,
+ // With static initializers.
+ " if (default_instance_ == NULL) $adddescriptorsname$();\n",
+ // Without.
+ " $adddescriptorsname$();\n",
+ // Vars.
+ "adddescriptorsname",
+ GlobalAddDescriptorsName(descriptor_->file()->name()));
+
+ printer->Print(
" return *default_instance_;\n"
"}\n"
"\n"
"$classname$* $classname$::default_instance_ = NULL;\n"
- "\n"
- "$classname$* $classname$::New() const {\n"
- " return new $classname$;\n"
- "}\n",
- "classname", classname_,
- "adddescriptorsname",
- GlobalAddDescriptorsName(descriptor_->file()->name()));
+ "\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_);
+ }
}
+// Return the number of bits set in n, a non-negative integer.
+static int popcnt(uint32 n) {
+ int result = 0;
+ while (n != 0) {
+ result += (n & 1);
+ n = n / 2;
+ }
+ return result;
+}
+
void MessageGenerator::
GenerateClear(io::Printer* printer) {
printer->Print("void $classname$::Clear() {\n",
"classname", classname_);
printer->Indent();
- int last_index = -1;
-
+ // Step 1: Extensions
if (descriptor_->extension_range_count() > 0) {
printer->Print("_extensions_.Clear();\n");
}
+ // Step 2: Everything but extensions, repeateds, unions.
+ // These are handled in chunks of 8. The first chunk is
+ // the non-extensions-non-repeateds-non-unions 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.
+ set<int> step2_indices;
+ hash_map<string, int> fieldname_to_chunk;
+ hash_map<int, string> memsets_for_chunk;
+ hash_map<int, int> memset_field_count_for_chunk;
+ hash_set<string> handled; // fields that appear anywhere in memsets_for_chunk
+ hash_map<int, uint32> fields_mask_for_chunk;
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
+ if (!field->is_repeated() && !field->containing_oneof()) {
+ step2_indices.insert(i);
+ int chunk = i / 8;
+ fieldname_to_chunk[FieldName(field)] = chunk;
+ fields_mask_for_chunk[chunk] |= static_cast<uint32>(1) << (i % 32);
+ }
+ }
- if (!field->is_repeated()) {
- // We can use the fact that _has_bits_ is a giant bitfield to our
- // advantage: We can check up to 32 bits at a time for equality to
- // zero, and skip the whole range if so. This can improve the speed
- // of Clear() for messages which contain a very large number of
- // optional fields of which only a few are used at a time. Here,
- // we've chosen to check 8 bits at a time rather than 32.
- if (i / 8 != last_index / 8 || last_index < 0) {
- if (last_index >= 0) {
- printer->Outdent();
- printer->Print("}\n");
- }
- printer->Print(
- "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
- "index", SimpleItoa(field->index()));
- printer->Indent();
+ // Step 2a: Greedily seek runs of fields that can be cleared by memset-to-0.
+ // The generated code uses two macros to help it clear runs of fields:
+ // ZR_HELPER_(f1) - ZR_HELPER_(f0) computes the difference, in bytes, of the
+ // positions of two fields in the Message.
+ // ZR_ zeroes a non-empty range of fields via memset.
+ const char* macros =
+ "#define ZR_HELPER_(f) reinterpret_cast<char*>(\\\n"
+ " &reinterpret_cast<$classname$*>(16)->f)\n\n"
+ "#define ZR_(first, last) do {\\\n"
+ " ::memset(&first, 0,\\\n"
+ " ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n"
+ "} while (0)\n\n";
+ for (int i = 0; i < runs_of_fields_.size(); i++) {
+ const vector<string>& run = runs_of_fields_[i];
+ if (run.size() < 2) continue;
+ const string& first_field_name = run[0];
+ const string& last_field_name = run.back();
+ int chunk = fieldname_to_chunk[run[0]];
+ memsets_for_chunk[chunk].append(
+ "ZR_(" + first_field_name + "_, " + last_field_name + "_);\n");
+ for (int j = 0; j < run.size(); j++) {
+ GOOGLE_DCHECK_EQ(chunk, fieldname_to_chunk[run[j]]);
+ handled.insert(run[j]);
+ }
+ memset_field_count_for_chunk[chunk] += run.size();
+ }
+ const bool macros_are_needed = handled.size() > 0;
+ if (macros_are_needed) {
+ printer->Outdent();
+ printer->Print(macros,
+ "classname", classname_);
+ printer->Indent();
+ }
+ // Step 2b: Finish step 2, ignoring fields handled in step 2a.
+ int last_index = -1;
+ bool chunk_block_in_progress = false;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (step2_indices.count(i) == 0) continue;
+ const FieldDescriptor* field = descriptor_->field(i);
+ const string fieldname = FieldName(field);
+ 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;
}
- last_index = i;
-
- // It's faster to just overwrite primitive types, but we should
- // only clear strings and messages if they were set.
- // TODO(kenton): Let the CppFieldGenerator decide this somehow.
- bool should_check_bit =
- field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
- field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
-
- if (should_check_bit) {
- printer->Print(
- "if (has_$name$()) {\n",
- "name", FieldName(field));
- printer->Indent();
+ // Start chunk.
+ 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 {
+ 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());
+ }
+ last_index = i;
+ if (handled.count(fieldname) > 0) continue;
+
+ // It's faster to just overwrite primitive types, but we should
+ // only clear strings and messages if they were set.
+ // TODO(kenton): Let the CppFieldGenerator decide this somehow.
+ bool should_check_bit =
+ field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+ field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
+
+ 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);
+ field_generators_.get(field).GenerateClearingCode(printer);
- if (should_check_bit) {
- printer->Outdent();
- printer->Print("}\n");
- }
+ if (have_enclosing_if) {
+ printer->Outdent();
+ printer->Print("}\n");
}
}
- if (last_index >= 0) {
+ if (chunk_block_in_progress) {
printer->Outdent();
printer->Print("}\n");
}
+ if (macros_are_needed) {
+ printer->Outdent();
+ printer->Print("\n#undef ZR_HELPER_\n#undef ZR_\n\n");
+ printer->Indent();
+ }
- // Repeated fields don't use _has_bits_ so we clear them in a separate
- // pass.
+ // Step 3: Repeated fields don't use _has_bits_; emit code to clear them here.
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
@@ -1181,12 +2151,29 @@ GenerateClear(io::Printer* printer) {
}
}
- printer->Print(
- "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
+ // Step 4: Unions.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "clear_$oneof_name$();\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name());
+ }
- if (HasUnknownFields(descriptor_->file())) {
+ if (HasFieldPresence(descriptor_->file())) {
+ // Step 5: Everything 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();
@@ -1194,13 +2181,95 @@ GenerateClear(io::Printer* printer) {
}
void MessageGenerator::
+GenerateOneofClear(io::Printer* printer) {
+ // Generated function clears the active field and union case (e.g. foo_case_).
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "void $classname$::clear_$oneofname$() {\n",
+ "classname", classname_,
+ "oneofname", descriptor_->oneof_decl(i)->name());
+ printer->Indent();
+ printer->Print(
+ "switch($oneofname$_case()) {\n",
+ "oneofname", descriptor_->oneof_decl(i)->name());
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ "case k$field_name$: {\n",
+ "field_name", UnderscoresToCamelCase(field->name(), true));
+ printer->Indent();
+ // We clear only allocated objects in oneofs
+ if (!IsStringOrMessage(field)) {
+ printer->Print(
+ "// No need to clear\n");
+ } else {
+ field_generators_.get(field).GenerateClearingCode(printer);
+ }
+ printer->Print(
+ "break;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+ printer->Print(
+ "case $cap_oneof_name$_NOT_SET: {\n"
+ " break;\n"
+ "}\n",
+ "cap_oneof_name",
+ ToUpper(descriptor_->oneof_decl(i)->name()));
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n",
+ "oneof_index", SimpleItoa(i),
+ "cap_oneof_name",
+ ToUpper(descriptor_->oneof_decl(i)->name()));
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+ }
+}
+
+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++) {
@@ -1208,13 +2277,33 @@ GenerateSwap(io::Printer* printer) {
field_generators_.get(field).GenerateSwappingCode(printer);
}
- 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));
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "std::swap($oneof_name$_, other->$oneof_name$_);\n"
+ "std::swap(_oneof_case_[$i$], other->_oneof_case_[$i$]);\n",
+ "oneof_name", descriptor_->oneof_decl(i)->name(),
+ "i", SimpleItoa(i));
}
- if (HasUnknownFields(descriptor_->file())) {
- printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
+ 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 (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 {
+ // 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) {
@@ -1226,8 +2315,6 @@ GenerateSwap(io::Printer* printer) {
printer->Outdent();
printer->Print("}\n");
- printer->Outdent();
- printer->Print("}\n");
}
void MessageGenerator::
@@ -1237,7 +2324,7 @@ GenerateMergeFrom(io::Printer* printer) {
// base class as a parameter).
printer->Print(
"void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
- " GOOGLE_CHECK_NE(&from, this);\n",
+ " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n",
"classname", classname_);
printer->Indent();
@@ -1272,7 +2359,7 @@ GenerateMergeFrom(io::Printer* printer) {
// Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast.
printer->Print(
"void $classname$::MergeFrom(const $classname$& from) {\n"
- " GOOGLE_CHECK_NE(&from, this);\n",
+ " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n",
"classname", classname_);
printer->Indent();
@@ -1286,40 +2373,85 @@ GenerateMergeFrom(io::Printer* printer) {
}
}
+ // Merge oneof fields. Oneof field requires oneof case check.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+ printer->Print(
+ "switch (from.$oneofname$_case()) {\n",
+ "oneofname", descriptor_->oneof_decl(i)->name());
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ "case k$field_name$: {\n",
+ "field_name", UnderscoresToCamelCase(field->name(), true));
+ printer->Indent();
+ field_generators_.get(field).GenerateMergingCode(printer);
+ printer->Print(
+ "break;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+ printer->Print(
+ "case $cap_oneof_name$_NOT_SET: {\n"
+ " break;\n"
+ "}\n",
+ "cap_oneof_name",
+ ToUpper(descriptor_->oneof_decl(i)->name()));
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+
// Merge Optional and Required fields (after a _has_bit check).
int last_index = -1;
for (int i = 0; i < descriptor_->field_count(); ++i) {
const FieldDescriptor* field = descriptor_->field(i);
- if (!field->is_repeated()) {
- // 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 (!field->is_repeated() && !field->containing_oneof()) {
+ 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");
}
@@ -1328,9 +2460,16 @@ GenerateMergeFrom(io::Printer* printer) {
printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
}
- if (HasUnknownFields(descriptor_->file())) {
- printer->Print(
- "mutable_unknown_fields()->MergeFrom(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();
@@ -1377,25 +2516,61 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// Special-case MessageSet.
printer->Print(
"bool $classname$::MergePartialFromCodedStream(\n"
- " ::google::protobuf::io::CodedInputStream* input) {\n"
+ " ::google::protobuf::io::CodedInputStream* input) {\n",
+ "classname", classname_);
+
+ PrintHandlingOptionalStaticInitializers(
+ descriptor_->file(), printer,
+ // With static initializers.
" return _extensions_.ParseMessageSet(input, default_instance_,\n"
- " mutable_unknown_fields());\n"
- "}\n",
+ " mutable_unknown_fields());\n",
+ // Without.
+ " return _extensions_.ParseMessageSet(input, &default_instance(),\n"
+ " mutable_unknown_fields());\n",
+ // Vars.
"classname", classname_);
+
+ printer->Print(
+ "}\n");
return;
}
printer->Print(
"bool $classname$::MergePartialFromCodedStream(\n"
" ::google::protobuf::io::CodedInputStream* input) {\n"
- "#define DO_(EXPRESSION) if (!(EXPRESSION)) return false\n"
- " ::google::protobuf::uint32 tag;\n"
- " while ((tag = input->ReadTag()) != 0) {\n",
+ "#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure\n"
+ " ::google::protobuf::uint32 tag;\n",
"classname", classname_);
+ if (!UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ " ::google::protobuf::io::StringOutputStream unknown_fields_string(\n"
+ " mutable_unknown_fields());\n"
+ " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
+ " &unknown_fields_string);\n");
+ }
+
+ printer->Print(
+ " // @@protoc_insertion_point(parse_start:$full_name$)\n",
+ "full_name", descriptor_->full_name());
+
printer->Indent();
+ printer->Print("for (;;) {\n");
printer->Indent();
+ google::protobuf::scoped_array<const FieldDescriptor * > ordered_fields(
+ SortFieldsByNumber(descriptor_));
+ uint32 maxtag = descriptor_->field_count() == 0 ? 0 :
+ WireFormat::MakeTag(ordered_fields[descriptor_->field_count() - 1]);
+ const int kCutoff0 = 127; // fits in 1-byte varint
+ const int kCutoff1 = (127 << 7) + 127; // fits in 2-byte varint
+ printer->Print("::std::pair< ::google::protobuf::uint32, bool> p = "
+ "input->ReadTagWithCutoff($max$);\n"
+ "tag = p.first;\n"
+ "if (!p.second) goto handle_unusual;\n",
+ "max", SimpleItoa(maxtag <= kCutoff0 ? kCutoff0 :
+ (maxtag <= kCutoff1 ? kCutoff1 :
+ maxtag)));
if (descriptor_->field_count() > 0) {
// We don't even want to print the switch() if we have no fields because
// MSVC dislikes switch() statements that contain only a default value.
@@ -1405,14 +2580,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// of each case. However, this is actually a bit slower in practice as it
// creates a jump table that is 8x larger and sparser, and meanwhile the
// if()s are highly predictable.
- printer->Print(
- "switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {\n");
+ printer->Print("switch (::google::protobuf::internal::WireFormatLite::"
+ "GetTagFieldNumber(tag)) {\n");
printer->Indent();
- scoped_array<const FieldDescriptor*> ordered_fields(
- SortFieldsByNumber(descriptor_));
-
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = ordered_fields[i];
@@ -1425,10 +2597,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
const FieldGenerator& field_generator = field_generators_.get(field);
// Emit code to parse the common, expected case.
- printer->Print(
- "if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n"
- " ::google::protobuf::internal::WireFormatLite::WIRETYPE_$wiretype$) {\n",
- "wiretype", kWireTypeNames[WireFormat::WireTypeForField(field)]);
+ printer->Print("if (tag == $commontag$) {\n",
+ "commontag", SimpleItoa(WireFormat::MakeTag(field)));
if (i > 0 || (field->is_repeated() && !field->options().packed())) {
printer->Print(
@@ -1446,20 +2616,22 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// Emit code to parse unexpectedly packed or unpacked values.
if (field->is_packable() && field->options().packed()) {
- printer->Print(
- "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n"
- " == ::google::protobuf::internal::WireFormatLite::\n"
- " WIRETYPE_$wiretype$) {\n",
- "wiretype",
- kWireTypeNames[WireFormat::WireTypeForFieldType(field->type())]);
+ internal::WireFormatLite::WireType wiretype =
+ WireFormat::WireTypeForFieldType(field->type());
+ printer->Print("} else if (tag == $uncommontag$) {\n",
+ "uncommontag", SimpleItoa(
+ internal::WireFormatLite::MakeTag(
+ field->number(), wiretype)));
printer->Indent();
field_generator.GenerateMergeFromCodedStream(printer);
printer->Outdent();
} else if (field->is_packable() && !field->options().packed()) {
- printer->Print(
- "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n"
- " == ::google::protobuf::internal::WireFormatLite::\n"
- " WIRETYPE_LENGTH_DELIMITED) {\n");
+ internal::WireFormatLite::WireType wiretype =
+ internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+ printer->Print("} else if (tag == $uncommontag$) {\n",
+ "uncommontag", SimpleItoa(
+ internal::WireFormatLite::MakeTag(
+ field->number(), wiretype)));
printer->Indent();
field_generator.GenerateMergeFromCodedStreamWithPacking(printer);
printer->Outdent();
@@ -1467,7 +2639,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print(
"} else {\n"
- " goto handle_uninterpreted;\n"
+ " goto handle_unusual;\n"
"}\n");
// switch() is slow since it can't be predicted well. Insert some if()s
@@ -1491,7 +2663,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// Expect EOF.
// TODO(kenton): Expect group end-tag?
printer->Print(
- "if (input->ExpectAtEnd()) return true;\n");
+ "if (input->ExpectAtEnd()) goto success;\n");
}
printer->Print(
@@ -1501,17 +2673,19 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print("}\n\n");
}
- printer->Print(
- "default: {\n"
- "handle_uninterpreted:\n");
+ printer->Print("default: {\n");
printer->Indent();
}
- // Is this an end-group tag? If so, this must be the end of the message.
+ printer->Outdent();
+ printer->Print("handle_unusual:\n");
+ printer->Indent();
+ // If tag is 0 or an end-group tag then this must be the end of the message.
printer->Print(
- "if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n"
+ "if (tag == 0 ||\n"
+ " ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n"
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n"
- " return true;\n"
+ " goto success;\n"
"}\n");
// Handle extension ranges.
@@ -1540,13 +2714,33 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
}
printer->Print(") {\n");
- if (HasUnknownFields(descriptor_->file())) {
- printer->Print(
- " 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 {
- printer->Print(
- " DO_(_extensions_.ParseField(tag, input, default_instance_));\n");
+ PrintHandlingOptionalStaticInitializers(
+ descriptor_->file(), printer,
+ // With static initializers.
+ " DO_(_extensions_.ParseField(tag, input, default_instance_);\n",
+ // Without.
+ " DO_(_extensions_.ParseField(tag, input, &default_instance());\n");
}
printer->Print(
" continue;\n"
@@ -1554,10 +2748,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
// We really don't recognize this tag. Skip it.
- if (HasUnknownFields(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(input, tag));\n");
@@ -1574,21 +2774,30 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Outdent();
printer->Outdent();
printer->Print(
- " }\n" // while
+ " }\n" // for (;;)
+ "success:\n"
+ " // @@protoc_insertion_point(parse_success:$full_name$)\n"
" return true;\n"
+ "failure:\n"
+ " // @@protoc_insertion_point(parse_failure:$full_name$)\n"
+ " return false;\n"
"#undef DO_\n"
- "}\n");
+ "}\n", "full_name", descriptor_->full_name());
}
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) {
@@ -1598,7 +2807,7 @@ void MessageGenerator::GenerateSerializeOneField(
field_generators_.get(field).GenerateSerializeWithCachedSizes(printer);
}
- if (!field->is_repeated()) {
+ if (have_enclosing_if) {
printer->Outdent();
printer->Print("}\n");
}
@@ -1633,11 +2842,10 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) {
" ::google::protobuf::io::CodedOutputStream* output) const {\n"
" _extensions_.SerializeMessageSetWithCachedSizes(output);\n",
"classname", classname_);
- if (HasUnknownFields(descriptor_->file())) {
- printer->Print(
- " ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n"
- " unknown_fields(), output);\n");
- }
+ GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file()));
+ printer->Print(
+ " ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n"
+ " unknown_fields(), output);\n");
printer->Print(
"}\n");
return;
@@ -1649,8 +2857,16 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) {
"classname", classname_);
printer->Indent();
+ printer->Print(
+ "// @@protoc_insertion_point(serialize_start:$full_name$)\n",
+ "full_name", descriptor_->full_name());
+
GenerateSerializeWithCachedSizesBody(printer, false);
+ printer->Print(
+ "// @@protoc_insertion_point(serialize_end:$full_name$)\n",
+ "full_name", descriptor_->full_name());
+
printer->Outdent();
printer->Print(
"}\n");
@@ -1666,12 +2882,11 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
" target =\n"
" _extensions_.SerializeMessageSetWithCachedSizesToArray(target);\n",
"classname", classname_);
- if (HasUnknownFields(descriptor_->file())) {
- printer->Print(
- " target = ::google::protobuf::internal::WireFormat::\n"
- " SerializeUnknownMessageSetItemsToArray(\n"
- " unknown_fields(), target);\n");
- }
+ GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file()));
+ printer->Print(
+ " target = ::google::protobuf::internal::WireFormat::\n"
+ " SerializeUnknownMessageSetItemsToArray(\n"
+ " unknown_fields(), target);\n");
printer->Print(
" return target;\n"
"}\n");
@@ -1684,8 +2899,16 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
"classname", classname_);
printer->Indent();
+ printer->Print(
+ "// @@protoc_insertion_point(serialize_to_array_start:$full_name$)\n",
+ "full_name", descriptor_->full_name());
+
GenerateSerializeWithCachedSizesBody(printer, true);
+ printer->Print(
+ "// @@protoc_insertion_point(serialize_to_array_end:$full_name$)\n",
+ "full_name", descriptor_->full_name());
+
printer->Outdent();
printer->Print(
" return target;\n"
@@ -1694,15 +2917,15 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
void MessageGenerator::
GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
- scoped_array<const FieldDescriptor*> ordered_fields(
- SortFieldsByNumber(descriptor_));
+ google::protobuf::scoped_array<const FieldDescriptor * > ordered_fields(
+ SortFieldsByNumber(descriptor_));
vector<const Descriptor::ExtensionRange*> sorted_extensions;
for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
sorted_extensions.push_back(descriptor_->extension_range(i));
}
- sort(sorted_extensions.begin(), sorted_extensions.end(),
- ExtensionRangeSorter());
+ std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeSorter());
// Merge the fields and the extension ranges, both sorted by field number.
int i, j;
@@ -1724,24 +2947,69 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
}
}
- if (HasUnknownFields(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");
+static vector<uint32> RequiredFieldsBitMask(const Descriptor* desc) {
+ vector<uint32> result;
+ uint32 mask = 0;
+ for (int i = 0; i < desc->field_count(); i++) {
+ if (i > 0 && i % 32 == 0) {
+ result.push_back(mask);
+ mask = 0;
+ }
+ if (desc->field(i)->is_required()) {
+ mask |= (1 << (i & 31));
+ }
+ }
+ if (mask != 0) {
+ result.push_back(mask);
}
+ return result;
+}
+
+// Create an expression that evaluates to
+// "for all i, (_has_bits_[i] & masks[i]) == masks[i]"
+// masks is allowed to be shorter than _has_bits_, but at least one element of
+// masks must be non-zero.
+static string ConditionalToCheckBitmasks(const vector<uint32>& masks) {
+ vector<string> parts;
+ for (int i = 0; i < masks.size(); i++) {
+ if (masks[i] == 0) continue;
+ char buffer[kFastToBufferSize];
+ FastHex32ToBuffer(masks[i], buffer);
+ string m = StrCat("0x", buffer);
+ // Each xor evaluates to 0 if the expected bits are present.
+ parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")"));
+ }
+ GOOGLE_CHECK(!parts.empty());
+ // If we have multiple parts, each expected to be 0, then bitwise-or them.
+ string result = parts.size() == 1 ? parts[0] :
+ StrCat("(", Join(parts, "\n | "), ")");
+ return result + " == 0";
}
void MessageGenerator::
@@ -1752,11 +3020,12 @@ GenerateByteSize(io::Printer* printer) {
"int $classname$::ByteSize() const {\n"
" int total_size = _extensions_.MessageSetByteSize();\n",
"classname", classname_);
- if (HasUnknownFields(descriptor_->file())) {
- printer->Print(
- " total_size += ::google::protobuf::internal::WireFormat::\n"
- " ComputeUnknownMessageSetItemsSize(unknown_fields());\n");
- }
+ 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"
+ "}\n");
printer->Print(
" GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
" _cached_size_ = total_size;\n"
@@ -1766,6 +3035,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_);
@@ -1774,45 +3070,121 @@ GenerateByteSize(io::Printer* printer) {
"int total_size = 0;\n"
"\n");
- int last_index = -1;
+ // Handle required fields (if any). We expect all of them to be
+ // present, so emit one conditional that checks for that. If they are all
+ // present then the fast path executes; otherwise the slow path executes.
+ if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) {
+ // The fast path works if all required fields are present.
+ vector<uint32> masks_for_has_bits = RequiredFieldsBitMask(descriptor_);
+ printer->Print((string("if (") +
+ ConditionalToCheckBitmasks(masks_for_has_bits) +
+ ") { // All required fields are present.\n").c_str());
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (!field->is_required()) continue;
+ PrintFieldComment(printer, field);
+ field_generators_.get(field).GenerateByteSize(printer);
+ printer->Print("\n");
+ }
+ printer->Outdent();
+ printer->Print("} else {\n" // the slow path
+ " total_size += RequiredFieldsByteSizeFallback();\n"
+ "}\n");
+ } else {
+ // num_required_fields_ <= 1: no need to be tricky
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (!field->is_required()) continue;
+ PrintFieldComment(printer, field);
+ printer->Print("if (has_$name$()) {\n",
+ "name", FieldName(field));
+ printer->Indent();
+ field_generators_.get(field).GenerateByteSize(printer);
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+ // Handle optional fields (worry below about repeateds, oneofs, etc.).
+ // These are handled in chunks of 8. The first chunk is
+ // the non-requireds-non-repeateds-non-unions-non-extensions in
+ // descriptor_->field(0), descriptor_->field(1), ... descriptor_->field(7),
+ // and the second chunk is the same for
+ // descriptor_->field(8), descriptor_->field(9), ... descriptor_->field(15),
+ // etc.
+ hash_map<int, uint32> fields_mask_for_chunk;
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
+ if (!field->is_required() && !field->is_repeated() &&
+ !field->containing_oneof()) {
+ fields_mask_for_chunk[i / 8] |= static_cast<uint32>(1) << (i % 32);
+ }
+ }
- if (!field->is_repeated()) {
+ 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");
}
@@ -1829,21 +3201,57 @@ GenerateByteSize(io::Printer* printer) {
}
}
+ // Fields inside a oneof don't use _has_bits_ so we count them in a separate
+ // pass.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "switch ($oneofname$_case()) {\n",
+ "oneofname", descriptor_->oneof_decl(i)->name());
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ PrintFieldComment(printer, field);
+ printer->Print(
+ "case k$field_name$: {\n",
+ "field_name", UnderscoresToCamelCase(field->name(), true));
+ printer->Indent();
+ field_generators_.get(field).GenerateByteSize(printer);
+ printer->Print(
+ "break;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+ printer->Print(
+ "case $cap_oneof_name$_NOT_SET: {\n"
+ " break;\n"
+ "}\n",
+ "cap_oneof_name",
+ ToUpper(descriptor_->oneof_decl(i)->name()));
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+
if (descriptor_->extension_range_count() > 0) {
printer->Print(
"total_size += _extensions_.ByteSize();\n"
"\n");
}
- if (HasUnknownFields(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");
+ 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,
@@ -1868,27 +3276,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));
+ }
}
}
@@ -1897,19 +3307,30 @@ GenerateIsInitialized(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ !ShouldIgnoreRequiredFieldCheck(field) &&
HasRequiredFields(field->message_type())) {
if (field->is_repeated()) {
printer->Print(
- "for (int i = 0; i < $name$_size(); i++) {\n"
- " if (!this->$name$(i).IsInitialized()) return false;\n"
- "}\n",
+ "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))"
+ " return false;\n",
"name", FieldName(field));
} else {
- printer->Print(
- "if (has_$name$()) {\n"
- " if (!this->$name$().IsInitialized()) return false;\n"
- "}\n",
- "name", FieldName(field));
+ if (field->options().weak() || !field->containing_oneof()) {
+ // 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(
+ "if (has_$name$()) {\n"
+ " if (!this->$name$_->IsInitialized()) return false;\n"
+ "}\n",
+ "name", FieldName(field));
+ } else {
+ printer->Print(
+ "if (has_$name$()) {\n"
+ " if (!this->$name$().IsInitialized()) return false;\n"
+ "}\n",
+ "name", FieldName(field));
+ }
}
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 04778f6d..ea96581d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,9 +35,14 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
-#include <google/protobuf/stubs/common.h>
+#include <vector>
#include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
namespace protobuf {
@@ -56,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 string& dllexport_decl);
+ MessageGenerator(const Descriptor* descriptor, const Options& options);
~MessageGenerator();
// Header stuff.
@@ -78,7 +82,7 @@ class MessageGenerator {
// Generate definitions of inline methods (placed at the end of the header
// file).
- void GenerateInlineMethods(io::Printer* printer);
+ void GenerateInlineMethods(io::Printer* printer, bool is_inline);
// Source file stuff.
@@ -112,7 +116,7 @@ class MessageGenerator {
private:
// Generate declarations and definitions of accessors for fields.
void GenerateFieldAccessorDeclarations(io::Printer* printer);
- void GenerateFieldAccessorDefinitions(io::Printer* printer);
+ void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline);
// Generate the field offsets array.
void GenerateOffsets(io::Printer* printer);
@@ -128,9 +132,12 @@ 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);
+ void GenerateOneofClear(io::Printer* printer);
void GenerateMergeFromCodedStream(io::Printer* printer);
void GenerateSerializeWithCachedSizes(io::Printer* printer);
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer);
@@ -153,11 +160,14 @@ class MessageGenerator {
const Descriptor* descriptor_;
string classname_;
- string dllexport_decl_;
+ Options options_;
FieldGeneratorMap field_generators_;
- scoped_array<scoped_ptr<MessageGenerator> > nested_generators_;
- scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
- scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+ vector< vector<string> > runs_of_fields_; // that might be trivially cleared
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > nested_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
+ int num_required_fields_;
+ 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 23e75b87..467b6bf6 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -45,13 +45,24 @@ namespace cpp {
namespace {
void SetMessageVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
- SetCommonFieldVariables(descriptor, variables);
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = FieldMessageTypeName(descriptor);
+ if (descriptor->options().weak() || !descriptor->containing_oneof()) {
+ (*variables)["non_null_ptr_to_name"] =
+ StrCat("this->", (*variables)["name"], "_");
+ }
(*variables)["stream_writer"] = (*variables)["declared_type"] +
(HasFastArraySerialization(descriptor->message_type()->file()) ?
"MaybeToArray" :
"");
+ // NOTE: Escaped here to unblock proto1->proto2 migration.
+ // TODO(liujisi): Extend this to apply for other conflicting methods.
+ (*variables)["release_name"] =
+ SafeFunctionName(descriptor->containing_type(),
+ descriptor, "release_");
+ (*variables)["full_name"] = descriptor->full_name();
}
} // namespace
@@ -59,9 +70,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
// ===================================================================
MessageFieldGenerator::
-MessageFieldGenerator(const FieldDescriptor* descriptor)
+MessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetMessageVariables(descriptor, &variables_);
+ SetMessageVariables(descriptor, &variables_, options);
}
MessageFieldGenerator::~MessageFieldGenerator() {}
@@ -73,35 +85,221 @@ GeneratePrivateMembers(io::Printer* printer) const {
void MessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "private:\n"
+ "void _slow_mutable_$name$()$deprecation$;\n");
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables_,
+ "void _slow_set_allocated_$name$(\n"
+ " ::google::protobuf::Arena* message_arena, $type$** $name$)$deprecation$;\n");
+ }
+ printer->Print(variables_,
+ "$type$* _slow_$release_name$()$deprecation$;\n"
+ "public:\n");
+ }
printer->Print(variables_,
- "inline const $type$& $name$() const$deprecation$;\n"
- "inline $type$* mutable_$name$()$deprecation$;\n"
- "inline $type$* release_$name$()$deprecation$;\n");
+ "const $type$& $name$() const$deprecation$;\n"
+ "$type$* mutable_$name$()$deprecation$;\n"
+ "$type$* $release_name$()$deprecation$;\n"
+ "void set_allocated_$name$($type$* $name$)$deprecation$;\n");
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "$type$* unsafe_arena_release_$name$()$deprecation$;\n"
+ "void unsafe_arena_set_allocated_$name$(\n"
+ " $type$* $name$)$deprecation$;\n");
+ }
+}
+
+void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
+ io::Printer* printer) const {
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "void $classname$::_slow_mutable_$name$() {\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"
+ "$type$* $classname$::_slow_$release_name$() {\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"
+ "}\n"
+ "$type$* $classname$::unsafe_arena_release_$name$() {\n"
+ " $clear_hasbit$\n"
+ " $type$* temp = $name$_;\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
+ "}\n");
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables_,
+ "void $classname$::_slow_set_allocated_$name$(\n"
+ " ::google::protobuf::Arena* message_arena, $type$** $name$) {\n"
+ " if (message_arena != NULL && \n"
+ " ::google::protobuf::Arena::GetArena(*$name$) == NULL) {\n"
+ " message_arena->Own(*$name$);\n"
+ " } else if (message_arena !=\n"
+ " ::google::protobuf::Arena::GetArena(*$name$)) {\n"
+ " $type$* new_$name$ = \n"
+ " ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+ " message_arena);\n"
+ " new_$name$->CopyFrom(**$name$);\n"
+ " *$name$ = new_$name$;\n"
+ " }\n"
+ "}\n");
+ }
+ printer->Print(variables_,
+ "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");
+ }
}
void MessageFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const $type$& $classname$::$name$() const {\n"
- " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n"
- "}\n"
- "inline $type$* $classname$::mutable_$name$() {\n"
- " set_has_$name$();\n"
- " if ($name$_ == NULL) $name$_ = new $type$;\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");
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ const $type$& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n");
+
+ PrintHandlingOptionalStaticInitializers(
+ variables, descriptor_->file(), printer,
+ // With static initializers.
+ " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
+ // Without.
+ " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
+
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables,
+ "}\n"
+ "$inline$ $type$* $classname$::mutable_$name$() {\n"
+ " $set_hasbit$\n"
+ " if ($name$_ == NULL) {\n"
+ " _slow_mutable_$name$();"
+ " }\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"
+ " return _slow_$release_name$();\n"
+ " } else {\n"
+ " $type$* temp = $name$_;\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
+ " }\n"
+ "}\n"
+ "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ " ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n"
+ " if (message_arena == NULL) {\n"
+ " delete $name$_;\n"
+ " }\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,
+ " _slow_set_allocated_$name$(message_arena, &$name$);\n");
+ } else {
+ printer->Print(variables,
+ " if (message_arena != NULL) {\n"
+ " message_arena->Own($name$);\n"
+ " }\n");
+ }
+ printer->Print(variables,
+ " }\n"
+ " $name$_ = $name$;\n"
+ " if ($name$) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_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::
@@ -137,7 +335,7 @@ void MessageFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
- " $number$, this->$name$(), output);\n");
+ " $number$, *$non_null_ptr_to_name$, output);\n");
}
void MessageFieldGenerator::
@@ -145,7 +343,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoVirtualToArray(\n"
- " $number$, this->$name$(), target);\n");
+ " $number$, *$non_null_ptr_to_name$, target);\n");
}
void MessageFieldGenerator::
@@ -153,15 +351,204 @@ GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
- " this->$name$());\n");
+ " *$non_null_ptr_to_name$);\n");
+}
+
+// ===================================================================
+
+MessageOneofFieldGenerator::
+MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
+ : MessageFieldGenerator(descriptor, options) {
+ SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
+
+void MessageOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ 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 (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::
+GenerateSwappingCode(io::Printer* printer) const {
+ // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void MessageOneofFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+ // Don't print any constructor code. The field is in a union. We allocate
+ // space only when this field is used.
}
// ===================================================================
RepeatedMessageFieldGenerator::
-RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor)
+RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetMessageVariables(descriptor, &variables_);
+ SetMessageVariables(descriptor, &variables_, options);
}
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
@@ -175,35 +562,43 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline const $type$& $name$(int index) const$deprecation$;\n"
- "inline $type$* mutable_$name$(int index)$deprecation$;\n"
- "inline $type$* add_$name$()$deprecation$;\n");
+ "const $type$& $name$(int index) const$deprecation$;\n"
+ "$type$* mutable_$name$(int index)$deprecation$;\n"
+ "$type$* add_$name$()$deprecation$;\n");
printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+ "const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
" $name$() const$deprecation$;\n"
- "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
+ "::google::protobuf::RepeatedPtrField< $type$ >*\n"
" mutable_$name$()$deprecation$;\n");
}
void RepeatedMessageFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const $type$& $classname$::$name$(int index) const {\n"
- " return $name$_.Get(index);\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ const $type$& $classname$::$name$(int index) const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return $name$_.$cppget$(index);\n"
"}\n"
- "inline $type$* $classname$::mutable_$name$(int index) {\n"
+ "$inline$ $type$* $classname$::mutable_$name$(int index) {\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $name$_.Mutable(index);\n"
"}\n"
- "inline $type$* $classname$::add_$name$() {\n"
+ "$inline$ $type$* $classname$::add_$name$() {\n"
+ " // @@protoc_insertion_point(field_add:$full_name$)\n"
" return $name$_.Add();\n"
"}\n");
- printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
"$classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
+ "$inline$ ::google::protobuf::RepeatedPtrField< $type$ >*\n"
"$classname$::mutable_$name$() {\n"
+ " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
"}\n");
}
@@ -220,7 +615,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::
@@ -244,7 +639,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
- "for (int i = 0; i < this->$name$_size(); i++) {\n"
+ "for (unsigned int i = 0, n = this->$name$_size(); i < n; i++) {\n"
" ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
" $number$, this->$name$(i), output);\n"
"}\n");
@@ -253,7 +648,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
- "for (int i = 0; i < this->$name$_size(); i++) {\n"
+ "for (unsigned int i = 0, n = this->$name$_size(); i < n; i++) {\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoVirtualToArray(\n"
" $number$, this->$name$(i), target);\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index f5147278..c1704fc1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,13 +46,16 @@ namespace cpp {
class MessageFieldGenerator : public FieldGenerator {
public:
- explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
+ explicit MessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~MessageFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
+ void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
@@ -62,22 +65,43 @@ class MessageFieldGenerator : public FieldGenerator {
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
- private:
+ protected:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
+ private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
};
+class MessageOneofFieldGenerator : public MessageFieldGenerator {
+ public:
+ explicit MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
+ ~MessageOneofFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
+ void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {}
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
+ void GenerateConstructorCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
+};
+
class RepeatedMessageFieldGenerator : public FieldGenerator {
public:
- explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+ explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~RepeatedMessageFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
new file mode 100644
index 00000000..0c99cff1
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_options.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.
+
+// Author: rennie@google.com (Jeffrey Rennie)
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Generator options:
+struct Options {
+ Options() : safe_boundary_check(false) {
+ }
+ string dllexport_decl;
+ bool safe_boundary_check;
+};
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
index 5c4aa4fb..d1efbfe6 100644
--- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,6 +34,11 @@
// It seemed like parameterizing it would add more complexity than it is
// worth.
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/io/zero_copy_stream.h>
@@ -67,13 +72,107 @@ 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;
}
void TryInsert(const string& filename, const string& insertion_point,
GeneratorContext* context) const {
- scoped_ptr<io::ZeroCopyOutputStream> output(
- context->OpenForInsert(filename, insertion_point));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->OpenForInsert(filename, insertion_point));
io::Printer printer(output.get(), '$');
printer.Print("// inserted $name$\n", "name", insertion_point);
}
@@ -83,13 +182,44 @@ class TestGenerator : public CodeGenerator {
// not verify that they are correctly-placed; that would require actually
// compiling the output which is a bit more than I care to do for this test.
TEST(CppPluginTest, PluginTest) {
- File::WriteStringToFileOrDie(
- "syntax = \"proto2\";\n"
- "package foo;\n"
- "message Bar {\n"
- " message Baz {}\n"
- "}\n",
- TestTempDir() + "/test.proto");
+ 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));
google::protobuf::compiler::CommandLineInterface cli;
cli.SetInputsAreProtoPathRelative(true);
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 5e8df0f4..329eae32 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -80,8 +80,9 @@ int FixedSize(FieldDescriptor::Type type) {
}
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
- SetCommonFieldVariables(descriptor, variables);
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
(*variables)["default"] = DefaultValue(descriptor);
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
@@ -92,6 +93,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["wire_format_field_type"] =
"::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name(
static_cast<FieldDescriptorProto_Type>(descriptor->type()));
+ (*variables)["full_name"] = descriptor->full_name();
}
} // namespace
@@ -99,9 +101,10 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// ===================================================================
PrimitiveFieldGenerator::
-PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
+PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetPrimitiveVariables(descriptor, &variables_);
+ SetPrimitiveVariables(descriptor, &variables_, options);
}
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
@@ -114,19 +117,23 @@ GeneratePrivateMembers(io::Printer* printer) const {
void PrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline $type$ $name$() const$deprecation$;\n"
- "inline void set_$name$($type$ value)$deprecation$;\n");
+ "$type$ $name$() const$deprecation$;\n"
+ "void set_$name$($type$ value)$deprecation$;\n");
}
void PrimitiveFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline void $classname$::set_$name$($type$ value) {\n"
- " set_has_$name$();\n"
+ "$inline$ void $classname$::set_$name$($type$ value) {\n"
+ " $set_hasbit$\n"
" $name$_ = value;\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n");
}
@@ -156,7 +163,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::
@@ -189,10 +196,71 @@ GenerateByteSize(io::Printer* printer) const {
// ===================================================================
+PrimitiveOneofFieldGenerator::
+PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
+ : PrimitiveFieldGenerator(descriptor, options) {
+ SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
+
+void PrimitiveOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ 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"
+ " return $default$;\n"
+ "}\n"
+ "$inline$ void $classname$::set_$name$($type$ value) {\n"
+ " 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");
+}
+
+void PrimitiveOneofFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
+}
+
+void PrimitiveOneofFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void PrimitiveOneofFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ " $classname$_default_oneof_instance_->$name$_ = $default$;\n");
+}
+
+void PrimitiveOneofFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ printer->Print(variables_,
+ "clear_$oneof_name$();\n"
+ "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
+ " $type$, $wire_format_field_type$>(\n"
+ " input, &$oneof_prefix$$name$_)));\n"
+ "set_has_$name$();\n");
+}
+
+// ===================================================================
+
RepeatedPrimitiveFieldGenerator::
-RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
+RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetPrimitiveVariables(descriptor, &variables_);
+ SetPrimitiveVariables(descriptor, &variables_, options);
if (descriptor->options().packed()) {
variables_["packed_reader"] = "ReadPackedPrimitive";
@@ -218,35 +286,42 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "inline $type$ $name$(int index) const$deprecation$;\n"
- "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
- "inline void add_$name$($type$ value)$deprecation$;\n");
+ "$type$ $name$(int index) const$deprecation$;\n"
+ "void set_$name$(int index, $type$ value)$deprecation$;\n"
+ "void add_$name$($type$ value)$deprecation$;\n");
printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
+ "const ::google::protobuf::RepeatedField< $type$ >&\n"
" $name$() const$deprecation$;\n"
- "inline ::google::protobuf::RepeatedField< $type$ >*\n"
+ "::google::protobuf::RepeatedField< $type$ >*\n"
" mutable_$name$()$deprecation$;\n");
}
void RepeatedPrimitiveFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline $type$ $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ $type$ $classname$::$name$(int index) const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
" return $name$_.Get(index);\n"
"}\n"
- "inline void $classname$::set_$name$(int index, $type$ value) {\n"
+ "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n"
" $name$_.Set(index, value);\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
- "inline void $classname$::add_$name$($type$ value) {\n"
+ "$inline$ void $classname$::add_$name$($type$ value) {\n"
" $name$_.Add(value);\n"
+ " // @@protoc_insertion_point(field_add:$full_name$)\n"
"}\n");
- printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::RepeatedField< $type$ >&\n"
"$classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline ::google::protobuf::RepeatedField< $type$ >*\n"
+ "$inline$ ::google::protobuf::RepeatedField< $type$ >*\n"
"$classname$::mutable_$name$() {\n"
+ " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
"}\n");
}
@@ -263,7 +338,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::
@@ -366,7 +441,9 @@ GenerateByteSize(io::Printer* printer) const {
" total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
"}\n"
+ "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
"_$name$_cached_byte_size_ = data_size;\n"
+ "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
"total_size += data_size;\n");
} else {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
index 8fcd74ae..fcd7d684 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,13 +46,15 @@ namespace cpp {
class PrimitiveFieldGenerator : public FieldGenerator {
public:
- explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~PrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
@@ -62,22 +64,43 @@ class PrimitiveFieldGenerator : public FieldGenerator {
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
- private:
+ protected:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
+ private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
};
+class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
+ public:
+ explicit PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
+ ~PrimitiveOneofFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
+ void GenerateConstructorCode(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator);
+};
+
class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
public:
- explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~RepeatedPrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc
index c2825683..226c2aa0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_service.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_service.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -43,14 +43,14 @@ namespace compiler {
namespace cpp {
ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
- const string& dllexport_decl)
+ const Options& options)
: descriptor_(descriptor) {
vars_["classname"] = descriptor_->name();
vars_["full_name"] = descriptor_->full_name();
- if (dllexport_decl.empty()) {
+ if (options.dllexport_decl.empty()) {
vars_["dllexport"] = "";
} else {
- vars_["dllexport"] = dllexport_decl + " ";
+ vars_["dllexport"] = options.dllexport_decl + " ";
}
}
@@ -301,7 +301,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
printer->Print(vars_,
" default:\n"
" GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
- " return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n"
+ " return *static_cast< ::google::protobuf::Message*>(NULL);\n"
" }\n"
"}\n"
"\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.h b/src/google/protobuf/compiler/cpp/cpp_service.h
index 10e9dd3c..ede2fd80 100644
--- a/src/google/protobuf/compiler/cpp/cpp_service.h
+++ b/src/google/protobuf/compiler/cpp/cpp_service.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -37,7 +37,7 @@
#include <map>
#include <string>
-#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
#include <google/protobuf/descriptor.h>
namespace google {
@@ -55,7 +55,7 @@ class ServiceGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit ServiceGenerator(const ServiceDescriptor* descriptor,
- const string& dllexport_decl);
+ const Options& options);
~ServiceGenerator();
// Header stuff.
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 8d611b69..1a1bcd3d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,14 +46,30 @@ namespace cpp {
namespace {
void SetStringVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables) {
- SetCommonFieldVariables(descriptor, variables);
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
(*variables)["default"] = DefaultValue(descriptor);
- (*variables)["default_variable"] = descriptor->default_value_string().empty()
- ? "::google::protobuf::internal::kEmptyString"
- : "_default_" + FieldName(descriptor) + "_";
+ (*variables)["default_length"] =
+ SimpleItoa(descriptor->default_value_string().length());
+ 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.
+ // TODO(liujisi): Extend this to apply for other conflicting methods.
+ (*variables)["release_name"] =
+ SafeFunctionName(descriptor->containing_type(),
+ descriptor, "release_");
+ (*variables)["full_name"] = descriptor->full_name();
+
+ (*variables)["string_piece"] = "::std::string";
}
} // namespace
@@ -61,18 +77,35 @@ void SetStringVariables(const FieldDescriptor* descriptor,
// ===================================================================
StringFieldGenerator::
-StringFieldGenerator(const FieldDescriptor* descriptor)
+StringFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetStringVariables(descriptor, &variables_);
+ SetStringVariables(descriptor, &variables_, options);
}
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::
+GenerateStaticMembers(io::Printer* printer) const {
if (!descriptor_->default_value_string().empty()) {
- printer->Print(variables_, "static const ::std::string $default_variable$;\n");
+ printer->Print(variables_, "static ::std::string* $default_variable$;\n");
}
}
@@ -94,7 +127,11 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
// files that applied the ctype. The field can still be accessed via the
// reflection interface since the reflection interface is independent of
// the string's underlying representation.
- if (descriptor_->options().ctype() != FieldOptions::STRING) {
+
+ bool unknown_ctype =
+ descriptor_->options().ctype() != EffectiveStringCType(descriptor_);
+
+ if (unknown_ctype) {
printer->Outdent();
printer->Print(
" private:\n"
@@ -103,15 +140,23 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
printer->Print(variables_,
- "inline const ::std::string& $name$() const$deprecation$;\n"
- "inline void set_$name$(const ::std::string& value)$deprecation$;\n"
- "inline void set_$name$(const char* value)$deprecation$;\n"
- "inline void set_$name$(const $pointer_type$* value, size_t size)"
+ "const ::std::string& $name$() const$deprecation$;\n"
+ "void set_$name$(const ::std::string& value)$deprecation$;\n"
+ "void set_$name$(const char* value)$deprecation$;\n"
+ "void set_$name$(const $pointer_type$* value, size_t size)"
"$deprecation$;\n"
- "inline ::std::string* mutable_$name$()$deprecation$;\n"
- "inline ::std::string* release_$name$()$deprecation$;\n");
+ "::std::string* mutable_$name$()$deprecation$;\n"
+ "::std::string* $release_name$()$deprecation$;\n"
+ "void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "::std::string* unsafe_arena_release_$name$()$deprecation$;\n"
+ "void unsafe_arena_set_allocated_$name$(\n"
+ " ::std::string* $name$)$deprecation$;\n");
+ }
+
- if (descriptor_->options().ctype() != FieldOptions::STRING) {
+ if (unknown_ctype) {
printer->Outdent();
printer->Print(" public:\n");
printer->Indent();
@@ -119,104 +164,202 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
void StringFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const ::std::string& $classname$::$name$() const {\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"
- "}\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"
- "}\n"
- "inline "
- "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
- " set_has_$name$();\n"
- " if ($name$_ == &$default_variable$) {\n"
- " $name$_ = new ::std::string;\n"
- " }\n"
- " $name$_->assign(reinterpret_cast<const char*>(value), size);\n"
- "}\n"
- "inline ::std::string* $classname$::mutable_$name$() {\n"
- " set_has_$name$();\n"
- " if ($name$_ == &$default_variable$) {\n");
- if (descriptor_->default_value_string().empty()) {
- printer->Print(variables_,
- " $name$_ = new ::std::string;\n");
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return $name$_.Get($default_variable$);\n"
+ "}\n"
+ "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
+ " $set_hasbit$\n"
+ " $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "$inline$ void $classname$::set_$name$(const char* value) {\n"
+ " $set_hasbit$\n"
+ " $name$_.Set($default_variable$, $string_piece$(value),\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+ "}\n"
+ "$inline$ "
+ "void $classname$::set_$name$(const $pointer_type$* value,\n"
+ " size_t size) {\n"
+ " $set_hasbit$\n"
+ " $name$_.Set($default_variable$, $string_piece$(\n"
+ " reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
+ " $set_hasbit$\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::$release_name$() {\n"
+ " $clear_hasbit$\n"
+ " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+ " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+ " $clear_hasbit$\n"
+ " return $name$_.UnsafeArenaRelease($default_variable$,\n"
+ " GetArenaNoVirtual());\n"
+ "}\n"
+ "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ " if ($name$ != NULL) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " $name$_.SetAllocated($default_variable$, $name$,\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n"
+ "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(\n"
+ " ::std::string* $name$) {\n"
+ " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+ " if ($name$ != NULL) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " $set_hasbit$\n"
+ " $name$_.UnsafeArenaSetAllocated($default_variable$,\n"
+ " $name$, GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
} else {
- printer->Print(variables_,
- " $name$_ = new ::std::string($default_variable$);\n");
+ // No-arena case.
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return $name$_.GetNoArena($default_variable$);\n"
+ "}\n"
+ "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
+ " $set_hasbit$\n"
+ " $name$_.SetNoArena($default_variable$, value);\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "$inline$ void $classname$::set_$name$(const char* value) {\n"
+ " $set_hasbit$\n"
+ " $name$_.SetNoArena($default_variable$, $string_piece$(value));\n"
+ " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+ "}\n"
+ "$inline$ "
+ "void $classname$::set_$name$(const $pointer_type$* value, "
+ "size_t size) {\n"
+ " $set_hasbit$\n"
+ " $name$_.SetNoArena($default_variable$,\n"
+ " $string_piece$(reinterpret_cast<const char*>(value), size));\n"
+ " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
+ " $set_hasbit$\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $name$_.MutableNoArena($default_variable$);\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::$release_name$() {\n"
+ " $clear_hasbit$\n"
+ " return $name$_.ReleaseNoArena($default_variable$);\n"
+ "}\n"
+ "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ " if ($name$ != NULL) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " $name$_.SetAllocatedNoArena($default_variable$, $name$);\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
}
- printer->Print(variables_,
- " }\n"
- " 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");
}
void StringFieldGenerator::
GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
if (!descriptor_->default_value_string().empty()) {
+ // Initialized in GenerateDefaultInstanceAllocator.
printer->Print(variables_,
- "const ::std::string $classname$::$default_variable$($default$);\n");
+ "::std::string* $classname$::$default_variable$ = NULL;\n");
}
}
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");
+ }
}
}
void StringFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
- printer->Print(variables_, "set_$name$(from.$name$());\n");
+ if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) {
+ // TODO(gpike): improve this
+ printer->Print(variables_, "set_$name$(from.$name$());\n");
+ } else {
+ printer->Print(variables_,
+ "$set_hasbit$\n"
+ "$name$_.AssignWithDefault($default_variable$, from.$name$_);\n");
+ }
}
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::
+GenerateDefaultInstanceAllocator(io::Printer* printer) const {
+ if (!descriptor_->default_value_string().empty()) {
+ printer->Print(variables_,
+ "$classname$::$default_variable$ =\n"
+ " new ::std::string($default$, $default_length$);\n");
+ }
+}
+
+void StringFieldGenerator::
+GenerateShutdownCode(io::Printer* printer) const {
+ if (!descriptor_->default_value_string().empty()) {
+ printer->Print(variables_,
+ "delete $classname$::$default_variable$;\n");
+ }
}
void StringFieldGenerator::
@@ -224,12 +367,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::VerifyUTF8String(\n"
+ "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$().data(), this->$name$().length(),\n"
- " ::google::protobuf::internal::WireFormat::PARSE);\n");
+ " ::google::protobuf::internal::WireFormat::PARSE,\n"
+ " \"$full_name$\");\n");
}
}
@@ -238,12 +383,13 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
- "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+ "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$().data(), this->$name$().length(),\n"
- " ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+ " ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
+ " \"$full_name$\");\n");
}
printer->Print(variables_,
- "::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
+ "::google::protobuf::internal::WireFormatLite::Write$declared_type$MaybeAliased(\n"
" $number$, this->$name$(), output);\n");
}
@@ -252,9 +398,10 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
- "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+ "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$().data(), this->$name$().length(),\n"
- " ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+ " ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
+ " \"$full_name$\");\n");
}
printer->Print(variables_,
"target =\n"
@@ -272,10 +419,254 @@ GenerateByteSize(io::Printer* printer) const {
// ===================================================================
+StringOneofFieldGenerator::
+StringOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
+ : StringFieldGenerator(descriptor, options) {
+ SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
+
+void StringOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " if (has_$name$()) {\n"
+ " return $oneof_prefix$$name$_.Get($default_variable$);\n"
+ " }\n"
+ " return *$default_variable$;\n"
+ "}\n"
+ "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.Set($default_variable$, value,\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "$inline$ void $classname$::set_$name$(const char* value) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.Set($default_variable$,\n"
+ " $string_piece$(value), GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+ "}\n"
+ "$inline$ "
+ "void $classname$::set_$name$(const $pointer_type$* value,\n"
+ " size_t size) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.Set($default_variable$, $string_piece$(\n"
+ " reinterpret_cast<const char*>(value), size),\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " return $oneof_prefix$$name$_.Mutable($default_variable$,\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::$release_name$() {\n"
+ " if (has_$name$()) {\n"
+ " clear_has_$oneof_name$();\n"
+ " return $oneof_prefix$$name$_.Release($default_variable$,\n"
+ " GetArenaNoVirtual());\n"
+ " } else {\n"
+ " return NULL;\n"
+ " }\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+ " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+ " if (has_$name$()) {\n"
+ " clear_has_$oneof_name$();\n"
+ " return $oneof_prefix$$name$_.UnsafeArenaRelease(\n"
+ " $default_variable$, GetArenaNoVirtual());\n"
+ " } else {\n"
+ " return NULL;\n"
+ " }\n"
+ "}\n"
+ "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ " if (!has_$name$()) {\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " clear_$oneof_name$();\n"
+ " if ($name$ != NULL) {\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.SetAllocated($default_variable$, $name$,\n"
+ " GetArenaNoVirtual());\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n"
+ "$inline$ void $classname$::unsafe_arena_set_allocated_$name$("
+ "::std::string* $name$) {\n"
+ " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+ " if (!has_$name$()) {\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " clear_$oneof_name$();\n"
+ " if ($name$) {\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, "
+ "$name$, GetArenaNoVirtual());\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
+ } else {
+ // No-arena case.
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " if (has_$name$()) {\n"
+ " return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n"
+ " }\n"
+ " return *$default_variable$;\n"
+ "}\n"
+ "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "$inline$ void $classname$::set_$name$(const char* value) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.SetNoArena($default_variable$,\n"
+ " $string_piece$(value));\n"
+ " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+ "}\n"
+ "$inline$ "
+ "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.SetNoArena($default_variable$, $string_piece$(\n"
+ " reinterpret_cast<const char*>(value), size));\n"
+ " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n"
+ "}\n"
+ "$inline$ ::std::string* $classname$::$release_name$() {\n"
+ " if (has_$name$()) {\n"
+ " clear_has_$oneof_name$();\n"
+ " return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n"
+ " } else {\n"
+ " return NULL;\n"
+ " }\n"
+ "}\n"
+ "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ " if (!has_$name$()) {\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " clear_$oneof_name$();\n"
+ " if ($name$ != NULL) {\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.SetAllocatedNoArena($default_variable$,\n"
+ " $name$);\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
+ }
+}
+
+void StringOneofFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "$oneof_prefix$$name$_.Destroy($default_variable$,\n"
+ " GetArenaNoVirtual());\n");
+ } else {
+ printer->Print(variables_,
+ "$oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n");
+ }
+}
+
+void StringOneofFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void StringOneofFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ " $classname$_default_oneof_instance_->$name$_.UnsafeSetDefault("
+ "$default_variable$);\n");
+}
+
+void StringOneofFieldGenerator::
+GenerateDestructorCode(io::Printer* printer) const {
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "if (has_$name$()) {\n"
+ " $oneof_prefix$$name$_.Destroy($default_variable$,\n"
+ " GetArenaNoVirtual());\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "if (has_$name$()) {\n"
+ " $oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n"
+ "}\n");
+ }
+}
+
+void StringOneofFieldGenerator::
+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::
-RepeatedStringFieldGenerator(const FieldDescriptor* descriptor)
+RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
: descriptor_(descriptor) {
- SetStringVariables(descriptor, &variables_);
+ SetStringVariables(descriptor, &variables_, options);
}
RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
@@ -289,7 +680,10 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedStringFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
// See comment above about unknown ctypes.
- if (descriptor_->options().ctype() != FieldOptions::STRING) {
+ bool unknown_ctype =
+ descriptor_->options().ctype() != EffectiveStringCType(descriptor_);
+
+ if (unknown_ctype) {
printer->Outdent();
printer->Print(
" private:\n"
@@ -298,26 +692,26 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
printer->Print(variables_,
- "inline const ::std::string& $name$(int index) const$deprecation$;\n"
- "inline ::std::string* mutable_$name$(int index)$deprecation$;\n"
- "inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
- "inline void set_$name$(int index, const char* value)$deprecation$;\n"
- "inline "
+ "const ::std::string& $name$(int index) const$deprecation$;\n"
+ "::std::string* mutable_$name$(int index)$deprecation$;\n"
+ "void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
+ "void set_$name$(int index, const char* value)$deprecation$;\n"
+ ""
"void set_$name$(int index, const $pointer_type$* value, size_t size)"
"$deprecation$;\n"
- "inline ::std::string* add_$name$()$deprecation$;\n"
- "inline void add_$name$(const ::std::string& value)$deprecation$;\n"
- "inline void add_$name$(const char* value)$deprecation$;\n"
- "inline void add_$name$(const $pointer_type$* value, size_t size)"
+ "::std::string* add_$name$()$deprecation$;\n"
+ "void add_$name$(const ::std::string& value)$deprecation$;\n"
+ "void add_$name$(const char* value)$deprecation$;\n"
+ "void add_$name$(const $pointer_type$* value, size_t size)"
"$deprecation$;\n");
printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
+ "const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
"$deprecation$;\n"
- "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
+ "::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
"$deprecation$;\n");
- if (descriptor_->options().ctype() != FieldOptions::STRING) {
+ if (unknown_ctype) {
printer->Outdent();
printer->Print(" public:\n");
printer->Indent();
@@ -325,46 +719,59 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
void RepeatedStringFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const ::std::string& $classname$::$name$(int index) const {\n"
- " return $name$_.Get(index);\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const {
+ map<string, string> variables(variables_);
+ variables["inline"] = is_inline ? "inline" : "";
+ printer->Print(variables,
+ "$inline$ const ::std::string& $classname$::$name$(int index) const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return $name$_.$cppget$(index);\n"
"}\n"
- "inline ::std::string* $classname$::mutable_$name$(int index) {\n"
+ "$inline$ ::std::string* $classname$::mutable_$name$(int index) {\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $name$_.Mutable(index);\n"
"}\n"
- "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n"
+ "$inline$ void $classname$::set_$name$(int index, const ::std::string& value) {\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
" $name$_.Mutable(index)->assign(value);\n"
"}\n"
- "inline void $classname$::set_$name$(int index, const char* value) {\n"
+ "$inline$ void $classname$::set_$name$(int index, const char* value) {\n"
" $name$_.Mutable(index)->assign(value);\n"
+ " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n"
- "inline void "
+ "$inline$ void "
"$classname$::set_$name$"
"(int index, const $pointer_type$* value, size_t size) {\n"
" $name$_.Mutable(index)->assign(\n"
" reinterpret_cast<const char*>(value), size);\n"
+ " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
"}\n"
- "inline ::std::string* $classname$::add_$name$() {\n"
+ "$inline$ ::std::string* $classname$::add_$name$() {\n"
" return $name$_.Add();\n"
"}\n"
- "inline void $classname$::add_$name$(const ::std::string& value) {\n"
+ "$inline$ void $classname$::add_$name$(const ::std::string& value) {\n"
" $name$_.Add()->assign(value);\n"
+ " // @@protoc_insertion_point(field_add:$full_name$)\n"
"}\n"
- "inline void $classname$::add_$name$(const char* value) {\n"
+ "$inline$ void $classname$::add_$name$(const char* value) {\n"
" $name$_.Add()->assign(value);\n"
+ " // @@protoc_insertion_point(field_add_char:$full_name$)\n"
"}\n"
- "inline void "
+ "$inline$ void "
"$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
" $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
+ " // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
"}\n");
- printer->Print(variables_,
- "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
+ printer->Print(variables,
+ "$inline$ const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
"$classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_list:$full_name$)\n"
" return $name$_;\n"
"}\n"
- "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
+ "$inline$ ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
"$classname$::mutable_$name$() {\n"
+ " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
" return &$name$_;\n"
"}\n");
}
@@ -381,7 +788,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::
@@ -397,9 +804,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
- "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
- " this->$name$(0).data(), this->$name$(0).length(),\n"
- " ::google::protobuf::internal::WireFormat::PARSE);\n");
+ "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
+ " this->$name$(this->$name$_size() - 1).data(),\n"
+ " this->$name$(this->$name$_size() - 1).length(),\n"
+ " ::google::protobuf::internal::WireFormat::PARSE,\n"
+ " \"$full_name$\");\n");
}
}
@@ -410,9 +819,10 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
- "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+ "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$(i).data(), this->$name$(i).length(),\n"
- " ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+ " ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
+ " \"$full_name$\");\n");
}
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
@@ -427,9 +837,10 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
- " ::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+ " ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$(i).data(), this->$name$(i).length(),\n"
- " ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+ " ::google::protobuf::internal::WireFormat::SERIALIZE,\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 7f45107d..d1f19cd9 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,40 +46,67 @@ namespace cpp {
class StringFieldGenerator : public FieldGenerator {
public:
- explicit StringFieldGenerator(const FieldDescriptor* descriptor);
+ explicit StringFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~StringFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateStaticMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
+ void GenerateDefaultInstanceAllocator(io::Printer* printer) const;
+ void GenerateShutdownCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
- private:
+ protected:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
+ private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
};
+class StringOneofFieldGenerator : public StringFieldGenerator {
+ public:
+ explicit StringOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
+ ~StringOneofFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ 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);
+};
+
class RepeatedStringFieldGenerator : public FieldGenerator {
public:
- explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor);
+ explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
~RepeatedStringFieldGenerator();
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const;
void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer,
+ bool is_inline) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
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 54d830fc..9f63155b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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; }
@@ -98,12 +99,54 @@ message TestConflictingSymbolNames {
// Some keywords.
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 {}
optional DO do = 32;
- extensions 1000 to max;
+ // Some template parameter names for extensions.
+ optional int32 field_type = 33;
+ optional bool is_packed = 34;
+
+ // test conflicting release_$name$. "length" and "do" field in this message
+ // must remain string or message fields to make the test valid.
+ optional string release_length = 35;
+ // A more extreme case, the field name "do" here is a keyword, which will be
+ // escaped to "do_" already. Test there is no conflict even with escaped field
+ // names.
+ optional DO release_do = 36;
+
+ // For clashing local variables in Serialize and ByteSize calculation.
+ optional string target = 38;
+
+ 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 TestConflictingEnumNames {
+ enum NestedConflictingEnum {
+ and = 1;
+ class = 2;
+ int = 3;
+ typedef = 4;
+ XOR = 5;
+ }
+
+ optional NestedConflictingEnum conflicting_enum = 1;
+}
+
+enum ConflictingEnum {
+ NOT_EQ = 1;
+ volatile = 2;
+ return = 3;
}
message DummyMessage {}
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 301a7ce6..cc758cf5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -44,6 +44,12 @@
// correctly and produces the interfaces we expect, which is why this test
// is written this way.
+#include <google/protobuf/compiler/cpp/cpp_unittest.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <vector>
#include <google/protobuf/unittest.pb.h>
@@ -51,6 +57,7 @@
#include <google/protobuf/unittest_embed_optimize_for.pb.h>
#include <google/protobuf/unittest_no_generic_services.pb.h>
#include <google/protobuf/test_util.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/io/coded_stream.h>
@@ -64,7 +71,7 @@
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -74,6 +81,8 @@ namespace cpp {
// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
namespace cpp_unittest {
+namespace protobuf_unittest = ::protobuf_unittest;
+
class MockErrorCollector : public MultiFileErrorCollector {
public:
@@ -144,6 +153,21 @@ TEST(GeneratedMessageTest, Defaults) {
&message.optional_import_message());
}
+#ifndef PROTOBUF_USE_DLLS
+TEST(GeneratedMessageTest, Int32StringConversion) {
+ EXPECT_EQ("971", Int32ToString(971));
+ EXPECT_EQ("(~0x7fffffff)", Int32ToString(kint32min));
+ EXPECT_EQ("2147483647", Int32ToString(kint32max));
+}
+
+TEST(GeneratedMessageTest, Int64StringConversion) {
+ EXPECT_EQ("GOOGLE_LONGLONG(971)", Int64ToString(971));
+ EXPECT_EQ("GOOGLE_LONGLONG(-2147483648)", Int64ToString(kint32min));
+ EXPECT_EQ("GOOGLE_LONGLONG(~0x7fffffffffffffff)", Int64ToString(kint64min));
+ EXPECT_EQ("GOOGLE_LONGLONG(9223372036854775807)", Int64ToString(kint64max));
+}
+#endif // !PROTOBUF_USE_DLLS
+
TEST(GeneratedMessageTest, FloatingPointDefaults) {
const unittest::TestExtremeDefaultValues& extreme_default =
unittest::TestExtremeDefaultValues::default_instance();
@@ -174,6 +198,15 @@ TEST(GeneratedMessageTest, Trigraph) {
EXPECT_EQ("? ? ?? ?? ??? ?\?/ ?\?-", extreme_default.cpp_trigraph());
}
+TEST(GeneratedMessageTest, ExtremeSmallIntegerDefault) {
+ const unittest::TestExtremeDefaultValues& extreme_default =
+ unittest::TestExtremeDefaultValues::default_instance();
+ EXPECT_EQ(~0x7fffffff, kint32min);
+ EXPECT_EQ(GOOGLE_LONGLONG(~0x7fffffffffffffff), kint64min);
+ EXPECT_EQ(kint32min, extreme_default.really_small_int32());
+ EXPECT_EQ(kint64min, extreme_default.really_small_int64());
+}
+
TEST(GeneratedMessageTest, Accessors) {
// Set every field to a unique value then go back and check all those
// values.
@@ -202,6 +235,13 @@ TEST(GeneratedMessageTest, MutableStringDefault) {
EXPECT_EQ("hello", *message.mutable_default_string());
}
+TEST(GeneratedMessageTest, StringDefaults) {
+ unittest::TestExtremeDefaultValues message;
+ // Check if '\000' can be used in default string value.
+ EXPECT_EQ(string("hel\000lo", 6), message.string_with_zero());
+ EXPECT_EQ(string("wor\000ld", 6), message.bytes_with_zero());
+}
+
TEST(GeneratedMessageTest, ReleaseString) {
// Check that release_foo() starts out NULL, and gives us a value
// that we can delete after it's been set.
@@ -213,11 +253,10 @@ TEST(GeneratedMessageTest, ReleaseString) {
message.set_default_string("blah");
EXPECT_TRUE(message.has_default_string());
- string* str = message.release_default_string();
+ google::protobuf::scoped_ptr<string> str(message.release_default_string());
EXPECT_FALSE(message.has_default_string());
ASSERT_TRUE(str != NULL);
EXPECT_EQ("blah", *str);
- delete str;
EXPECT_EQ(NULL, message.release_default_string());
EXPECT_FALSE(message.has_default_string());
@@ -233,17 +272,59 @@ TEST(GeneratedMessageTest, ReleaseMessage) {
EXPECT_FALSE(message.has_optional_nested_message());
message.mutable_optional_nested_message()->set_bb(1);
- unittest::TestAllTypes::NestedMessage* nest =
- message.release_optional_nested_message();
+ google::protobuf::scoped_ptr<unittest::TestAllTypes::NestedMessage> nest(
+ message.release_optional_nested_message());
EXPECT_FALSE(message.has_optional_nested_message());
ASSERT_TRUE(nest != NULL);
EXPECT_EQ(1, nest->bb());
- delete nest;
EXPECT_EQ(NULL, message.release_optional_nested_message());
EXPECT_FALSE(message.has_optional_nested_message());
}
+TEST(GeneratedMessageTest, SetAllocatedString) {
+ // Check that set_allocated_foo() works for strings.
+ unittest::TestAllTypes message;
+
+ EXPECT_FALSE(message.has_optional_string());
+ const string kHello("hello");
+ message.set_optional_string(kHello);
+ EXPECT_TRUE(message.has_optional_string());
+
+ message.set_allocated_optional_string(NULL);
+ EXPECT_FALSE(message.has_optional_string());
+ EXPECT_EQ("", message.optional_string());
+
+ message.set_allocated_optional_string(new string(kHello));
+ EXPECT_TRUE(message.has_optional_string());
+ EXPECT_EQ(kHello, message.optional_string());
+}
+
+TEST(GeneratedMessageTest, SetAllocatedMessage) {
+ // Check that set_allocated_foo() can be called in all cases.
+ unittest::TestAllTypes message;
+
+ EXPECT_FALSE(message.has_optional_nested_message());
+
+ message.mutable_optional_nested_message()->set_bb(1);
+ EXPECT_TRUE(message.has_optional_nested_message());
+
+ message.set_allocated_optional_nested_message(NULL);
+ EXPECT_FALSE(message.has_optional_nested_message());
+ EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(),
+ &message.optional_nested_message());
+
+ message.mutable_optional_nested_message()->set_bb(1);
+ unittest::TestAllTypes::NestedMessage* nest =
+ message.release_optional_nested_message();
+ ASSERT_TRUE(nest != NULL);
+ EXPECT_FALSE(message.has_optional_nested_message());
+
+ message.set_allocated_optional_nested_message(nest);
+ EXPECT_TRUE(message.has_optional_nested_message());
+ EXPECT_EQ(1, message.optional_nested_message().bb());
+}
+
TEST(GeneratedMessageTest, Clear) {
// Set every field to a unique value, clear the message, then check that
// it is cleared.
@@ -430,6 +511,8 @@ TEST(GeneratedMessageTest, CopyAssignmentOperator) {
TestUtil::ExpectAllFieldsSet(message2);
}
+#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \
+ !defined(GOOGLE_PROTOBUF_NO_RTTI)
TEST(GeneratedMessageTest, UpcastCopyFrom) {
// Test the CopyFrom method that takes in the generic const Message&
// parameter.
@@ -442,6 +525,7 @@ TEST(GeneratedMessageTest, UpcastCopyFrom) {
TestUtil::ExpectAllFieldsSet(message2);
}
+#endif
#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
@@ -452,7 +536,7 @@ TEST(GeneratedMessageTest, DynamicMessageCopyFrom) {
// Construct a new version of the dynamic message via the factory.
DynamicMessageFactory factory;
- scoped_ptr<Message> message1;
+ google::protobuf::scoped_ptr<Message> message1;
message1.reset(factory.GetPrototype(
unittest::TestAllTypes::descriptor())->New());
@@ -493,16 +577,19 @@ TEST(GeneratedMessageTest, NonEmptyMergeFrom) {
TestUtil::ExpectAllFieldsSet(message1);
}
-#ifdef GTEST_HAS_DEATH_TEST
+#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \
+ !defined(GOOGLE_PROTOBUF_NO_RTTI)
+#ifdef PROTOBUF_HAS_DEATH_TEST
TEST(GeneratedMessageTest, MergeFromSelf) {
unittest::TestAllTypes message;
- EXPECT_DEATH(message.MergeFrom(message), "&from");
+ EXPECT_DEATH(message.MergeFrom(message), "Check failed:.*pb[.]cc");
EXPECT_DEATH(message.MergeFrom(implicit_cast<const Message&>(message)),
- "&from");
+ "Check failed:.*pb[.]cc");
}
-#endif // GTEST_HAS_DEATH_TEST
+#endif // PROTOBUF_HAS_DEATH_TEST
+#endif // !PROTOBUF_TEST_NO_DESCRIPTORS || !GOOGLE_PROTOBUF_NO_RTTI
// Test the generated SerializeWithCachedSizesToArray(),
TEST(GeneratedMessageTest, SerializationToArray) {
@@ -695,6 +782,31 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) {
message.set_friend_(5);
EXPECT_EQ(5, message.friend_());
+
+ message.set_class_(6);
+ EXPECT_EQ(6, message.class_());
+
+ // Instantiate extension template functions to test conflicting template
+ // parameter names.
+ typedef protobuf_unittest::TestConflictingSymbolNamesExtension ExtensionMessage;
+ message.AddExtension(ExtensionMessage::repeated_int32_ext, 123);
+ EXPECT_EQ(123,
+ message.GetExtension(ExtensionMessage::repeated_int32_ext, 0));
+}
+
+TEST(GeneratedMessageTest, TestConflictingEnumNames) {
+ protobuf_unittest::TestConflictingEnumNames message;
+ message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_and_);
+ EXPECT_EQ(1, message.conflicting_enum());
+ message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_XOR);
+ EXPECT_EQ(5, message.conflicting_enum());
+
+
+ protobuf_unittest::ConflictingEnum conflicting_enum;
+ conflicting_enum = protobuf_unittest::NOT_EQ;
+ EXPECT_EQ(1, conflicting_enum);
+ conflicting_enum = protobuf_unittest::return_;
+ EXPECT_EQ(3, conflicting_enum);
}
#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
@@ -766,6 +878,40 @@ TEST(GeneratedMessageTest, TestSpaceUsed) {
message1.SpaceUsed());
}
+TEST(GeneratedMessageTest, TestOneofSpaceUsed) {
+ unittest::TestOneof2 message1;
+ EXPECT_LE(sizeof(unittest::TestOneof2), message1.SpaceUsed());
+
+ const int empty_message_size = message1.SpaceUsed();
+ // Setting primitive types shouldn't affect the space used.
+ message1.set_foo_int(123);
+ message1.set_bar_int(12345);
+ EXPECT_EQ(empty_message_size, message1.SpaceUsed());
+
+ // Setting a string in oneof to a small value should only increase SpaceUsed()
+ // by the size of a string object.
+ message1.set_foo_string("abc");
+ EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsed());
+
+ // Setting a string in oneof to a value larger than the string object itself
+ // should increase SpaceUsed(), because it cannot store the value internally.
+ message1.set_foo_string(string(sizeof(string) + 1, 'x'));
+ int min_expected_increase = message1.foo_string().capacity() +
+ sizeof(string);
+ EXPECT_LE(empty_message_size + min_expected_increase,
+ message1.SpaceUsed());
+
+ // Setting a message in oneof should delete the other fields and increase the
+ // size by the size of the nested message type. NestedMessage is simple enough
+ // that it is equal to sizeof(NestedMessage)
+ message1.mutable_foo_message();
+ ASSERT_EQ(sizeof(unittest::TestOneof2::NestedMessage),
+ message1.foo_message().SpaceUsed());
+ EXPECT_EQ(empty_message_size +
+ sizeof(unittest::TestOneof2::NestedMessage),
+ message1.SpaceUsed());
+}
+
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
@@ -813,6 +959,9 @@ TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) {
case unittest::TestAllTypes::BAZ:
i = 3;
break;
+ case unittest::TestAllTypes::NEG:
+ i = -1;
+ break;
// no default case: We want to make sure the compiler recognizes that
// all cases are covered. (GCC warns if you do not cover all cases of
// an enum in a switch.)
@@ -841,7 +990,7 @@ TEST(GeneratedEnumTest, IsValidValue) {
}
TEST(GeneratedEnumTest, MinAndMax) {
- EXPECT_EQ(unittest::TestAllTypes::FOO,
+ EXPECT_EQ(unittest::TestAllTypes::NEG,
unittest::TestAllTypes::NestedEnum_MIN);
EXPECT_EQ(unittest::TestAllTypes::BAZ,
unittest::TestAllTypes::NestedEnum_MAX);
@@ -869,11 +1018,10 @@ TEST(GeneratedEnumTest, MinAndMax) {
EXPECT_NE(null_pointer, &unittest::ForeignEnum_MAX);
EXPECT_NE(null_pointer, &unittest::ForeignEnum_ARRAYSIZE);
- // Make sure we can use _MIN, _MAX and _ARRAYSIZE as switch cases.
+ // Make sure we can use _MIN and _MAX as switch cases.
switch (unittest::SPARSE_A) {
case unittest::TestSparseEnum_MIN:
case unittest::TestSparseEnum_MAX:
- case unittest::TestSparseEnum_ARRAYSIZE:
break;
default:
break;
@@ -916,6 +1064,20 @@ TEST(GeneratedEnumTest, GetEnumDescriptor) {
GetEnumDescriptor<unittest::TestSparseEnum>());
}
+enum NonProtoEnum {
+ kFoo = 1,
+};
+
+TEST(GeneratedEnumTest, IsProtoEnumTypeTrait) {
+ EXPECT_TRUE(is_proto_enum<unittest::TestAllTypes::NestedEnum>::value);
+ EXPECT_TRUE(is_proto_enum<unittest::ForeignEnum>::value);
+ EXPECT_TRUE(is_proto_enum<unittest::TestEnumWithDupValue>::value);
+ EXPECT_TRUE(is_proto_enum<unittest::TestSparseEnum>::value);
+
+ EXPECT_FALSE(is_proto_enum<int>::value);
+ EXPECT_FALSE(is_proto_enum<NonProtoEnum>::value);
+}
+
#endif // PROTOBUF_TEST_NO_DESCRIPTORS
// ===================================================================
@@ -1076,7 +1238,7 @@ class GeneratedServiceTest : public testing::Test {
unittest::FooResponse foo_response_;
unittest::BarRequest bar_request_;
unittest::BarResponse bar_response_;
- scoped_ptr<Closure> done_;
+ google::protobuf::scoped_ptr<Closure> done_;
};
TEST_F(GeneratedServiceTest, GetDescriptor) {
@@ -1130,7 +1292,7 @@ TEST_F(GeneratedServiceTest, CallMethod) {
TEST_F(GeneratedServiceTest, CallMethodTypeFailure) {
// Verify death if we call Foo() with Bar's message types.
-#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
+#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet
EXPECT_DEBUG_DEATH(
mock_service_.CallMethod(foo_, &mock_controller_,
&foo_request_, &bar_response_, done_.get()),
@@ -1141,7 +1303,7 @@ TEST_F(GeneratedServiceTest, CallMethodTypeFailure) {
mock_service_.CallMethod(foo_, &mock_controller_,
&bar_request_, &foo_response_, done_.get()),
"dynamic_cast");
-#endif // GTEST_HAS_DEATH_TEST
+#endif // PROTOBUF_HAS_DEATH_TEST
}
TEST_F(GeneratedServiceTest, GetPrototypes) {
@@ -1215,6 +1377,657 @@ TEST_F(GeneratedServiceTest, NotImplemented) {
EXPECT_TRUE(controller.called_);
}
+// ===================================================================
+
+class OneofTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+
+ void ExpectEnumCasesWork(const unittest::TestOneof2 &message) {
+ switch (message.foo_case()) {
+ case unittest::TestOneof2::kFooInt:
+ EXPECT_TRUE(message.has_foo_int());
+ break;
+ case unittest::TestOneof2::kFooString:
+ EXPECT_TRUE(message.has_foo_string());
+ break;
+ case unittest::TestOneof2::kFooBytes:
+ EXPECT_TRUE(message.has_foo_bytes());
+ break;
+ case unittest::TestOneof2::kFooEnum:
+ EXPECT_TRUE(message.has_foo_enum());
+ break;
+ case unittest::TestOneof2::kFooMessage:
+ EXPECT_TRUE(message.has_foo_message());
+ break;
+ case unittest::TestOneof2::kFoogroup:
+ EXPECT_TRUE(message.has_foogroup());
+ break;
+ case unittest::TestOneof2::FOO_NOT_SET:
+ break;
+ }
+ }
+};
+
+TEST_F(OneofTest, SettingOneFieldClearsOthers) {
+ unittest::TestOneof2 message;
+
+ message.set_foo_int(123);
+ EXPECT_TRUE(message.has_foo_int());
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+ message.set_foo_string("foo");
+ EXPECT_TRUE(message.has_foo_string());
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+
+ message.set_foo_bytes("qux");
+ EXPECT_TRUE(message.has_foo_bytes());
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+ message.set_foo_enum(unittest::TestOneof2::FOO);
+ EXPECT_TRUE(message.has_foo_enum());
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+ message.mutable_foo_message()->set_qux_int(234);
+ EXPECT_TRUE(message.has_foo_message());
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+ message.mutable_foogroup()->set_a(345);
+ EXPECT_TRUE(message.has_foogroup());
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+
+ // we repeat this because we didn't test if this properly clears other fields
+ // at the beginning.
+ message.set_foo_int(123);
+ EXPECT_TRUE(message.has_foo_int());
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+}
+
+TEST_F(OneofTest, EnumCases) {
+ unittest::TestOneof2 message;
+
+ message.set_foo_int(123);
+ ExpectEnumCasesWork(message);
+ message.set_foo_string("foo");
+ ExpectEnumCasesWork(message);
+ message.set_foo_bytes("qux");
+ ExpectEnumCasesWork(message);
+ message.set_foo_enum(unittest::TestOneof2::FOO);
+ ExpectEnumCasesWork(message);
+ message.mutable_foo_message()->set_qux_int(234);
+ ExpectEnumCasesWork(message);
+ message.mutable_foogroup()->set_a(345);
+ ExpectEnumCasesWork(message);
+}
+
+TEST_F(OneofTest, PrimitiveType) {
+ unittest::TestOneof2 message;
+ // Unset field returns default value
+ EXPECT_EQ(message.foo_int(), 0);
+
+ message.set_foo_int(123);
+ EXPECT_TRUE(message.has_foo_int());
+ EXPECT_EQ(message.foo_int(), 123);
+ message.clear_foo_int();
+ EXPECT_FALSE(message.has_foo_int());
+}
+
+TEST_F(OneofTest, EnumType) {
+ unittest::TestOneof2 message;
+ // Unset field returns default value
+ EXPECT_EQ(message.foo_enum(), 1);
+
+ message.set_foo_enum(unittest::TestOneof2::FOO);
+ EXPECT_TRUE(message.has_foo_enum());
+ EXPECT_EQ(message.foo_enum(), unittest::TestOneof2::FOO);
+ message.clear_foo_enum();
+ EXPECT_FALSE(message.has_foo_enum());
+}
+
+TEST_F(OneofTest, SetString) {
+ // Check that setting a string field in various ways works
+ unittest::TestOneof2 message;
+
+ // Unset field returns default value
+ EXPECT_EQ(message.foo_string(), "");
+
+ message.set_foo_string("foo");
+ EXPECT_TRUE(message.has_foo_string());
+ EXPECT_EQ(message.foo_string(), "foo");
+ message.clear_foo_string();
+ EXPECT_FALSE(message.has_foo_string());
+
+ message.set_foo_string(string("bar"));
+ EXPECT_TRUE(message.has_foo_string());
+ EXPECT_EQ(message.foo_string(), "bar");
+ message.clear_foo_string();
+ EXPECT_FALSE(message.has_foo_string());
+
+
+ message.set_foo_string("qux", 3);
+ EXPECT_TRUE(message.has_foo_string());
+ EXPECT_EQ(message.foo_string(), "qux");
+ message.clear_foo_string();
+ EXPECT_FALSE(message.has_foo_string());
+
+ message.mutable_foo_string()->assign("quux");
+ EXPECT_TRUE(message.has_foo_string());
+ EXPECT_EQ(message.foo_string(), "quux");
+ message.clear_foo_string();
+ EXPECT_FALSE(message.has_foo_string());
+
+ message.set_foo_string("corge");
+ EXPECT_TRUE(message.has_foo_string());
+ EXPECT_EQ(message.foo_string(), "corge");
+ message.clear_foo_string();
+ EXPECT_FALSE(message.has_foo_string());
+}
+
+TEST_F(OneofTest, ReleaseString) {
+ // Check that release_foo() starts out NULL, and gives us a value
+ // that we can delete after it's been set.
+ unittest::TestOneof2 message;
+
+ EXPECT_EQ(NULL, message.release_foo_string());
+ EXPECT_FALSE(message.has_foo_string());
+
+ message.set_foo_string("blah");
+ EXPECT_TRUE(message.has_foo_string());
+ google::protobuf::scoped_ptr<string> str(message.release_foo_string());
+ EXPECT_FALSE(message.has_foo_string());
+ ASSERT_TRUE(str != NULL);
+ EXPECT_EQ("blah", *str);
+
+ EXPECT_EQ(NULL, message.release_foo_string());
+ EXPECT_FALSE(message.has_foo_string());
+}
+
+TEST_F(OneofTest, SetAllocatedString) {
+ // Check that set_allocated_foo() works for strings.
+ unittest::TestOneof2 message;
+
+ EXPECT_FALSE(message.has_foo_string());
+ const string kHello("hello");
+ message.set_foo_string(kHello);
+ EXPECT_TRUE(message.has_foo_string());
+
+ message.set_allocated_foo_string(NULL);
+ EXPECT_FALSE(message.has_foo_string());
+ EXPECT_EQ("", message.foo_string());
+
+ message.set_allocated_foo_string(new string(kHello));
+ EXPECT_TRUE(message.has_foo_string());
+ EXPECT_EQ(kHello, message.foo_string());
+}
+
+
+TEST_F(OneofTest, SetMessage) {
+ // Check that setting a message field works
+ unittest::TestOneof2 message;
+
+ // Unset field returns default instance
+ EXPECT_EQ(&message.foo_message(),
+ &unittest::TestOneof2_NestedMessage::default_instance());
+ EXPECT_EQ(message.foo_message().qux_int(), 0);
+
+ message.mutable_foo_message()->set_qux_int(234);
+ EXPECT_TRUE(message.has_foo_message());
+ EXPECT_EQ(message.foo_message().qux_int(), 234);
+ message.clear_foo_message();
+ EXPECT_FALSE(message.has_foo_message());
+}
+
+TEST_F(OneofTest, ReleaseMessage) {
+ // Check that release_foo() starts out NULL, and gives us a value
+ // that we can delete after it's been set.
+ unittest::TestOneof2 message;
+
+ EXPECT_EQ(NULL, message.release_foo_message());
+ EXPECT_FALSE(message.has_foo_message());
+
+ message.mutable_foo_message()->set_qux_int(1);
+ EXPECT_TRUE(message.has_foo_message());
+ google::protobuf::scoped_ptr<unittest::TestOneof2_NestedMessage> mes(
+ message.release_foo_message());
+ EXPECT_FALSE(message.has_foo_message());
+ ASSERT_TRUE(mes != NULL);
+ EXPECT_EQ(1, mes->qux_int());
+
+ EXPECT_EQ(NULL, message.release_foo_message());
+ EXPECT_FALSE(message.has_foo_message());
+}
+
+TEST_F(OneofTest, SetAllocatedMessage) {
+ // Check that set_allocated_foo() works for messages.
+ unittest::TestOneof2 message;
+
+ EXPECT_FALSE(message.has_foo_message());
+
+ message.mutable_foo_message()->set_qux_int(1);
+ EXPECT_TRUE(message.has_foo_message());
+
+ message.set_allocated_foo_message(NULL);
+ EXPECT_FALSE(message.has_foo_message());
+ EXPECT_EQ(&message.foo_message(),
+ &unittest::TestOneof2_NestedMessage::default_instance());
+
+ message.mutable_foo_message()->set_qux_int(1);
+ unittest::TestOneof2_NestedMessage* mes = message.release_foo_message();
+ ASSERT_TRUE(mes != NULL);
+ EXPECT_FALSE(message.has_foo_message());
+
+ message.set_allocated_foo_message(mes);
+ EXPECT_TRUE(message.has_foo_message());
+ EXPECT_EQ(1, message.foo_message().qux_int());
+}
+
+
+TEST_F(OneofTest, Clear) {
+ unittest::TestOneof2 message;
+
+ message.set_foo_int(1);
+ EXPECT_TRUE(message.has_foo_int());
+ message.clear_foo_int();
+ EXPECT_FALSE(message.has_foo_int());
+}
+
+TEST_F(OneofTest, Defaults) {
+ unittest::TestOneof2 message;
+
+ EXPECT_FALSE(message.has_foo_int());
+ EXPECT_EQ(message.foo_int(), 0);
+
+ EXPECT_FALSE(message.has_foo_string());
+ EXPECT_EQ(message.foo_string(), "");
+
+
+ EXPECT_FALSE(message.has_foo_bytes());
+ EXPECT_EQ(message.foo_bytes(), "");
+
+ EXPECT_FALSE(message.has_foo_enum());
+ EXPECT_EQ(message.foo_enum(), 1);
+
+ EXPECT_FALSE(message.has_foo_message());
+ EXPECT_EQ(message.foo_message().qux_int(), 0);
+
+ EXPECT_FALSE(message.has_foogroup());
+ EXPECT_EQ(message.foogroup().a(), 0);
+
+
+ EXPECT_FALSE(message.has_bar_int());
+ EXPECT_EQ(message.bar_int(), 5);
+
+ EXPECT_FALSE(message.has_bar_string());
+ EXPECT_EQ(message.bar_string(), "STRING");
+
+
+ EXPECT_FALSE(message.has_bar_bytes());
+ EXPECT_EQ(message.bar_bytes(), "BYTES");
+
+ EXPECT_FALSE(message.has_bar_enum());
+ EXPECT_EQ(message.bar_enum(), 2);
+}
+
+TEST_F(OneofTest, SwapWithEmpty) {
+ unittest::TestOneof2 message1, message2;
+ message1.set_foo_string("FOO");
+ EXPECT_TRUE(message1.has_foo_string());
+ message1.Swap(&message2);
+ EXPECT_FALSE(message1.has_foo_string());
+ EXPECT_TRUE(message2.has_foo_string());
+ EXPECT_EQ(message2.foo_string(), "FOO");
+}
+
+TEST_F(OneofTest, SwapWithSelf) {
+ unittest::TestOneof2 message;
+ message.set_foo_string("FOO");
+ EXPECT_TRUE(message.has_foo_string());
+ message.Swap(&message);
+ EXPECT_TRUE(message.has_foo_string());
+ EXPECT_EQ(message.foo_string(), "FOO");
+}
+
+TEST_F(OneofTest, SwapBothHasFields) {
+ unittest::TestOneof2 message1, message2;
+
+ message1.set_foo_string("FOO");
+ EXPECT_TRUE(message1.has_foo_string());
+ message2.mutable_foo_message()->set_qux_int(1);
+ EXPECT_TRUE(message2.has_foo_message());
+
+ message1.Swap(&message2);
+ EXPECT_FALSE(message1.has_foo_string());
+ EXPECT_FALSE(message2.has_foo_message());
+ EXPECT_TRUE(message1.has_foo_message());
+ EXPECT_EQ(message1.foo_message().qux_int(), 1);
+ EXPECT_TRUE(message2.has_foo_string());
+ EXPECT_EQ(message2.foo_string(), "FOO");
+}
+
+TEST_F(OneofTest, CopyConstructor) {
+ unittest::TestOneof2 message1;
+ message1.set_foo_bytes("FOO");
+
+ unittest::TestOneof2 message2(message1);
+ EXPECT_TRUE(message2.has_foo_bytes());
+ EXPECT_EQ(message2.foo_bytes(), "FOO");
+}
+
+TEST_F(OneofTest, CopyFrom) {
+ unittest::TestOneof2 message1, message2;
+ message1.set_foo_enum(unittest::TestOneof2::BAR);
+ EXPECT_TRUE(message1.has_foo_enum());
+
+ message2.CopyFrom(message1);
+ EXPECT_TRUE(message2.has_foo_enum());
+ EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::BAR);
+
+ // Copying from self should be a no-op.
+ message2.CopyFrom(message2);
+ EXPECT_TRUE(message2.has_foo_enum());
+ EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::BAR);
+}
+
+TEST_F(OneofTest, CopyAssignmentOperator) {
+ unittest::TestOneof2 message1;
+ message1.mutable_foo_message()->set_qux_int(123);
+ EXPECT_TRUE(message1.has_foo_message());
+
+ unittest::TestOneof2 message2;
+ message2 = message1;
+ EXPECT_EQ(message2.foo_message().qux_int(), 123);
+
+ // Make sure that self-assignment does something sane.
+ message2 = message2;
+ EXPECT_EQ(message2.foo_message().qux_int(), 123);
+}
+
+TEST_F(OneofTest, UpcastCopyFrom) {
+ // Test the CopyFrom method that takes in the generic const Message&
+ // parameter.
+ unittest::TestOneof2 message1, message2;
+ message1.mutable_foogroup()->set_a(123);
+ EXPECT_TRUE(message1.has_foogroup());
+
+ const Message* source = implicit_cast<const Message*>(&message1);
+ message2.CopyFrom(*source);
+
+ EXPECT_TRUE(message2.has_foogroup());
+ EXPECT_EQ(message2.foogroup().a(), 123);
+}
+
+// Test the generated SerializeWithCachedSizesToArray(),
+// This indirectly tests MergePartialFromCodedStream()
+// We have to test each field type separately because we cannot set them at the
+// same time
+TEST_F(OneofTest, SerializationToArray) {
+ // Primitive type
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.set_foo_int(123);
+ int size = message1.ByteSize();
+ data.resize(size);
+ uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+ uint8* end = message1.SerializeWithCachedSizesToArray(start);
+ EXPECT_EQ(size, end - start);
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_int(), 123);
+ }
+
+ // String
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.set_foo_string("foo");
+ int size = message1.ByteSize();
+ data.resize(size);
+ uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+ uint8* end = message1.SerializeWithCachedSizesToArray(start);
+ EXPECT_EQ(size, end - start);
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_string(), "foo");
+ }
+
+
+ // Bytes
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.set_foo_bytes("qux");
+ int size = message1.ByteSize();
+ data.resize(size);
+ uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+ uint8* end = message1.SerializeWithCachedSizesToArray(start);
+ EXPECT_EQ(size, end - start);
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_bytes(), "qux");
+ }
+
+ // Enum
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.set_foo_enum(unittest::TestOneof2::FOO);
+ int size = message1.ByteSize();
+ data.resize(size);
+ uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+ uint8* end = message1.SerializeWithCachedSizesToArray(start);
+ EXPECT_EQ(size, end - start);
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::FOO);
+ }
+
+ // Message
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.mutable_foo_message()->set_qux_int(234);
+ int size = message1.ByteSize();
+ data.resize(size);
+ uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+ uint8* end = message1.SerializeWithCachedSizesToArray(start);
+ EXPECT_EQ(size, end - start);
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_message().qux_int(), 234);
+ }
+
+ // Group
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.mutable_foogroup()->set_a(345);
+ int size = message1.ByteSize();
+ data.resize(size);
+ uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+ uint8* end = message1.SerializeWithCachedSizesToArray(start);
+ EXPECT_EQ(size, end - start);
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foogroup().a(), 345);
+ }
+
+}
+
+// Test the generated SerializeWithCachedSizes() by forcing the buffer to write
+// one byte at a time.
+// This indirectly tests MergePartialFromCodedStream()
+// We have to test each field type separately because we cannot set them at the
+// same time
+TEST_F(OneofTest, SerializationToStream) {
+ // Primitive type
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.set_foo_int(123);
+ int size = message1.ByteSize();
+ data.resize(size);
+
+ {
+ // Allow the output stream to buffer only one byte at a time.
+ io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+ io::CodedOutputStream output_stream(&array_stream);
+ message1.SerializeWithCachedSizes(&output_stream);
+ EXPECT_FALSE(output_stream.HadError());
+ EXPECT_EQ(size, output_stream.ByteCount());
+ }
+
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_int(), 123);
+ }
+
+ // String
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.set_foo_string("foo");
+ int size = message1.ByteSize();
+ data.resize(size);
+
+ {
+ // Allow the output stream to buffer only one byte at a time.
+ io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+ io::CodedOutputStream output_stream(&array_stream);
+ message1.SerializeWithCachedSizes(&output_stream);
+ EXPECT_FALSE(output_stream.HadError());
+ EXPECT_EQ(size, output_stream.ByteCount());
+ }
+
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_string(), "foo");
+ }
+
+
+ // Bytes
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.set_foo_bytes("qux");
+ int size = message1.ByteSize();
+ data.resize(size);
+
+ {
+ // Allow the output stream to buffer only one byte at a time.
+ io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+ io::CodedOutputStream output_stream(&array_stream);
+ message1.SerializeWithCachedSizes(&output_stream);
+ EXPECT_FALSE(output_stream.HadError());
+ EXPECT_EQ(size, output_stream.ByteCount());
+ }
+
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_bytes(), "qux");
+ }
+
+ // Enum
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.set_foo_enum(unittest::TestOneof2::FOO);
+ int size = message1.ByteSize();
+ data.resize(size);
+
+ {
+ // Allow the output stream to buffer only one byte at a time.
+ io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+ io::CodedOutputStream output_stream(&array_stream);
+ message1.SerializeWithCachedSizes(&output_stream);
+ EXPECT_FALSE(output_stream.HadError());
+ EXPECT_EQ(size, output_stream.ByteCount());
+ }
+
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::FOO);
+ }
+
+ // Message
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.mutable_foo_message()->set_qux_int(234);
+ int size = message1.ByteSize();
+ data.resize(size);
+
+ {
+ // Allow the output stream to buffer only one byte at a time.
+ io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+ io::CodedOutputStream output_stream(&array_stream);
+ message1.SerializeWithCachedSizes(&output_stream);
+ EXPECT_FALSE(output_stream.HadError());
+ EXPECT_EQ(size, output_stream.ByteCount());
+ }
+
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foo_message().qux_int(), 234);
+ }
+
+ // Group
+ {
+ unittest::TestOneof2 message1, message2;
+ string data;
+ message1.mutable_foogroup()->set_a(345);
+ int size = message1.ByteSize();
+ data.resize(size);
+
+ {
+ // Allow the output stream to buffer only one byte at a time.
+ io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+ io::CodedOutputStream output_stream(&array_stream);
+ message1.SerializeWithCachedSizes(&output_stream);
+ EXPECT_FALSE(output_stream.HadError());
+ EXPECT_EQ(size, output_stream.ByteCount());
+ }
+
+ EXPECT_TRUE(message2.ParseFromString(data));
+ EXPECT_EQ(message2.foogroup().a(), 345);
+ }
+
+}
+
+TEST_F(OneofTest, MergeFrom) {
+ unittest::TestOneof2 message1, message2;
+
+ message1.set_foo_int(123);
+ message2.MergeFrom(message1);
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+ EXPECT_TRUE(message2.has_foo_int());
+ EXPECT_EQ(message2.foo_int(), 123);
+
+ message1.set_foo_string("foo");
+ message2.MergeFrom(message1);
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+ EXPECT_TRUE(message2.has_foo_string());
+ EXPECT_EQ(message2.foo_string(), "foo");
+
+
+ message1.set_foo_bytes("qux");
+ message2.MergeFrom(message1);
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+ EXPECT_TRUE(message2.has_foo_bytes());
+ EXPECT_EQ(message2.foo_bytes(), "qux");
+
+ message1.set_foo_enum(unittest::TestOneof2::FOO);
+ message2.MergeFrom(message1);
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+ EXPECT_TRUE(message2.has_foo_enum());
+ EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::FOO);
+
+ message1.mutable_foo_message()->set_qux_int(234);
+ message2.MergeFrom(message1);
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+ EXPECT_TRUE(message2.has_foo_message());
+ EXPECT_EQ(message2.foo_message().qux_int(), 234);
+
+ message1.mutable_foogroup()->set_a(345);
+ message2.MergeFrom(message1);
+ TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+ EXPECT_TRUE(message2.has_foogroup());
+ EXPECT_EQ(message2.foogroup().a(), 345);
+
+}
+
} // namespace cpp_unittest
} // namespace cpp
} // namespace compiler
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.h b/src/google/protobuf/compiler/cpp/cpp_unittest.h
new file mode 100644
index 00000000..69c8f44c
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.h
@@ -0,0 +1,51 @@
+// 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 declares the namespace google::protobuf::protobuf_unittest in order to expose
+// any problems with the generated class names. We use this header to ensure
+// unittest.cc will declare the namespace prior to other includes, while obeying
+// normal include ordering.
+//
+// When generating a class name of "foo.Bar" we must ensure we prefix the class
+// name with "::", in case the namespace google::protobuf::foo exists. We intentionally
+// trigger that case here by declaring google::protobuf::protobuf_unittest.
+//
+// See ClassName in helpers.h for more details.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
+
+namespace google {
+namespace protobuf {
+namespace protobuf_unittest {}
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
new file mode 100644
index 00000000..cb6ca1b1
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
@@ -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.
+
+// Test that proto2 compiler can generate valid code when the enum value
+// is INT_MAX. Note that this is a compile-only test and this proto is not
+// referenced in any C++ code.
+syntax = "proto2";
+
+package protobuf_unittest;
+
+message TestLargeEnumValue {
+ enum EnumWithLargeValue {
+ VALUE_1 = 1;
+ VALUE_MAX = 0x7fffffff;
+ }
+}
diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc
index 422f759f..8333684e 100644
--- a/src/google/protobuf/compiler/importer.cc
+++ b/src/google/protobuf/compiler/importer.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -43,6 +43,10 @@
#include <errno.h>
#include <algorithm>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <google/protobuf/compiler/importer.h>
@@ -121,10 +125,11 @@ SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {}
bool SourceTreeDescriptorDatabase::FindFileByName(
const string& filename, FileDescriptorProto* output) {
- scoped_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
+ google::protobuf::scoped_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
if (input == NULL) {
if (error_collector_ != NULL) {
- error_collector_->AddError(filename, -1, 0, "File not found.");
+ error_collector_->AddError(filename, -1, 0,
+ source_tree_->GetLastErrorMessage());
}
return false;
}
@@ -186,6 +191,7 @@ Importer::Importer(SourceTree* source_tree,
MultiFileErrorCollector* error_collector)
: database_(source_tree),
pool_(&database_, database_.GetValidationErrorCollector()) {
+ pool_.EnforceWeakDependencies(true);
database_.RecordErrorsTo(error_collector);
}
@@ -195,10 +201,22 @@ const FileDescriptor* Importer::Import(const string& filename) {
return pool_.FindFileByName(filename);
}
+void Importer::AddUnusedImportTrackFile(const string& file_name) {
+ pool_.AddUnusedImportTrackFile(file_name);
+}
+
+void Importer::ClearUnusedImportTrackFiles() {
+ pool_.ClearUnusedImportTrackFiles();
+}
+
// ===================================================================
SourceTree::~SourceTree() {}
+string SourceTree::GetLastErrorMessage() {
+ return "File not found.";
+}
+
DiskSourceTree::DiskSourceTree() {}
DiskSourceTree::~DiskSourceTree() {}
@@ -239,9 +257,9 @@ static string CanonicalizePath(string path) {
}
#endif
- vector<string> parts;
vector<string> canonical_parts;
- SplitStringUsing(path, "/", &parts); // Note: Removes empty parts.
+ vector<string> parts = Split(
+ path, "/", true); // Note: Removes empty parts.
for (int i = 0; i < parts.size(); i++) {
if (parts[i] == ".") {
// Ignore.
@@ -249,7 +267,7 @@ static string CanonicalizePath(string path) {
canonical_parts.push_back(parts[i]);
}
}
- string result = JoinStrings(canonical_parts, "/");
+ string result = Join(canonical_parts, "/");
if (!path.empty() && path[0] == '/') {
// Restore leading slash.
result = '/' + result;
@@ -385,7 +403,7 @@ DiskSourceTree::DiskFileToVirtualFile(
// Verify that we can open the file. Note that this also has the side-effect
// of verifying that we are not canonicalizing away any non-existent
// directories.
- scoped_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
+ google::protobuf::scoped_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
if (stream == NULL) {
return CANNOT_OPEN;
}
@@ -395,8 +413,8 @@ DiskSourceTree::DiskFileToVirtualFile(
bool DiskSourceTree::VirtualFileToDiskFile(const string& virtual_file,
string* disk_file) {
- scoped_ptr<io::ZeroCopyInputStream> stream(OpenVirtualFile(virtual_file,
- disk_file));
+ google::protobuf::scoped_ptr<io::ZeroCopyInputStream> stream(
+ OpenVirtualFile(virtual_file, disk_file));
return stream != NULL;
}
@@ -404,6 +422,10 @@ io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) {
return OpenVirtualFile(filename, NULL);
}
+string DiskSourceTree::GetLastErrorMessage() {
+ return last_error_message_;
+}
+
io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
const string& virtual_file,
string* disk_file) {
@@ -412,6 +434,8 @@ io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
// We do not allow importing of paths containing things like ".." or
// consecutive slashes since the compiler expects files to be uniquely
// identified by file name.
+ last_error_message_ = "Backslashes, consecutive slashes, \".\", or \"..\" "
+ "are not allowed in the virtual path";
return NULL;
}
@@ -429,13 +453,13 @@ io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
if (errno == EACCES) {
// The file exists but is not readable.
- // TODO(kenton): Find a way to report this more nicely.
- GOOGLE_LOG(WARNING) << "Read access is denied for file: " << temp_disk_file;
+ last_error_message_ = "Read access is denied for file: " +
+ temp_disk_file;
return NULL;
}
}
}
-
+ last_error_message_ = "File not found.";
return NULL;
}
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index 7a2efc29..f010fd08 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -166,6 +166,9 @@ class LIBPROTOBUF_EXPORT Importer {
return &pool_;
}
+ void AddUnusedImportTrackFile(const string& file_name);
+ void ClearUnusedImportTrackFiles();
+
private:
SourceTreeDescriptorDatabase database_;
DescriptorPool pool_;
@@ -204,6 +207,13 @@ class LIBPROTOBUF_EXPORT SourceTree {
// contain "." or ".." components.
virtual io::ZeroCopyInputStream* Open(const string& filename) = 0;
+ // If Open() returns NULL, calling this method immediately will return an
+ // description of the error.
+ // Subclasses should implement this method and return a meaningful value for
+ // better error reporting.
+ // TODO(xiaofeng): change this to a pure virtual function.
+ virtual string GetLastErrorMessage();
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceTree);
};
@@ -273,17 +283,21 @@ class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree {
bool VirtualFileToDiskFile(const string& virtual_file, string* disk_file);
// implements SourceTree -------------------------------------------
- io::ZeroCopyInputStream* Open(const string& filename);
+ virtual io::ZeroCopyInputStream* Open(const string& filename);
+
+ virtual string GetLastErrorMessage();
private:
struct Mapping {
string virtual_path;
string disk_path;
- inline Mapping(const string& virtual_path, const string& disk_path)
- : virtual_path(virtual_path), disk_path(disk_path) {}
+ inline Mapping(const string& virtual_path_param,
+ const string& disk_path_param)
+ : virtual_path(virtual_path_param), disk_path(disk_path_param) {}
};
vector<Mapping> mappings_;
+ string last_error_message_;
// Like Open(), but returns the on-disk path in disk_file if disk_file is
// non-NULL and the file could be successfully opened.
diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc
index 56fad56e..43eb0ed5 100644
--- a/src/google/protobuf/compiler/importer_unittest.cc
+++ b/src/google/protobuf/compiler/importer_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,12 +33,17 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/stubs/hash.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/testing/file.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/stubs/strutil.h>
@@ -52,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))
@@ -92,6 +101,10 @@ class MockSourceTree : public SourceTree {
}
}
+ string GetLastErrorMessage() {
+ return "File not found.";
+ }
+
private:
hash_map<string, const char*> files_;
};
@@ -210,119 +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());
-}
// ===================================================================
@@ -333,30 +233,32 @@ 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(File::CreateDir(dirnames_[i].c_str(), DEFAULT_FILE_MODE));
+ GOOGLE_CHECK_OK(File::CreateDir(dirnames_[i], 0777));
}
}
virtual void TearDown() {
for (int i = 0; i < dirnames_.size(); i++) {
- File::DeleteRecursively(dirnames_[i], NULL, NULL);
+ if (FileExists(dirnames_[i])) {
+ File::DeleteRecursively(dirnames_[i], NULL, NULL);
+ }
}
}
void AddFile(const string& filename, const char* contents) {
- File::WriteStringToFileOrDie(contents, filename);
+ GOOGLE_CHECK_OK(File::SetContents(filename, contents, true));
}
void AddSubdir(const string& dirname) {
- GOOGLE_CHECK(File::CreateDir(dirname.c_str(), DEFAULT_FILE_MODE));
+ GOOGLE_CHECK_OK(File::CreateDir(dirname, 0777));
}
void ExpectFileContents(const string& filename,
const char* expected_contents) {
- scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
+ google::protobuf::scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
ASSERT_FALSE(input == NULL);
@@ -371,9 +273,11 @@ class DiskSourceTreeTest : public testing::Test {
EXPECT_EQ(expected_contents, file_contents);
}
- void ExpectFileNotFound(const string& filename) {
- scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
+ void ExpectCannotOpenFile(const string& filename,
+ const string& error_message) {
+ google::protobuf::scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
EXPECT_TRUE(input == NULL);
+ EXPECT_EQ(error_message, source_tree_.GetLastErrorMessage());
}
DiskSourceTree source_tree_;
@@ -389,7 +293,7 @@ TEST_F(DiskSourceTreeTest, MapRoot) {
source_tree_.MapPath("", dirnames_[0]);
ExpectFileContents("foo", "Hello World!");
- ExpectFileNotFound("bar");
+ ExpectCannotOpenFile("bar", "File not found.");
}
TEST_F(DiskSourceTreeTest, MapDirectory) {
@@ -400,15 +304,21 @@ TEST_F(DiskSourceTreeTest, MapDirectory) {
source_tree_.MapPath("baz", dirnames_[0]);
ExpectFileContents("baz/foo", "Hello World!");
- ExpectFileNotFound("baz/bar");
- ExpectFileNotFound("foo");
- ExpectFileNotFound("bar");
+ ExpectCannotOpenFile("baz/bar", "File not found.");
+ ExpectCannotOpenFile("foo", "File not found.");
+ ExpectCannotOpenFile("bar", "File not found.");
// Non-canonical file names should not work.
- ExpectFileNotFound("baz//foo");
- ExpectFileNotFound("baz/../baz/foo");
- ExpectFileNotFound("baz/./foo");
- ExpectFileNotFound("baz/foo/");
+ ExpectCannotOpenFile("baz//foo",
+ "Backslashes, consecutive slashes, \".\", or \"..\" are "
+ "not allowed in the virtual path");
+ ExpectCannotOpenFile("baz/../baz/foo",
+ "Backslashes, consecutive slashes, \".\", or \"..\" are "
+ "not allowed in the virtual path");
+ ExpectCannotOpenFile("baz/./foo",
+ "Backslashes, consecutive slashes, \".\", or \"..\" are "
+ "not allowed in the virtual path");
+ ExpectCannotOpenFile("baz/foo/", "File not found.");
}
TEST_F(DiskSourceTreeTest, NoParent) {
@@ -420,8 +330,12 @@ TEST_F(DiskSourceTreeTest, NoParent) {
source_tree_.MapPath("", dirnames_[0] + "/bar");
ExpectFileContents("baz", "Blah.");
- ExpectFileNotFound("../foo");
- ExpectFileNotFound("../bar/baz");
+ ExpectCannotOpenFile("../foo",
+ "Backslashes, consecutive slashes, \".\", or \"..\" are "
+ "not allowed in the virtual path");
+ ExpectCannotOpenFile("../bar/baz",
+ "Backslashes, consecutive slashes, \".\", or \"..\" are "
+ "not allowed in the virtual path");
}
TEST_F(DiskSourceTreeTest, MapFile) {
@@ -431,7 +345,7 @@ TEST_F(DiskSourceTreeTest, MapFile) {
source_tree_.MapPath("foo", dirnames_[0] + "/foo");
ExpectFileContents("foo", "Hello World!");
- ExpectFileNotFound("bar");
+ ExpectCannotOpenFile("bar", "File not found.");
}
TEST_F(DiskSourceTreeTest, SearchMultipleDirectories) {
@@ -445,7 +359,7 @@ TEST_F(DiskSourceTreeTest, SearchMultipleDirectories) {
ExpectFileContents("foo", "Hello World!");
ExpectFileContents("bar", "Goodbye World!");
- ExpectFileNotFound("baz");
+ ExpectCannotOpenFile("baz", "File not found.");
}
TEST_F(DiskSourceTreeTest, OrderingTrumpsSpecificity) {
@@ -453,8 +367,7 @@ TEST_F(DiskSourceTreeTest, OrderingTrumpsSpecificity) {
// directory is more-specific than a former one.
// Create the "bar" directory so we can put a file in it.
- ASSERT_TRUE(File::CreateDir((dirnames_[0] + "/bar").c_str(),
- DEFAULT_FILE_MODE));
+ GOOGLE_CHECK_OK(File::CreateDir(dirnames_[0] + "/bar", 0777));
// Add files and map paths.
AddFile(dirnames_[0] + "/bar/foo", "Hello World!");
diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc
new file mode 100644
index 00000000..7d21fe61
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_context.cc
@@ -0,0 +1,195 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/java/java_context.h>
+
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map_util.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+Context::Context(const FileDescriptor* file)
+ : name_resolver_(new ClassNameResolver) {
+ InitializeFieldGeneratorInfo(file);
+}
+
+Context::~Context() {
+}
+
+ClassNameResolver* Context::GetNameResolver() {
+ return name_resolver_.get();
+}
+
+namespace {
+// Whether two fields have conflicting accessors (assuming name1 and name2
+// are different). name1 and name2 are field1 and field2's camel-case name
+// respectively.
+bool IsConflicting(const FieldDescriptor* field1, const string& name1,
+ const FieldDescriptor* field2, const string& name2,
+ string* info) {
+ if (field1->is_repeated()) {
+ if (field2->is_repeated()) {
+ // Both fields are repeated.
+ return false;
+ } else {
+ // field1 is repeated, and field2 is not.
+ if (name1 + "Count" == name2) {
+ *info = "both repeated field \"" + field1->name() + "\" and singular " +
+ "field \"" + field2->name() + "\" generates the method \"" +
+ "get" + name1 + "Count()\"";
+ return true;
+ }
+ if (name1 + "List" == name2) {
+ *info = "both repeated field \"" + field1->name() + "\" and singular " +
+ "field \"" + field2->name() + "\" generates the method \"" +
+ "get" + name1 + "List()\"";
+ return true;
+ }
+ // Well, there are obviously many more conflicting cases, but it probably
+ // doesn't worth the effort to exhaust all of them because they rarely
+ // happen and as we are continuing adding new methods/changing existing
+ // methods the number of different conflicting cases will keep growing.
+ // We can just add more cases here when they are found in the real world.
+ return false;
+ }
+ } else {
+ if (field2->is_repeated()) {
+ return IsConflicting(field2, name2, field1, name1, info);
+ } else {
+ // None of the two fields are repeated.
+ return false;
+ }
+ }
+}
+} // namespace
+
+void Context::InitializeFieldGeneratorInfo(const FileDescriptor* file) {
+ for (int i = 0; i < file->message_type_count(); ++i) {
+ InitializeFieldGeneratorInfoForMessage(file->message_type(i));
+ }
+}
+
+void Context::InitializeFieldGeneratorInfoForMessage(
+ const Descriptor* message) {
+ for (int i = 0; i < message->nested_type_count(); ++i) {
+ InitializeFieldGeneratorInfoForMessage(message->nested_type(i));
+ }
+ vector<const FieldDescriptor*> fields;
+ for (int i = 0; i < message->field_count(); ++i) {
+ fields.push_back(message->field(i));
+ }
+ InitializeFieldGeneratorInfoForFields(fields);
+
+ for (int i = 0; i < message->oneof_decl_count(); ++i) {
+ const OneofDescriptor* oneof = message->oneof_decl(i);
+ OneofGeneratorInfo info;
+ info.name = UnderscoresToCamelCase(oneof->name(), false);
+ info.capitalized_name = UnderscoresToCamelCase(oneof->name(), true);
+ oneof_generator_info_map_[oneof] = info;
+ }
+}
+
+void Context::InitializeFieldGeneratorInfoForFields(
+ const vector<const FieldDescriptor*>& fields) {
+ // Find out all fields that conflict with some other field in the same
+ // message.
+ vector<bool> is_conflict(fields.size());
+ vector<string> conflict_reason(fields.size());
+ for (int i = 0; i < fields.size(); ++i) {
+ const FieldDescriptor* field = fields[i];
+ const string& name = UnderscoresToCapitalizedCamelCase(field);
+ for (int j = i + 1; j < fields.size(); ++j) {
+ const FieldDescriptor* other = fields[j];
+ const string& other_name = UnderscoresToCapitalizedCamelCase(other);
+ if (name == other_name) {
+ is_conflict[i] = is_conflict[j] = true;
+ conflict_reason[i] = conflict_reason[j] =
+ "capitalized name of field \"" + field->name() +
+ "\" conflicts with field \"" + other->name() + "\"";
+ } else if (IsConflicting(field, name, other, other_name,
+ &conflict_reason[j])) {
+ is_conflict[i] = is_conflict[j] = true;
+ conflict_reason[i] = conflict_reason[j];
+ }
+ }
+ if (is_conflict[i]) {
+ GOOGLE_LOG(WARNING) << "field \"" << field->full_name() << "\" is conflicting "
+ << "with another field: " << conflict_reason[i];
+ }
+ }
+ for (int i = 0; i < fields.size(); ++i) {
+ const FieldDescriptor* field = fields[i];
+ FieldGeneratorInfo info;
+ info.name = UnderscoresToCamelCase(field);
+ info.capitalized_name = UnderscoresToCapitalizedCamelCase(field);
+ // For fields conflicting with some other fields, we append the field
+ // number to their field names in generated code to avoid conflicts.
+ if (is_conflict[i]) {
+ info.name += SimpleItoa(field->number());
+ info.capitalized_name += SimpleItoa(field->number());
+ info.disambiguated_reason = conflict_reason[i];
+ }
+ field_generator_info_map_[field] = info;
+ }
+}
+
+const FieldGeneratorInfo* Context::GetFieldGeneratorInfo(
+ const FieldDescriptor* field) const {
+ const FieldGeneratorInfo* result =
+ FindOrNull(field_generator_info_map_, field);
+ if (result == NULL) {
+ GOOGLE_LOG(FATAL) << "Can not find FieldGeneratorInfo for field: "
+ << field->full_name();
+ }
+ return result;
+}
+
+const OneofGeneratorInfo* Context::GetOneofGeneratorInfo(
+ const OneofDescriptor* oneof) const {
+ const OneofGeneratorInfo* result =
+ FindOrNull(oneof_generator_info_map_, oneof);
+ if (result == NULL) {
+ GOOGLE_LOG(FATAL) << "Can not find OneofGeneratorInfo for oneof: "
+ << oneof->name();
+ }
+ return result;
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h
new file mode 100644
index 00000000..5b595d07
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_context.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__
+
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+ class FileDescriptor;
+ class FieldDescriptor;
+ class OneofDescriptor;
+ class Descriptor;
+ namespace compiler {
+ namespace java {
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+} // namespace protobuf
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+struct FieldGeneratorInfo;
+struct OneofGeneratorInfo;
+// A context object holds the information that is shared among all code
+// generators.
+class Context {
+ public:
+ explicit Context(const FileDescriptor* file);
+ ~Context();
+
+ // Get the name resolver associated with this context. The resolver
+ // can be used to map descriptors to Java class names.
+ ClassNameResolver* GetNameResolver();
+
+ // Get the FieldGeneratorInfo for a given field.
+ const FieldGeneratorInfo* GetFieldGeneratorInfo(
+ const FieldDescriptor* field) const;
+
+ // Get the OneofGeneratorInfo for a given oneof.
+ const OneofGeneratorInfo* GetOneofGeneratorInfo(
+ const OneofDescriptor* oneof) const;
+
+ private:
+ void InitializeFieldGeneratorInfo(const FileDescriptor* file);
+ void InitializeFieldGeneratorInfoForMessage(const Descriptor* message);
+ void InitializeFieldGeneratorInfoForFields(
+ const vector<const FieldDescriptor*>& fields);
+
+ google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
+ map<const FieldDescriptor*, FieldGeneratorInfo> field_generator_info_map_;
+ map<const OneofDescriptor*, OneofGeneratorInfo> oneof_generator_info_map_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__
diff --git a/src/google/protobuf/compiler/java/java_doc_comment.cc b/src/google/protobuf/compiler/java/java_doc_comment.cc
new file mode 100644
index 00000000..663f0c97
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_doc_comment.cc
@@ -0,0 +1,233 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+
+#include <vector>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+string EscapeJavadoc(const string& input) {
+ string result;
+ result.reserve(input.size() * 2);
+
+ char prev = '*';
+
+ for (string::size_type i = 0; i < input.size(); i++) {
+ char c = input[i];
+ switch (c) {
+ case '*':
+ // Avoid "/*".
+ if (prev == '/') {
+ result.append("&#42;");
+ } else {
+ result.push_back(c);
+ }
+ break;
+ case '/':
+ // Avoid "*/".
+ if (prev == '*') {
+ result.append("&#47;");
+ } else {
+ result.push_back(c);
+ }
+ break;
+ case '@':
+ // '@' starts javadoc tags including the @deprecated tag, which will
+ // cause a compile-time error if inserted before a declaration that
+ // does not have a corresponding @Deprecated annotation.
+ result.append("&#64;");
+ break;
+ case '<':
+ // Avoid interpretation as HTML.
+ result.append("&lt;");
+ break;
+ case '>':
+ // Avoid interpretation as HTML.
+ result.append("&gt;");
+ break;
+ case '&':
+ // Avoid interpretation as HTML.
+ result.append("&amp;");
+ break;
+ case '\\':
+ // Java interprets Unicode escape sequences anywhere!
+ result.append("&#92;");
+ break;
+ default:
+ result.push_back(c);
+ break;
+ }
+
+ prev = c;
+ }
+
+ return result;
+}
+
+static void WriteDocCommentBodyForLocation(
+ io::Printer* printer, const SourceLocation& location) {
+ string comments = location.leading_comments.empty() ?
+ location.trailing_comments : location.leading_comments;
+ if (!comments.empty()) {
+ // TODO(kenton): Ideally we should parse the comment text as Markdown and
+ // write it back as HTML, but this requires a Markdown parser. For now
+ // we just use <pre> to get fixed-width text formatting.
+
+ // If the comment itself contains block comment start or end markers,
+ // HTML-escape them so that they don't accidentally close the doc comment.
+ comments = EscapeJavadoc(comments);
+
+ vector<string> lines = Split(comments, "\n");
+ while (!lines.empty() && lines.back().empty()) {
+ lines.pop_back();
+ }
+
+ printer->Print(
+ " *\n"
+ " * <pre>\n");
+ for (int i = 0; i < lines.size(); i++) {
+ // Most lines should start with a space. Watch out for lines that start
+ // with a /, since putting that right after the leading asterisk will
+ // close the comment.
+ if (!lines[i].empty() && lines[i][0] == '/') {
+ printer->Print(" * $line$\n", "line", lines[i]);
+ } else {
+ printer->Print(" *$line$\n", "line", lines[i]);
+ }
+ }
+ printer->Print(" * </pre>\n");
+ }
+}
+
+template <typename DescriptorType>
+static void WriteDocCommentBody(
+ io::Printer* printer, const DescriptorType* descriptor) {
+ SourceLocation location;
+ if (descriptor->GetSourceLocation(&location)) {
+ WriteDocCommentBodyForLocation(printer, location);
+ }
+}
+
+static string FirstLineOf(const string& value) {
+ string result = value;
+
+ string::size_type pos = result.find_first_of('\n');
+ if (pos != string::npos) {
+ result.erase(pos);
+ }
+
+ // If line ends in an opening brace, make it "{ ... }" so it looks nice.
+ if (!result.empty() && result[result.size() - 1] == '{') {
+ result.append(" ... }");
+ }
+
+ return result;
+}
+
+void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
+ printer->Print(
+ "/**\n"
+ " * Protobuf type {@code $fullname$}\n",
+ "fullname", EscapeJavadoc(message->full_name()));
+ WriteDocCommentBody(printer, message);
+ printer->Print(" */\n");
+}
+
+void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) {
+ // In theory we should have slightly different comments for setters, getters,
+ // etc., but in practice everyone already knows the difference between these
+ // so it's redundant information.
+
+ // We use the field declaration as the first line of the comment, e.g.:
+ // optional string foo = 5;
+ // This communicates a lot of information about the field in a small space.
+ // If the field is a group, the debug string might end with {.
+ printer->Print(
+ "/**\n"
+ " * <code>$def$</code>\n",
+ "def", EscapeJavadoc(FirstLineOf(field->DebugString())));
+ WriteDocCommentBody(printer, field);
+ printer->Print(" */\n");
+}
+
+void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) {
+ printer->Print(
+ "/**\n"
+ " * Protobuf enum {@code $fullname$}\n",
+ "fullname", EscapeJavadoc(enum_->full_name()));
+ WriteDocCommentBody(printer, enum_);
+ printer->Print(" */\n");
+}
+
+void WriteEnumValueDocComment(io::Printer* printer,
+ const EnumValueDescriptor* value) {
+ printer->Print(
+ "/**\n"
+ " * <code>$def$</code>\n",
+ "def", EscapeJavadoc(FirstLineOf(value->DebugString())));
+ WriteDocCommentBody(printer, value);
+ printer->Print(" */\n");
+}
+
+void WriteServiceDocComment(io::Printer* printer,
+ const ServiceDescriptor* service) {
+ printer->Print(
+ "/**\n"
+ " * Protobuf service {@code $fullname$}\n",
+ "fullname", EscapeJavadoc(service->full_name()));
+ WriteDocCommentBody(printer, service);
+ printer->Print(" */\n");
+}
+
+void WriteMethodDocComment(io::Printer* printer,
+ const MethodDescriptor* method) {
+ printer->Print(
+ "/**\n"
+ " * <code>$def$</code>\n",
+ "def", EscapeJavadoc(FirstLineOf(method->DebugString())));
+ WriteDocCommentBody(printer, method);
+ printer->Print(" */\n");
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/python/google/protobuf/pyext/python_descriptor.h b/src/google/protobuf/compiler/java/java_doc_comment.h
index 5232680f..7d9535c9 100644
--- a/python/google/protobuf/pyext/python_descriptor.h
+++ b/src/google/protobuf/compiler/java/java_doc_comment.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -28,60 +28,42 @@
// (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: petar@google.com (Petar Petrov)
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
-#ifndef GOOGLE_PROTOBUF_PYTHON_DESCRIPTOR_H__
-#define GOOGLE_PROTOBUF_PYTHON_DESCRIPTOR_H__
-
-#include <Python.h>
-#include <structmember.h>
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
#include <google/protobuf/descriptor.h>
-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
-typedef int Py_ssize_t;
-#define PY_SSIZE_T_MAX INT_MAX
-#define PY_SSIZE_T_MIN INT_MIN
-#endif
-
namespace google {
namespace protobuf {
-namespace python {
-
-typedef struct {
- PyObject_HEAD
-
- // The proto2 descriptor that this object represents.
- const google::protobuf::FieldDescriptor* descriptor;
-
- // Full name of the field (PyString).
- PyObject* full_name;
-
- // Name of the field (PyString).
- PyObject* name;
-
- // C++ type of the field (PyLong).
- PyObject* cpp_type;
+ namespace io {
+ class Printer; // printer.h
+ }
+}
- // Name of the field (PyLong).
- PyObject* label;
-
- // Identity of the descriptor (PyLong used as a poiner).
- PyObject* id;
-} CFieldDescriptor;
-
-extern PyTypeObject CFieldDescriptor_Type;
-
-extern PyTypeObject CDescriptorPool_Type;
-
-
-PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args);
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* args);
-bool InitDescriptor();
-google::protobuf::DescriptorPool* GetDescriptorPool();
-
-} // namespace python
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
+void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field);
+void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_);
+void WriteEnumValueDocComment(io::Printer* printer,
+ const EnumValueDescriptor* value);
+void WriteServiceDocComment(io::Printer* printer,
+ const ServiceDescriptor* service);
+void WriteMethodDocComment(io::Printer* printer,
+ const MethodDescriptor* method);
+
+// Exposed for testing only.
+LIBPROTOC_EXPORT string EscapeJavadoc(const string& input);
+
+} // namespace java
+} // namespace compiler
} // namespace protobuf
} // namespace google
-#endif // GOOGLE_PROTOBUF_PYTHON_DESCRIPTOR_H__
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
diff --git a/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc b/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc
new file mode 100644
index 00000000..ae582ea6
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc
@@ -0,0 +1,67 @@
+// 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)
+
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+namespace {
+
+TEST(JavaDocCommentTest, Escaping) {
+ EXPECT_EQ("foo /&#42; bar *&#47; baz", EscapeJavadoc("foo /* bar */ baz"));
+ EXPECT_EQ("foo /&#42;&#47; baz", EscapeJavadoc("foo /*/ baz"));
+ EXPECT_EQ("{&#64;foo}", EscapeJavadoc("{@foo}"));
+ EXPECT_EQ("&lt;i&gt;&amp;&lt;/i&gt;", EscapeJavadoc("<i>&</i>"));
+ EXPECT_EQ("foo&#92;u1234bar", EscapeJavadoc("foo\\u1234bar"));
+ EXPECT_EQ("&#64;deprecated", EscapeJavadoc("@deprecated"));
+}
+
+// TODO(kenton): It's hard to write a robust test of the doc comments -- we
+// can only really compare the output against a golden value, which is a
+// fairly tedious and fragile testing strategy. If we want to go that route,
+// it probably makes sense to bite the bullet and write a test that compares
+// the whole generated output for unittest.proto against a golden value, with
+// a very simple script that can be run to regenerate it with the latest code.
+// This would mean that updates to the golden file would have to be included
+// in any change to the code generator, which would actually be fairly useful
+// as it allows the reviewer to see clearly how the generated code is
+// changing.
+
+} // namespace
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 9d7bcab6..0353b607 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,8 +35,11 @@
#include <map>
#include <string>
+#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/strutil.h>
@@ -46,8 +49,22 @@ namespace protobuf {
namespace compiler {
namespace java {
-EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
- : descriptor_(descriptor) {
+namespace {
+bool EnumHasCustomOptions(const EnumDescriptor* descriptor) {
+ if (descriptor->options().unknown_fields().field_count() > 0) return true;
+ for (int i = 0; i < descriptor->value_count(); ++i) {
+ const EnumValueDescriptor* value = descriptor->value(i);
+ if (value->options().unknown_fields().field_count() > 0) return true;
+ }
+ return false;
+}
+} // namespace
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
+ bool immutable_api,
+ Context* context)
+ : descriptor_(descriptor), immutable_api_(immutable_api),
+ name_resolver_(context->GetNameResolver()) {
for (int i = 0; i < descriptor_->value_count(); i++) {
const EnumValueDescriptor* value = descriptor_->value(i);
const EnumValueDescriptor* canonical_value =
@@ -67,6 +84,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
EnumGenerator::~EnumGenerator() {}
void EnumGenerator::Generate(io::Printer* printer) {
+ WriteEnumDocComment(printer, descriptor_);
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public enum $classname$\n"
@@ -85,10 +103,18 @@ void EnumGenerator::Generate(io::Printer* printer) {
vars["name"] = canonical_values_[i]->name();
vars["index"] = SimpleItoa(canonical_values_[i]->index());
vars["number"] = SimpleItoa(canonical_values_[i]->number());
+ WriteEnumValueDocComment(printer, canonical_values_[i]);
+ if (canonical_values_[i]->options().deprecated()) {
+ printer->Print("@java.lang.Deprecated\n");
+ }
printer->Print(vars,
"$name$($index$, $number$),\n");
}
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print("UNRECOGNIZED(-1, -1),\n");
+ }
+
printer->Print(
";\n"
"\n");
@@ -100,6 +126,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
vars["classname"] = descriptor_->name();
vars["name"] = aliases_[i].value->name();
vars["canonical_name"] = aliases_[i].canonical_value->name();
+ WriteEnumValueDocComment(printer, aliases_[i].value);
printer->Print(vars,
"public static final $classname$ $name$ = $canonical_name$;\n");
}
@@ -108,6 +135,7 @@ void EnumGenerator::Generate(io::Printer* printer) {
map<string, string> vars;
vars["name"] = descriptor_->value(i)->name();
vars["number"] = SimpleItoa(descriptor_->value(i)->number());
+ WriteEnumValueDocComment(printer, descriptor_->value(i));
printer->Print(vars,
"public static final int $name$_VALUE = $number$;\n");
}
@@ -117,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",
@@ -173,43 +211,105 @@ void EnumGenerator::Generate(io::Printer* printer) {
// at module init time because it wouldn't work with descriptor.proto, but
// we can cache the value the first time getDescriptor() is called.
if (descriptor_->containing_type() == NULL) {
- printer->Print(
- " return $file$.getDescriptor().getEnumTypes().get($index$);\n",
- "file", ClassName(descriptor_->file()),
- "index", SimpleItoa(descriptor_->index()));
+ if (!MultipleJavaFiles(descriptor_->file(), immutable_api_)) {
+ printer->Print(
+ " return $file$.getDescriptor().getEnumTypes().get($index$);\n",
+ "file", name_resolver_->GetClassName(descriptor_->file(),
+ immutable_api_),
+ "index", SimpleItoa(descriptor_->index()));
+ } else {
+ printer->Indent();
+ if (EnumHasCustomOptions(descriptor_)) {
+ // We need to load the immutable classes in order to parse custom
+ // options. However, since file level enums (no outer class) are
+ // shared by immutable code and mutable code, the immutable classes
+ // may not exist. So we try to use Java reflection to retrieve the
+ // descriptor from immutable classes.
+ printer->Print(
+ "try {\n"
+ " java.lang.Class immutableFileClass =\n"
+ " java.lang.Class.forName(\"$immutable_file_class_name$\");\n"
+ " @java.lang.SuppressWarnings(\"unchecked\")\n"
+ " java.lang.reflect.Method m =\n"
+ " immutableFileClass.getMethod(\"getDescriptor\");\n"
+ " com.google.protobuf.Descriptors.FileDescriptor file =\n"
+ " (com.google.protobuf.Descriptors.FileDescriptor)\n"
+ " m.invoke(immutableFileClass);\n"
+ " return file.getEnumTypes().get($index$);\n"
+ "} catch (Exception e) {\n"
+ // Immutable classes cannot be found. Proceed as if custom options
+ // don't exist.
+ "}\n",
+ "immutable_file_class_name",
+ name_resolver_->GetImmutableClassName(descriptor_->file()),
+ "index", SimpleItoa(descriptor_->index()));
+ }
+ printer->Print(
+ "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();
+ }
} else {
printer->Print(
- " return $parent$.getDescriptor().getEnumTypes().get($index$);\n",
- "parent", ClassName(descriptor_->containing_type()),
- "index", SimpleItoa(descriptor_->index()));
+ " return $parent$.$descriptor$.getEnumTypes().get($index$);\n",
+ "parent", name_resolver_->GetClassName(descriptor_->containing_type(),
+ immutable_api_),
+ "descriptor", descriptor_->containing_type()->options()
+ .no_standard_descriptor_accessor()
+ ? "getDefaultInstance().getDescriptorForType()"
+ : "getDescriptor()",
+ "index", SimpleItoa(descriptor_->index()));
}
printer->Print(
"}\n"
"\n"
- "private static final $classname$[] VALUES = {\n"
- " ",
+ "private static final $classname$[] VALUES = ",
"classname", descriptor_->name());
- for (int i = 0; i < descriptor_->value_count(); i++) {
- printer->Print("$name$, ",
- "name", descriptor_->value(i)->name());
+ if (CanUseEnumValues()) {
+ // If the constants we are going to output are exactly the ones we
+ // have declared in the Java enum in the same order, then we can use
+ // the values() method that the Java compiler automatically generates
+ // for every enum.
+ printer->Print("values();\n");
+ } else {
+ printer->Print(
+ "{\n"
+ " ");
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ printer->Print("$name$, ",
+ "name", descriptor_->value(i)->name());
+ }
+ printer->Print(
+ "\n"
+ "};\n");
}
printer->Print(
"\n"
- "};\n"
- "\n"
"public static $classname$ valueOf(\n"
" com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
" 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");
@@ -237,6 +337,18 @@ void EnumGenerator::Generate(io::Printer* printer) {
printer->Print("}\n\n");
}
+bool EnumGenerator::CanUseEnumValues() {
+ if (canonical_values_.size() != descriptor_->value_count()) {
+ return false;
+ }
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ if (descriptor_->value(i)->name() != canonical_values_[i]->name()) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_enum.h b/src/google/protobuf/compiler/java/java_enum.h
index 05ece1f1..a0d91f5a 100644
--- a/src/google/protobuf/compiler/java/java_enum.h
+++ b/src/google/protobuf/compiler/java/java_enum.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -41,6 +41,12 @@
namespace google {
namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
namespace io {
class Printer; // printer.h
}
@@ -52,7 +58,9 @@ namespace java {
class EnumGenerator {
public:
- explicit EnumGenerator(const EnumDescriptor* descriptor);
+ explicit EnumGenerator(const EnumDescriptor* descriptor,
+ bool immutable_api,
+ Context* context);
~EnumGenerator();
void Generate(io::Printer* printer);
@@ -73,6 +81,13 @@ class EnumGenerator {
};
vector<Alias> aliases_;
+ bool immutable_api_;
+
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ bool CanUseEnumValues();
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
};
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 72caa10b..71a2ba4b 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,9 +35,12 @@
#include <map>
#include <string>
-#include <google/protobuf/compiler/java/java_enum_field.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum_field.h>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
@@ -49,20 +52,21 @@ namespace java {
namespace {
-// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
-// repeat code between this and the other field types.
void SetEnumVariables(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
map<string, string>* variables) {
- (*variables)["name"] =
- UnderscoresToCamelCase(descriptor);
- (*variables)["capitalized_name"] =
- UnderscoresToCapitalizedCamelCase(descriptor);
- (*variables)["constant_name"] = FieldConstantName(descriptor);
- (*variables)["number"] = SimpleItoa(descriptor->number());
- (*variables)["type"] = ClassName(descriptor->enum_type());
- (*variables)["default"] = DefaultValue(descriptor);
+ SetCommonFieldVariables(descriptor, info, variables);
+
+ (*variables)["type"] =
+ name_resolver->GetImmutableClassName(descriptor->enum_type());
+ (*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)));
@@ -73,225 +77,569 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
(*variables)["on_changed"] =
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
- // For singular messages and builders, one bit is used for the hasField bit.
- (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ if (SupportFieldPresence(descriptor->file())) {
+ // For singular messages and builders, one bit is used for the hasField bit.
+ (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
- (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
- (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
- (*variables)["clear_has_field_bit_builder"] =
- GenerateClearBit(builderBitIndex);
+ // Note that these have a trailing ";".
+ (*variables)["set_has_field_bit_message"] =
+ GenerateSetBit(messageBitIndex) + ";";
+ (*variables)["set_has_field_bit_builder"] =
+ GenerateSetBit(builderBitIndex) + ";";
+ (*variables)["clear_has_field_bit_builder"] =
+ GenerateClearBit(builderBitIndex) + ";";
+
+ (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+ } else {
+ (*variables)["set_has_field_bit_message"] = "";
+ (*variables)["set_has_field_bit_builder"] = "";
+ (*variables)["clear_has_field_bit_builder"] = "";
+
+ (*variables)["is_field_present_message"] =
+ (*variables)["name"] + "_ != " +
+ (*variables)["default"] + ".getNumber()";
+ }
// For repated builders, one bit is used for whether the array is immutable.
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+ // 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);
+
(*variables)["get_has_field_bit_from_local"] =
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
// ===================================================================
-EnumFieldGenerator::
-EnumFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex,
- int builderBitIndex)
+ImmutableEnumFieldGenerator::
+ImmutableEnumFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
- builderBitIndex_(builderBitIndex) {
- SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_);
+ builderBitIndex_(builderBitIndex),
+ name_resolver_(context->GetNameResolver()) {
+ SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
}
-EnumFieldGenerator::~EnumFieldGenerator() {}
+ImmutableEnumFieldGenerator::~ImmutableEnumFieldGenerator() {}
-int EnumFieldGenerator::GetNumBitsForMessage() const {
+int ImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
return 1;
}
-int EnumFieldGenerator::GetNumBitsForBuilder() const {
+int ImmutableEnumFieldGenerator::GetNumBitsForBuilder() const {
return 1;
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ 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$boolean has$capitalized_name$();\n"
"$deprecation$$type$ get$capitalized_name$();\n");
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $type$ $name$_;\n"
- "$deprecation$public boolean has$capitalized_name$() {\n"
- " return $get_has_field_bit_message$;\n"
- "}\n"
+ "private int $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " 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 EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $type$ $name$_ = $default$;\n"
- "$deprecation$public boolean has$capitalized_name$() {\n"
- " return $get_has_field_bit_builder$;\n"
- "}\n"
+ "private int $name$_ = $default_number$;\n");
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " 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"
- "}\n"
+ " $type$ result = $type$.valueOf($name$_);\n"
+ " return result == null ? $unknown$ : result;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
" if (value == null) {\n"
" throw new NullPointerException();\n"
" }\n"
- " $set_has_field_bit_builder$;\n"
- " $name$_ = value;\n"
+ " $set_has_field_bit_builder$\n"
+ " $name$_ = value.getNumber();\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
- " $clear_has_field_bit_builder$;\n"
- " $name$_ = $default$;\n"
+ " $clear_has_field_bit_builder$\n"
+ " $name$_ = $default_number$;\n"
" $on_changed$\n"
" return this;\n"
"}\n");
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for enums
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateInitializationCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_ = $default$;\n");
+ printer->Print(variables_, "$name$_ = $default_number$;\n");
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateBuilderClearCode(io::Printer* printer) const {
printer->Print(variables_,
- "$name$_ = $default$;\n"
- "$clear_has_field_bit_builder$;\n");
+ "$name$_ = $default_number$;\n"
+ "$clear_has_field_bit_builder$\n");
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
- printer->Print(variables_,
- "if (other.has$capitalized_name$()) {\n"
- " set$capitalized_name$(other.get$capitalized_name$());\n"
- "}\n");
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " set$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+ } else if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(variables_,
+ "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.";
+ }
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "if ($get_has_field_bit_from_local$) {\n"
+ " $set_has_field_bit_to_local$;\n"
+ "}\n");
+ }
printer->Print(variables_,
- "if ($get_has_field_bit_from_local$) {\n"
- " $set_has_field_bit_to_local$;\n"
- "}\n"
"result.$name$_ = $name$_;\n");
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
- printer->Print(variables_,
- "int rawValue = input.readEnum();\n"
- "$type$ value = $type$.valueOf(rawValue);\n");
- if (HasUnknownFields(descriptor_->containing_type())) {
+ if (SupportUnknownEnumValue(descriptor_->file())) {
printer->Print(variables_,
- "if (value == null) {\n"
- " unknownFields.mergeVarintField($number$, rawValue);\n"
- "} else {\n");
+ "int rawValue = input.readEnum();\n"
+ "$set_has_field_bit_message$\n"
+ "$name$_ = rawValue;\n");
} else {
printer->Print(variables_,
- "if (value != null) {\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_,
- " $set_has_field_bit_builder$;\n"
- " $name$_ = value;\n"
- "}\n");
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for enums
+}
+
+void ImmutableEnumFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
- " output.writeEnum($number$, $name$_.getNumber());\n"
+ "if ($is_field_present_message$) {\n"
+ " output.writeEnum($number$, $name$_);\n"
"}\n");
}
-void EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
+ "if ($is_field_present_message$) {\n"
" size += com.google.protobuf.CodedOutputStream\n"
- " .computeEnumSize($number$, $name$_.getNumber());\n"
+ " .computeEnumSize($number$, $name$_);\n"
"}\n");
}
-void EnumFieldGenerator::
+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 EnumFieldGenerator::
+void ImmutableEnumFieldGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(variables_,
"hash = (37 * hash) + $constant_name$;\n"
- "hash = (53 * hash) + hashEnum(get$capitalized_name$());\n");
+ "hash = (53 * hash) + $name$_;\n");
}
-string EnumFieldGenerator::GetBoxedType() const {
- return ClassName(descriptor_->enum_type());
+string ImmutableEnumFieldGenerator::GetBoxedType() const {
+ return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
}
// ===================================================================
-RepeatedEnumFieldGenerator::
-RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex,
- int builderBitIndex)
+ImmutableEnumOneofFieldGenerator::
+ImmutableEnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableEnumFieldGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableEnumOneofFieldGenerator::
+~ImmutableEnumOneofFieldGenerator() {}
+
+void ImmutableEnumOneofFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " 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"
+ " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+ " return result == null ? $unknown$ : result;\n"
+ " }\n"
+ " return $default$;\n"
+ "}\n");
+}
+
+void ImmutableEnumOneofFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " 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"
+ " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+ " return result == null ? $unknown$ : result;\n"
+ " }\n"
+ " return $default$;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = value.getNumber();\n"
+ " $on_changed$\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " $on_changed$\n"
+ " }\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutableEnumOneofFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " result.$oneof_name$_ = $oneof_name$_;\n"
+ "}\n");
+}
+
+void ImmutableEnumOneofFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ 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 {
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(variables_,
+ "int rawValue = input.readEnum();\n"
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = rawValue;\n");
+ } else {
+ printer->Print(variables_,
+ "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");
+ }
+}
+
+void ImmutableEnumOneofFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n"
+ "}\n");
+}
+
+void ImmutableEnumOneofFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\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::
+RepeatedImmutableEnumFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
- builderBitIndex_(builderBitIndex) {
- SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_);
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
}
-RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+RepeatedImmutableEnumFieldGenerator::~RepeatedImmutableEnumFieldGenerator() {}
-int RepeatedEnumFieldGenerator::GetNumBitsForMessage() const {
+int RepeatedImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
return 0;
}
-int RepeatedEnumFieldGenerator::GetNumBitsForBuilder() const {
+int RepeatedImmutableEnumFieldGenerator::GetNumBitsForBuilder() const {
return 1;
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$int get$capitalized_name$Count();\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n"
- "$deprecation$int get$capitalized_name$Count();\n"
"$deprecation$$type$ get$capitalized_name$(int index);\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$java.util.List<java.lang.Integer>\n"
+ "get$capitalized_name$ValueList();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$int get$capitalized_name$Value(int index);\n");
+ }
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private java.util.List<$type$> $name$_;\n"
+ "private java.util.List<java.lang.Integer> $name$_;\n"
+ "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n"
+ " java.lang.Integer, $type$> $name$_converter_ =\n"
+ " new com.google.protobuf.Internal.ListAdapter.Converter<\n"
+ " java.lang.Integer, $type$>() {\n"
+ " public $type$ convert(java.lang.Integer from) {\n"
+ " $type$ result = $type$.valueOf(from);\n"
+ " return result == null ? $unknown$ : result;\n"
+ " }\n"
+ " };\n");
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
- " return $name$_;\n" // note: unmodifiable list
- "}\n"
+ " return new com.google.protobuf.Internal.ListAdapter<\n"
+ " java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
- " return $name$_.get(index);\n"
+ " return $name$_converter_.convert($name$_.get(index));\n"
"}\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<java.lang.Integer>\n"
+ "get$capitalized_name$ValueList() {\n"
+ " return $name$_;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+ " return $name$_.get(index);\n"
+ "}\n");
+ }
if (descriptor_->options().packed() &&
HasGeneratedMethods(descriptor_->containing_type())) {
@@ -300,7 +648,7 @@ GenerateMembers(io::Printer* printer) const {
}
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
// One field is the list and the other field keeps track of whether the
@@ -312,81 +660,140 @@ GenerateBuilderMembers(io::Printer* printer) const {
// memory allocations. Note, immutable is a strong guarantee here -- not
// just that the list cannot be modified via the reference but that the
// list can never be modified.
- "private java.util.List<$type$> $name$_ =\n"
+ "private java.util.List<java.lang.Integer> $name$_ =\n"
" java.util.Collections.emptyList();\n"
"private void ensure$capitalized_name$IsMutable() {\n"
" if (!$get_mutable_bit_builder$) {\n"
- " $name$_ = new java.util.ArrayList<$type$>($name$_);\n"
+ " $name$_ = new java.util.ArrayList<java.lang.Integer>($name$_);\n"
" $set_mutable_bit_builder$;\n"
" }\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
// Note: We return an unmodifiable list because otherwise the caller
// could hold on to the returned list and modify it after the message
// 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"
- "}\n"
+ " return new com.google.protobuf.Internal.ListAdapter<\n"
+ " java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
- " return $name$_.get(index);\n"
- "}\n"
+ " return $name$_converter_.convert($name$_.get(index));\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$(\n"
" int index, $type$ value) {\n"
" if (value == null) {\n"
" 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"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
" if (value == null) {\n"
" 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"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder addAll$capitalized_name$(\n"
" java.lang.Iterable<? extends $type$> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
- " super.addAll(values, $name$_);\n"
+ " for ($type$ value : values) {\n"
+ " $name$_.add(value.getNumber());\n"
+ " }\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
" $name$_ = java.util.Collections.emptyList();\n"
" $clear_mutable_bit_builder$;\n"
" $on_changed$\n"
" return this;\n"
"}\n");
+
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<java.lang.Integer>\n"
+ "get$capitalized_name$ValueList() {\n"
+ " return java.util.Collections.unmodifiableList($name$_);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+ " return $name$_.get(index);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$Value(\n"
+ " int index, int value) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.set(index, value);\n"
+ " $on_changed$\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$Value(int value) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " $name$_.add(value);\n"
+ " $on_changed$\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder addAll$capitalized_name$Value(\n"
+ " java.lang.Iterable<java.lang.Integer> values) {\n"
+ " ensure$capitalized_name$IsMutable();\n"
+ " for (int value : values) {\n"
+ " $name$_.add(value);\n"
+ " }\n"
+ " $on_changed$\n"
+ " return this;\n"
+ "}\n");
+ }
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for enums
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateInitializationCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateBuilderClearCode(io::Printer* printer) const {
printer->Print(variables_,
"$name$_ = java.util.Collections.emptyList();\n"
"$clear_mutable_bit_builder$;\n");
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
// The code below does two optimizations:
// 1. If the other list is empty, there's nothing to do. This ensures we
@@ -406,7 +813,7 @@ GenerateMergingCode(io::Printer* printer) const {
"}\n");
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
// The code below ensures that the result has an immutable list. If our
// list is immutable, we can just reuse it. If not, we make it immutable.
@@ -418,27 +825,38 @@ GenerateBuildingCode(io::Printer* printer) const {
"result.$name$_ = $name$_;\n");
}
-void RepeatedEnumFieldGenerator::
+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 (HasUnknownFields(descriptor_->containing_type())) {
+ if (SupportUnknownEnumValue(descriptor_->file())) {
printer->Print(variables_,
- "if (value == null) {\n"
- " unknownFields.mergeVarintField($number$, rawValue);\n"
- "} else {\n");
+ "int rawValue = input.readEnum();\n"
+ "if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n"
+ "$name$_.add(rawValue);\n");
} else {
printer->Print(variables_,
- "if (value != null) {\n");
+ "int rawValue = input.readEnum();\n"
+ "$type$ value = $type$.valueOf(rawValue);\n"
+ "if (value == null) {\n");
+ if (PreserveUnknownFields(descriptor_->containing_type())) {
+ printer->Print(variables_,
+ " unknownFields.mergeVarintField($number$, rawValue);\n");
+ }
+ printer->Print(variables_,
+ "} else {\n"
+ " if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n"
+ " $set_mutable_bit_parser$;\n"
+ " }\n"
+ " $name$_.add(rawValue);\n"
+ "}\n");
}
- printer->Print(variables_,
- " add$capitalized_name$(value);\n"
- "}\n");
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateParsingCodeFromPacked(io::Printer* printer) const {
// Wrap GenerateParsingCode's contents with a while loop.
@@ -456,7 +874,15 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const {
"input.popLimit(oldLimit);\n");
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_mutable_bit_parser$) {\n"
+ " $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+ "}\n");
+}
+
+void RepeatedImmutableEnumFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
if (descriptor_->options().packed()) {
printer->Print(variables_,
@@ -465,17 +891,17 @@ 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");
}
}
-void RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
"{\n"
@@ -485,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");
@@ -511,24 +937,23 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print("}\n");
}
-void RepeatedEnumFieldGenerator::
+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 RepeatedEnumFieldGenerator::
+void RepeatedImmutableEnumFieldGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(variables_,
"if (get$capitalized_name$Count() > 0) {\n"
" hash = (37 * hash) + $constant_name$;\n"
- " hash = (53 * hash) + hashEnumList(get$capitalized_name$List());\n"
+ " hash = (53 * hash) + $name$_.hashCode();\n"
"}\n");
}
-string RepeatedEnumFieldGenerator::GetBoxedType() const {
- return ClassName(descriptor_->enum_type());
+string RepeatedImmutableEnumFieldGenerator::GetBoxedType() const {
+ return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
}
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h
index 0cad6be0..b8ff7343 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.h
+++ b/src/google/protobuf/compiler/java/java_enum_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -41,16 +41,26 @@
namespace google {
namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+}
+
+namespace protobuf {
namespace compiler {
namespace java {
-class EnumFieldGenerator : public FieldGenerator {
+class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
public:
- explicit EnumFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex, int builderBitIndex);
- ~EnumFieldGenerator();
+ explicit ImmutableEnumFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableEnumFieldGenerator();
- // implements FieldGenerator ---------------------------------------
+ // implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const;
int GetNumBitsForBuilder() const;
void GenerateInterfaceMembers(io::Printer* printer) const;
@@ -61,6 +71,7 @@ class EnumFieldGenerator : public FieldGenerator {
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;
@@ -69,22 +80,47 @@ class EnumFieldGenerator : public FieldGenerator {
string GetBoxedType() const;
- private:
+ protected:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
const int messageBitIndex_;
const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldGenerator);
+};
+
+class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator {
+ public:
+ ImmutableEnumOneofFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableEnumOneofFieldGenerator();
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ 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);
};
-class RepeatedEnumFieldGenerator : public FieldGenerator {
+class RepeatedImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
public:
- explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex, int builderBitIndex);
- ~RepeatedEnumFieldGenerator();
+ explicit RepeatedImmutableEnumFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~RepeatedImmutableEnumFieldGenerator();
- // implements FieldGenerator ---------------------------------------
+ // implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const;
int GetNumBitsForBuilder() const;
void GenerateInterfaceMembers(io::Printer* printer) const;
@@ -96,6 +132,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
void GenerateBuildingCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
void GenerateParsingCodeFromPacked(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;
@@ -109,8 +146,10 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
map<string, string> variables_;
const int messageBitIndex_;
const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableEnumFieldGenerator);
};
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc
index 9b147c77..27cf416b 100644
--- a/src/google/protobuf/compiler/java/java_extension.cc
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,73 +33,50 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/java/java_extension.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
-#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace java {
-namespace {
-
-const char* TypeName(FieldDescriptor::Type field_type) {
- switch (field_type) {
- case FieldDescriptor::TYPE_INT32 : return "INT32";
- case FieldDescriptor::TYPE_UINT32 : return "UINT32";
- case FieldDescriptor::TYPE_SINT32 : return "SINT32";
- case FieldDescriptor::TYPE_FIXED32 : return "FIXED32";
- case FieldDescriptor::TYPE_SFIXED32: return "SFIXED32";
- case FieldDescriptor::TYPE_INT64 : return "INT64";
- case FieldDescriptor::TYPE_UINT64 : return "UINT64";
- case FieldDescriptor::TYPE_SINT64 : return "SINT64";
- case FieldDescriptor::TYPE_FIXED64 : return "FIXED64";
- case FieldDescriptor::TYPE_SFIXED64: return "SFIXED64";
- case FieldDescriptor::TYPE_FLOAT : return "FLOAT";
- case FieldDescriptor::TYPE_DOUBLE : return "DOUBLE";
- case FieldDescriptor::TYPE_BOOL : return "BOOL";
- case FieldDescriptor::TYPE_STRING : return "STRING";
- case FieldDescriptor::TYPE_BYTES : return "BYTES";
- case FieldDescriptor::TYPE_ENUM : return "ENUM";
- case FieldDescriptor::TYPE_GROUP : return "GROUP";
- case FieldDescriptor::TYPE_MESSAGE : return "MESSAGE";
-
- // No default because we want the compiler to complain if any new
- // types are added.
- }
-
- GOOGLE_LOG(FATAL) << "Can't get here.";
- return NULL;
-}
-
-}
-
-ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor)
- : descriptor_(descriptor) {
+ImmutableExtensionGenerator::ImmutableExtensionGenerator(
+ const FieldDescriptor* descriptor, Context* context)
+ : descriptor_(descriptor), context_(context),
+ name_resolver_(context->GetNameResolver()) {
if (descriptor_->extension_scope() != NULL) {
- scope_ = ClassName(descriptor_->extension_scope());
+ scope_ = name_resolver_->GetImmutableClassName(
+ descriptor_->extension_scope());
} else {
- scope_ = ClassName(descriptor_->file());
+ scope_ = name_resolver_->GetImmutableClassName(descriptor_->file());
}
}
-ExtensionGenerator::~ExtensionGenerator() {}
+ImmutableExtensionGenerator::~ImmutableExtensionGenerator() {}
// Initializes the vars referenced in the generated code templates.
-void InitTemplateVars(const FieldDescriptor* descriptor,
- const string& scope,
- map<string, string>* vars_pointer) {
+void ExtensionGenerator::InitTemplateVars(const FieldDescriptor* descriptor,
+ const string& scope,
+ bool immutable,
+ ClassNameResolver* name_resolver,
+ map<string, string>* vars_pointer) {
map<string, string> &vars = *vars_pointer;
vars["scope"] = scope;
vars["name"] = UnderscoresToCamelCase(descriptor);
- vars["containing_type"] = ClassName(descriptor->containing_type());
+ vars["containing_type"] =
+ name_resolver->GetClassName(descriptor->containing_type(), immutable);
vars["number"] = SimpleItoa(descriptor->number());
vars["constant_name"] = FieldConstantName(descriptor);
vars["index"] = SimpleItoa(descriptor->index());
- vars["default"] =
- descriptor->is_repeated() ? "" : DefaultValue(descriptor);
- vars["type_constant"] = TypeName(GetType(descriptor));
+ vars["default"] = descriptor->is_repeated() ?
+ "" : DefaultValue(descriptor, immutable, name_resolver);
+ vars["type_constant"] = FieldTypeName(GetType(descriptor));
vars["packed"] = descriptor->options().packed() ? "true" : "false";
vars["enum_map"] = "null";
vars["prototype"] = "null";
@@ -108,13 +85,21 @@ void InitTemplateVars(const FieldDescriptor* descriptor,
string singular_type;
switch (java_type) {
case JAVATYPE_MESSAGE:
- singular_type = ClassName(descriptor->message_type());
+ singular_type = name_resolver->GetClassName(descriptor->message_type(),
+ immutable);
vars["prototype"] = singular_type + ".getDefaultInstance()";
break;
case JAVATYPE_ENUM:
- singular_type = ClassName(descriptor->enum_type());
+ singular_type = name_resolver->GetClassName(descriptor->enum_type(),
+ immutable);
vars["enum_map"] = singular_type + ".internalGetValueMap()";
break;
+ case JAVATYPE_STRING:
+ singular_type = "java.lang.String";
+ break;
+ case JAVATYPE_BYTES:
+ singular_type = immutable ? "com.google.protobuf.ByteString" : "byte[]";
+ break;
default:
singular_type = BoxedPrimitiveTypeName(java_type);
break;
@@ -124,12 +109,15 @@ void InitTemplateVars(const FieldDescriptor* descriptor,
vars["singular_type"] = singular_type;
}
-void ExtensionGenerator::Generate(io::Printer* printer) {
+void ImmutableExtensionGenerator::Generate(io::Printer* printer) {
map<string, string> vars;
- InitTemplateVars(descriptor_, scope_, &vars);
+ const bool kUseImmutableNames = true;
+ InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_,
+ &vars);
printer->Print(vars,
"public static final int $constant_name$ = $number$;\n");
+ WriteFieldDocComment(printer, descriptor_);
if (HasDescriptorMethods(descriptor_->file())) {
// Non-lite extensions
if (descriptor_->extension_scope() == NULL) {
@@ -172,7 +160,8 @@ void ExtensionGenerator::Generate(io::Printer* printer) {
" $enum_map$,\n"
" $number$,\n"
" com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
- " $packed$);\n");
+ " $packed$,\n"
+ " $singular_type$.class);\n");
} else {
printer->Print(
vars,
@@ -186,12 +175,13 @@ void ExtensionGenerator::Generate(io::Printer* printer) {
" $prototype$,\n"
" $enum_map$,\n"
" $number$,\n"
- " com.google.protobuf.WireFormat.FieldType.$type_constant$);\n");
+ " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
+ " $singular_type$.class);\n");
}
}
}
-void ExtensionGenerator::GenerateNonNestedInitializationCode(
+void ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
io::Printer* printer) {
if (descriptor_->extension_scope() == NULL &&
HasDescriptorMethods(descriptor_->file())) {
@@ -203,7 +193,8 @@ void ExtensionGenerator::GenerateNonNestedInitializationCode(
}
}
-void ExtensionGenerator::GenerateRegistrationCode(io::Printer* printer) {
+void ImmutableExtensionGenerator::GenerateRegistrationCode(
+ io::Printer* printer) {
printer->Print(
"registry.add($scope$.$name$);\n",
"scope", scope_,
diff --git a/src/google/protobuf/compiler/java/java_extension.h b/src/google/protobuf/compiler/java/java_extension.h
index 009ed9ff..f1701fb5 100644
--- a/src/google/protobuf/compiler/java/java_extension.h
+++ b/src/google/protobuf/compiler/java/java_extension.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,6 +35,7 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__
#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__
+#include <map>
#include <string>
#include <google/protobuf/stubs/common.h>
@@ -42,6 +43,12 @@
namespace google {
namespace protobuf {
class FieldDescriptor; // descriptor.h
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
namespace io {
class Printer; // printer.h
}
@@ -56,17 +63,42 @@ namespace java {
// since extensions are just simple identifiers with interesting types.
class ExtensionGenerator {
public:
- explicit ExtensionGenerator(const FieldDescriptor* descriptor);
- ~ExtensionGenerator();
+ explicit ExtensionGenerator() {}
+ virtual ~ExtensionGenerator() {}
+
+ virtual void Generate(io::Printer* printer) = 0;
+ virtual void GenerateNonNestedInitializationCode(io::Printer* printer) = 0;
+ virtual void GenerateRegistrationCode(io::Printer* printer) = 0;
- void Generate(io::Printer* printer);
- void GenerateNonNestedInitializationCode(io::Printer* printer);
- void GenerateRegistrationCode(io::Printer* printer);
+ protected:
+ static void InitTemplateVars(const FieldDescriptor* descriptor,
+ const string& scope,
+ bool immutable,
+ ClassNameResolver* name_resolver,
+ map<string, string>* vars_pointer);
private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+};
+
+class ImmutableExtensionGenerator : public ExtensionGenerator {
+ public:
+ explicit ImmutableExtensionGenerator(const FieldDescriptor* descriptor,
+ Context* context);
+ virtual ~ImmutableExtensionGenerator();
+
+ virtual void Generate(io::Printer* printer);
+ virtual void GenerateNonNestedInitializationCode(io::Printer* printer);
+ virtual void GenerateRegistrationCode(io::Printer* printer);
+
+ protected:
const FieldDescriptor* descriptor_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
string scope_;
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionGenerator);
};
} // namespace java
@@ -74,4 +106,4 @@ class ExtensionGenerator {
} // namespace protobuf
} // namespace google
-#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index c7d433c8..af9978e2 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,102 +33,188 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/java/java_field.h>
-#include <google/protobuf/compiler/java/java_helpers.h>
-#include <google/protobuf/compiler/java/java_primitive_field.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_enum_field.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_lazy_message_field.h>
+#include <google/protobuf/compiler/java/java_map_field.h>
#include <google/protobuf/compiler/java/java_message_field.h>
+#include <google/protobuf/compiler/java/java_primitive_field.h>
#include <google/protobuf/compiler/java/java_string_field.h>
-#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
namespace google {
namespace protobuf {
namespace compiler {
namespace java {
-FieldGenerator::~FieldGenerator() {}
+namespace {
-void FieldGenerator::GenerateParsingCodeFromPacked(io::Printer* printer) const {
+ImmutableFieldGenerator* MakeImmutableGenerator(
+ const FieldDescriptor* field, int messageBitIndex, int builderBitIndex,
+ Context* context) {
+ if (field->is_repeated()) {
+ switch (GetJavaType(field)) {
+ case JAVATYPE_MESSAGE:
+ if (IsMapEntry(field->message_type())) {
+ return new ImmutableMapFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ } else {
+ if (IsLazy(field)) {
+ return new RepeatedImmutableLazyMessageFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ } else {
+ return new RepeatedImmutableMessageFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ }
+ case JAVATYPE_ENUM:
+ return new RepeatedImmutableEnumFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ case JAVATYPE_STRING:
+ return new RepeatedImmutableStringFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ default:
+ return new RepeatedImmutablePrimitiveFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ } else {
+ if (field->containing_oneof()) {
+ switch (GetJavaType(field)) {
+ case JAVATYPE_MESSAGE:
+ if (IsLazy(field)) {
+ return new ImmutableLazyMessageOneofFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ } else {
+ return new ImmutableMessageOneofFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ case JAVATYPE_ENUM:
+ return new ImmutableEnumOneofFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ case JAVATYPE_STRING:
+ return new ImmutableStringOneofFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ default:
+ return new ImmutablePrimitiveOneofFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ } else {
+ switch (GetJavaType(field)) {
+ case JAVATYPE_MESSAGE:
+ if (IsLazy(field)) {
+ return new ImmutableLazyMessageFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ } else {
+ return new ImmutableMessageFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ case JAVATYPE_ENUM:
+ return new ImmutableEnumFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ case JAVATYPE_STRING:
+ return new ImmutableStringFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ default:
+ return new ImmutablePrimitiveFieldGenerator(
+ field, messageBitIndex, builderBitIndex, context);
+ }
+ }
+ }
+}
+
+
+static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) {
// Reaching here indicates a bug. Cases are:
- // - This FieldGenerator should support packing, but this method should be
- // overridden.
- // - This FieldGenerator doesn't support packing, and this method should
- // never have been called.
+ // - This FieldGenerator should support packing,
+ // but this method should be overridden.
+ // - This FieldGenerator doesn't support packing, and this method
+ // should never have been called.
GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() "
<< "called on field generator that does not support packing.";
}
-FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
- : descriptor_(descriptor),
- field_generators_(
- new scoped_ptr<FieldGenerator>[descriptor->field_count()]),
- extension_generators_(
- new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
+} // namespace
+
+ImmutableFieldGenerator::~ImmutableFieldGenerator() {}
+
+void ImmutableFieldGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+ ReportUnexpectedPackedFieldsCall(printer);
+}
+
+// ===================================================================
+
+template <>
+FieldGeneratorMap<ImmutableFieldGenerator>::FieldGeneratorMap(
+ const Descriptor* descriptor, Context* context)
+ : descriptor_(descriptor),
+ field_generators_(new google::protobuf::scoped_ptr<
+ ImmutableFieldGenerator>[descriptor->field_count()]) {
// Construct all the FieldGenerators and assign them bit indices for their
// bit fields.
int messageBitIndex = 0;
int builderBitIndex = 0;
for (int i = 0; i < descriptor->field_count(); i++) {
- FieldGenerator* generator = MakeGenerator(descriptor->field(i),
- messageBitIndex, builderBitIndex);
+ ImmutableFieldGenerator* generator = MakeImmutableGenerator(
+ descriptor->field(i), messageBitIndex, builderBitIndex, context);
field_generators_[i].reset(generator);
messageBitIndex += generator->GetNumBitsForMessage();
builderBitIndex += generator->GetNumBitsForBuilder();
}
- for (int i = 0; i < descriptor->extension_count(); i++) {
- FieldGenerator* generator = MakeGenerator(descriptor->extension(i),
- messageBitIndex, builderBitIndex);
- extension_generators_[i].reset(generator);
- messageBitIndex += generator->GetNumBitsForMessage();
- builderBitIndex += generator->GetNumBitsForBuilder();
- }
}
-FieldGenerator* FieldGeneratorMap::MakeGenerator(
- const FieldDescriptor* field, int messageBitIndex, int builderBitIndex) {
- if (field->is_repeated()) {
- switch (GetJavaType(field)) {
- case JAVATYPE_MESSAGE:
- return new RepeatedMessageFieldGenerator(
- field, messageBitIndex, builderBitIndex);
- case JAVATYPE_ENUM:
- return new RepeatedEnumFieldGenerator(
- field, messageBitIndex, builderBitIndex);
- case JAVATYPE_STRING:
- return new RepeatedStringFieldGenerator(
- field, messageBitIndex, builderBitIndex);
- default:
- return new RepeatedPrimitiveFieldGenerator(
- field, messageBitIndex, builderBitIndex);
- }
- } else {
- switch (GetJavaType(field)) {
- case JAVATYPE_MESSAGE:
- return new MessageFieldGenerator(
- field, messageBitIndex, builderBitIndex);
- case JAVATYPE_ENUM:
- return new EnumFieldGenerator(
- field, messageBitIndex, builderBitIndex);
- case JAVATYPE_STRING:
- return new StringFieldGenerator(
- field, messageBitIndex, builderBitIndex);
- default:
- return new PrimitiveFieldGenerator(
- field, messageBitIndex, builderBitIndex);
- }
- }
-}
+template<>
+FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap() {}
-FieldGeneratorMap::~FieldGeneratorMap() {}
-const FieldGenerator& FieldGeneratorMap::get(
- const FieldDescriptor* field) const {
- GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
- return *field_generators_[field->index()];
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+ const FieldGeneratorInfo* info,
+ map<string, string>* variables) {
+ (*variables)["field_name"] = descriptor->name();
+ (*variables)["name"] = info->name;
+ (*variables)["capitalized_name"] = info->capitalized_name;
+ (*variables)["disambiguated_reason"] = info->disambiguated_reason;
+ (*variables)["constant_name"] = FieldConstantName(descriptor);
+ (*variables)["number"] = SimpleItoa(descriptor->number());
}
-const FieldGenerator& FieldGeneratorMap::get_extension(int index) const {
- return *extension_generators_[index];
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+ const OneofGeneratorInfo* info,
+ map<string, string>* variables) {
+ (*variables)["oneof_name"] = info->name;
+ (*variables)["oneof_capitalized_name"] = info->capitalized_name;
+ (*variables)["oneof_index"] =
+ SimpleItoa(descriptor->containing_oneof()->index());
+ (*variables)["set_oneof_case_message"] = info->name +
+ "Case_ = " + SimpleItoa(descriptor->number());
+ (*variables)["clear_oneof_case_message"] = info->name +
+ "Case_ = 0";
+ (*variables)["has_oneof_case_message"] = info->name +
+ "Case_ == " + SimpleItoa(descriptor->number());
+}
+
+void PrintExtraFieldInfo(const map<string, string>& variables,
+ io::Printer* printer) {
+ const map<string, string>::const_iterator it =
+ variables.find("disambiguated_reason");
+ if (it != variables.end() && !it->second.empty()) {
+ printer->Print(
+ variables,
+ "// An alternative name is used for field \"$field_name$\" because:\n"
+ "// $disambiguated_reason$\n");
+ }
}
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
index 6097f357..1cf360c1 100644
--- a/src/google/protobuf/compiler/java/java_field.h
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,14 +35,26 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
+
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
namespace google {
namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
namespace io {
- class Printer; // printer.h
+ class Printer; // printer.h
}
}
@@ -50,10 +62,10 @@ namespace protobuf {
namespace compiler {
namespace java {
-class FieldGenerator {
+class ImmutableFieldGenerator {
public:
- FieldGenerator() {}
- virtual ~FieldGenerator();
+ ImmutableFieldGenerator() {}
+ virtual ~ImmutableFieldGenerator();
virtual int GetNumBitsForMessage() const = 0;
virtual int GetNumBitsForBuilder() const = 0;
@@ -66,10 +78,12 @@ class FieldGenerator {
virtual void GenerateBuildingCode(io::Printer* printer) const = 0;
virtual void GenerateParsingCode(io::Printer* printer) const = 0;
virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+ virtual void GenerateParsingDoneCode(io::Printer* printer) const = 0;
virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer)
const = 0;
+ virtual void GenerateStaticInitializationCode(io::Printer* printer) const {}
virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
virtual void GenerateHashCode(io::Printer* printer) const = 0;
@@ -77,29 +91,73 @@ class FieldGenerator {
virtual string GetBoxedType() const = 0;
private:
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldGenerator);
};
+
// Convenience class which constructs FieldGenerators for a Descriptor.
+template<typename FieldGeneratorType>
class FieldGeneratorMap {
public:
- explicit FieldGeneratorMap(const Descriptor* descriptor);
+ explicit FieldGeneratorMap(const Descriptor* descriptor,
+ Context* context);
~FieldGeneratorMap();
- const FieldGenerator& get(const FieldDescriptor* field) const;
- const FieldGenerator& get_extension(int index) const;
+ const FieldGeneratorType& get(const FieldDescriptor* field) const;
private:
const Descriptor* descriptor_;
- scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
- scoped_array<scoped_ptr<FieldGenerator> > extension_generators_;
-
- static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
- int messageBitIndex, int builderBitIndex);
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<FieldGeneratorType> > field_generators_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
};
+template<typename FieldGeneratorType>
+inline const FieldGeneratorType&
+FieldGeneratorMap<FieldGeneratorType>::get(const FieldDescriptor* field) const {
+ GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
+ return *field_generators_[field->index()];
+}
+
+// Instantiate template for mutable and immutable maps.
+template<>
+FieldGeneratorMap<ImmutableFieldGenerator>::
+FieldGeneratorMap(const Descriptor* descriptor,
+ Context* context);
+
+template<>
+FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap();
+
+
+// Field information used in FieldGeneartors.
+struct FieldGeneratorInfo {
+ string name;
+ string capitalized_name;
+ string disambiguated_reason;
+};
+
+// Oneof information used in OneofFieldGeneartors.
+struct OneofGeneratorInfo {
+ string name;
+ string capitalized_name;
+};
+
+// Set some common variables used in variable FieldGenerators.
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+ const FieldGeneratorInfo* info,
+ map<string, string>* variables);
+
+// Set some common oneof variables used in OneofFieldGenerators.
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+ const OneofGeneratorInfo* info,
+ map<string, string>* variables);
+
+// Print useful comments before a field's accessors.
+void PrintExtraFieldInfo(const map<string, string>& variables,
+ io::Printer* printer);
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 8968069f..f1e3cf67 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,15 +33,26 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/java/java_file.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_enum.h>
-#include <google/protobuf/compiler/java/java_service.h>
#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_generator_factory.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_message.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_service.h>
+#include <google/protobuf/compiler/java/java_shared_code_generator.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
@@ -51,18 +62,24 @@ namespace java {
namespace {
-// Recursively searches the given message to see if it contains any extensions.
-bool UsesExtensions(const Message& message) {
+
+// Recursively searches the given message to collect extensions.
+// Returns true if all the extensions can be recognized. The extensions will be
+// appended in to the extensions parameter.
+// Returns false when there are unknown fields, in which case the data in the
+// extensions output parameter is not reliable and should be discarded.
+bool CollectExtensions(const Message& message,
+ vector<const FieldDescriptor*>* extensions) {
const Reflection* reflection = message.GetReflection();
- // We conservatively assume that unknown fields are extensions.
- if (reflection->GetUnknownFields(message).field_count() > 0) return true;
+ // There are unknown fields that could be extensions, thus this call fails.
+ if (reflection->GetUnknownFields(message).field_count() > 0) return false;
vector<const FieldDescriptor*> fields;
reflection->ListFields(message, &fields);
for (int i = 0; i < fields.size(); i++) {
- if (fields[i]->is_extension()) return true;
+ if (fields[i]->is_extension()) extensions->push_back(fields[i]);
if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
if (fields[i]->is_repeated()) {
@@ -70,25 +87,82 @@ bool UsesExtensions(const Message& message) {
for (int j = 0; j < size; j++) {
const Message& sub_message =
reflection->GetRepeatedMessage(message, fields[i], j);
- if (UsesExtensions(sub_message)) return true;
+ if (!CollectExtensions(sub_message, extensions)) return false;
}
} else {
const Message& sub_message = reflection->GetMessage(message, fields[i]);
- if (UsesExtensions(sub_message)) return true;
+ if (!CollectExtensions(sub_message, extensions)) return false;
}
}
}
- return false;
+ return true;
+}
+
+// Finds all extensions in the given message and its sub-messages. If the
+// message contains unknown fields (which could be extensions), then those
+// extensions are defined in alternate_pool.
+// The message will be converted to a DynamicMessage backed by alternate_pool
+// in order to handle this case.
+void CollectExtensions(const FileDescriptorProto& file_proto,
+ const DescriptorPool& alternate_pool,
+ vector<const FieldDescriptor*>* extensions,
+ const string& file_data) {
+ if (!CollectExtensions(file_proto, extensions)) {
+ // There are unknown fields in the file_proto, which are probably
+ // extensions. We need to parse the data into a dynamic message based on the
+ // builder-pool to find out all extensions.
+ const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName(
+ file_proto.GetDescriptor()->full_name());
+ GOOGLE_CHECK(file_proto_desc)
+ << "Find unknown fields in FileDescriptorProto when building "
+ << file_proto.name()
+ << ". It's likely that those fields are custom options, however, "
+ "descriptor.proto is not in the transitive dependencies. "
+ "This normally should not happen. Please report a bug.";
+ DynamicMessageFactory factory;
+ google::protobuf::scoped_ptr<Message> dynamic_file_proto(
+ factory.GetPrototype(file_proto_desc)->New());
+ GOOGLE_CHECK(dynamic_file_proto.get() != NULL);
+ GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data));
+
+ // Collect the extensions again from the dynamic message. There should be no
+ // more unknown fields this time, i.e. all the custom options should be
+ // parsed as extensions now.
+ extensions->clear();
+ GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions))
+ << "Find unknown fields in FileDescriptorProto when building "
+ << file_proto.name()
+ << ". It's likely that those fields are custom options, however, "
+ "those options cannot be recognized in the builder pool. "
+ "This normally should not happen. Please report a bug.";
+ }
}
} // namespace
-FileGenerator::FileGenerator(const FileDescriptor* file)
- : file_(file),
- java_package_(FileJavaPackage(file)),
- classname_(FileClassName(file)) {
+FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
+ : file_(file),
+ java_package_(FileJavaPackage(file, immutable_api)),
+ message_generators_(
+ new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]),
+ extension_generators_(
+ new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]),
+ context_(new Context(file)),
+ name_resolver_(context_->GetNameResolver()),
+ immutable_api_(immutable_api) {
+ classname_ = name_resolver_->GetFileClassName(file, immutable_api);
+ generator_factory_.reset(
+ new ImmutableGeneratorFactory(context_.get()));
+ for (int i = 0; i < file_->message_type_count(); ++i) {
+ message_generators_[i].reset(
+ generator_factory_->NewMessageGenerator(file_->message_type(i)));
+ }
+ for (int i = 0; i < file_->extension_count(); ++i) {
+ extension_generators_[i].reset(
+ generator_factory_->NewExtensionGenerator(file_->extension(i)));
+ }
}
FileGenerator::~FileGenerator() {}
@@ -98,25 +172,7 @@ bool FileGenerator::Validate(string* error) {
// problem that leads to Java compile errors that can be hard to understand.
// It's especially bad when using the java_multiple_files, since we would
// end up overwriting the outer class with one of the inner ones.
-
- bool found_conflict = false;
- for (int i = 0; i < file_->enum_type_count() && !found_conflict; i++) {
- if (file_->enum_type(i)->name() == classname_) {
- found_conflict = true;
- }
- }
- for (int i = 0; i < file_->message_type_count() && !found_conflict; i++) {
- if (file_->message_type(i)->name() == classname_) {
- found_conflict = true;
- }
- }
- for (int i = 0; i < file_->service_count() && !found_conflict; i++) {
- if (file_->service(i)->name() == classname_) {
- found_conflict = true;
- }
- }
-
- if (found_conflict) {
+ if (name_resolver_->HasConflictingClassName(file_, classname_)) {
error->assign(file_->name());
error->append(
": Cannot generate Java output because the file's outer class name, \"");
@@ -127,7 +183,6 @@ bool FileGenerator::Validate(string* error) {
"option to specify a different outer class name for the .proto file.");
return false;
}
-
return true;
}
@@ -161,12 +216,11 @@ void FileGenerator::Generate(io::Printer* printer) {
printer->Indent();
for (int i = 0; i < file_->extension_count(); i++) {
- ExtensionGenerator(file_->extension(i)).GenerateRegistrationCode(printer);
+ extension_generators_[i]->GenerateRegistrationCode(printer);
}
for (int i = 0; i < file_->message_type_count(); i++) {
- MessageGenerator(file_->message_type(i))
- .GenerateExtensionRegistrationCode(printer);
+ message_generators_[i]->GenerateExtensionRegistrationCode(printer);
}
printer->Outdent();
@@ -175,18 +229,20 @@ void FileGenerator::Generate(io::Printer* printer) {
// -----------------------------------------------------------------
- if (!file_->options().java_multiple_files()) {
+ if (!MultipleJavaFiles(file_, immutable_api_)) {
for (int i = 0; i < file_->enum_type_count(); i++) {
- EnumGenerator(file_->enum_type(i)).Generate(printer);
+ EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
+ .Generate(printer);
}
for (int i = 0; i < file_->message_type_count(); i++) {
- MessageGenerator messageGenerator(file_->message_type(i));
- messageGenerator.GenerateInterface(printer);
- messageGenerator.Generate(printer);
+ message_generators_[i]->GenerateInterface(printer);
+ message_generators_[i]->Generate(printer);
}
if (HasGenericServices(file_)) {
for (int i = 0; i < file_->service_count(); i++) {
- ServiceGenerator(file_->service(i)).Generate(printer);
+ google::protobuf::scoped_ptr<ServiceGenerator> generator(
+ generator_factory_->NewServiceGenerator(file_->service(i)));
+ generator->Generate(printer);
}
}
}
@@ -194,28 +250,29 @@ void FileGenerator::Generate(io::Printer* printer) {
// Extensions must be generated in the outer class since they are values,
// not classes.
for (int i = 0; i < file_->extension_count(); i++) {
- ExtensionGenerator(file_->extension(i)).Generate(printer);
+ extension_generators_[i]->Generate(printer);
}
// Static variables.
for (int i = 0; i < file_->message_type_count(); i++) {
- // TODO(kenton): Reuse MessageGenerator objects?
- MessageGenerator(file_->message_type(i)).GenerateStaticVariables(printer);
+ message_generators_[i]->GenerateStaticVariables(printer);
}
printer->Print("\n");
if (HasDescriptorMethods(file_)) {
- GenerateEmbeddedDescriptor(printer);
+ if (immutable_api_) {
+ GenerateDescriptorInitializationCodeForImmutable(printer);
+ } else {
+ GenerateDescriptorInitializationCodeForMutable(printer);
+ }
} else {
printer->Print(
"static {\n");
printer->Indent();
for (int i = 0; i < file_->message_type_count(); i++) {
- // TODO(kenton): Reuse MessageGenerator objects?
- MessageGenerator(file_->message_type(i))
- .GenerateStaticVariableInitializers(printer);
+ message_generators_[i]->GenerateStaticVariableInitializers(printer);
}
printer->Outdent();
@@ -231,23 +288,8 @@ void FileGenerator::Generate(io::Printer* printer) {
printer->Print("}\n");
}
-void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
- // Embed the descriptor. We simply serialize the entire FileDescriptorProto
- // and embed it as a string literal, which is parsed and built into real
- // descriptors at initialization time. We unfortunately have to put it in
- // a string literal, not a byte array, because apparently using a literal
- // byte array causes the Java compiler to generate *instructions* to
- // initialize each and every byte of the array, e.g. as if you typed:
- // b[0] = 123; b[1] = 456; b[2] = 789;
- // This makes huge bytecode files and can easily hit the compiler's internal
- // code size limits (error "code to large"). String literals are apparently
- // embedded raw, which is what we want.
- FileDescriptorProto file_proto;
- file_->CopyTo(&file_proto);
-
- string file_data;
- file_proto.SerializeToString(&file_data);
-
+void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
+ io::Printer* printer) {
printer->Print(
"public static com.google.protobuf.Descriptors.FileDescriptor\n"
" getDescriptor() {\n"
@@ -255,105 +297,136 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
"}\n"
"private static com.google.protobuf.Descriptors.FileDescriptor\n"
" descriptor;\n"
- "static {\n"
- " java.lang.String[] descriptorData = {\n");
- printer->Indent();
+ "static {\n");
printer->Indent();
- // Only write 40 bytes per line.
- static const int kBytesPerLine = 40;
- for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
- if (i > 0) {
- // Every 400 lines, start a new string literal, in order to avoid the
- // 64k length limit.
- if (i % 400 == 0) {
- printer->Print(",\n");
- } else {
- printer->Print(" +\n");
- }
- }
- printer->Print("\"$data$\"",
- "data", CEscape(file_data.substr(i, kBytesPerLine)));
- }
-
- printer->Outdent();
- printer->Print("\n};\n");
-
- // -----------------------------------------------------------------
- // Create the InternalDescriptorAssigner.
+ SharedCodeGenerator shared_code_generator(file_);
+ shared_code_generator.GenerateDescriptors(printer);
- printer->Print(
- "com.google.protobuf.Descriptors.FileDescriptor."
- "InternalDescriptorAssigner assigner =\n"
- " new com.google.protobuf.Descriptors.FileDescriptor."
- "InternalDescriptorAssigner() {\n"
- " public com.google.protobuf.ExtensionRegistry assignDescriptors(\n"
- " com.google.protobuf.Descriptors.FileDescriptor root) {\n"
- " descriptor = root;\n");
-
- printer->Indent();
- printer->Indent();
- printer->Indent();
for (int i = 0; i < file_->message_type_count(); i++) {
- // TODO(kenton): Reuse MessageGenerator objects?
- MessageGenerator(file_->message_type(i))
- .GenerateStaticVariableInitializers(printer);
+ message_generators_[i]->GenerateStaticVariableInitializers(printer);
}
for (int i = 0; i < file_->extension_count(); i++) {
- // TODO(kenton): Reuse ExtensionGenerator objects?
- ExtensionGenerator(file_->extension(i))
- .GenerateNonNestedInitializationCode(printer);
+ extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
}
- if (UsesExtensions(file_proto)) {
- // Must construct an ExtensionRegistry containing all possible extensions
- // and return it.
+ // Proto compiler builds a DescriptorPool, which holds all the descriptors to
+ // generate, when processing the ".proto" files. We call this DescriptorPool
+ // the parsed pool (a.k.a. file_->pool()).
+ //
+ // Note that when users try to extend the (.*)DescriptorProto in their
+ // ".proto" files, it does not affect the pre-built FileDescriptorProto class
+ // in proto compiler. When we put the descriptor data in the file_proto, those
+ // extensions become unknown fields.
+ //
+ // Now we need to find out all the extension value to the (.*)DescriptorProto
+ // in the file_proto message, and prepare an ExtensionRegistry to return.
+ //
+ // To find those extensions, we need to parse the data into a dynamic message
+ // of the FileDescriptor based on the builder-pool, then we can use
+ // reflections to find all extension fields
+ FileDescriptorProto file_proto;
+ file_->CopyTo(&file_proto);
+ string file_data;
+ file_proto.SerializeToString(&file_data);
+ vector<const FieldDescriptor*> extensions;
+ CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
+
+ if (extensions.size() > 0) {
+ // Must construct an ExtensionRegistry containing all existing extensions
+ // and use it to parse the descriptor data again to recognize extensions.
printer->Print(
"com.google.protobuf.ExtensionRegistry registry =\n"
- " com.google.protobuf.ExtensionRegistry.newInstance();\n"
- "registerAllExtensions(registry);\n");
- for (int i = 0; i < file_->dependency_count(); i++) {
- if (ShouldIncludeDependency(file_->dependency(i))) {
- printer->Print(
- "$dependency$.registerAllExtensions(registry);\n",
- "dependency", ClassName(file_->dependency(i)));
- }
+ " com.google.protobuf.ExtensionRegistry.newInstance();\n");
+ for (int i = 0; i < extensions.size(); i++) {
+ google::protobuf::scoped_ptr<ExtensionGenerator> generator(
+ generator_factory_->NewExtensionGenerator(extensions[i]));
+ generator->GenerateRegistrationCode(printer);
}
printer->Print(
- "return registry;\n");
- } else {
- printer->Print(
- "return null;\n");
+ "com.google.protobuf.Descriptors.FileDescriptor\n"
+ " .internalUpdateFileDescriptor(descriptor, registry);\n");
}
- printer->Outdent();
- printer->Outdent();
- printer->Outdent();
+ // Force descriptor initialization of all dependencies.
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ if (ShouldIncludeDependency(file_->dependency(i), true)) {
+ string dependency =
+ name_resolver_->GetImmutableClassName(file_->dependency(i));
+ printer->Print(
+ "$dependency$.getDescriptor();\n",
+ "dependency", dependency);
+ }
+ }
+ printer->Outdent();
printer->Print(
- " }\n"
- " };\n");
+ "}\n");
+}
- // -----------------------------------------------------------------
- // Invoke internalBuildGeneratedFileFrom() to build the file.
+void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer* printer) {
+ printer->Print(
+ "public static com.google.protobuf.Descriptors.FileDescriptor\n"
+ " getDescriptor() {\n"
+ " return descriptor;\n"
+ "}\n"
+ "private static com.google.protobuf.Descriptors.FileDescriptor\n"
+ " descriptor;\n"
+ "static {\n");
+ printer->Indent();
printer->Print(
- "com.google.protobuf.Descriptors.FileDescriptor\n"
- " .internalBuildGeneratedFileFrom(descriptorData,\n"
- " new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
+ "descriptor = $immutable_package$.$descriptor_classname$.descriptor;\n",
+ "immutable_package", FileJavaPackage(file_, true),
+ "descriptor_classname", name_resolver_->GetDescriptorClassName(file_));
+
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateStaticVariableInitializers(printer);
+ }
+ for (int i = 0; i < file_->extension_count(); i++) {
+ extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
+ }
+
+ // Check if custom options exist. If any, try to load immutable classes since
+ // custom options are only represented with immutable messages.
+ FileDescriptorProto file_proto;
+ file_->CopyTo(&file_proto);
+ string file_data;
+ file_proto.SerializeToString(&file_data);
+ vector<const FieldDescriptor*> extensions;
+ CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
+
+ if (extensions.size() > 0) {
+ // Try to load immutable messages' outer class. Its initialization code
+ // will take care of interpreting custom options.
+ printer->Print(
+ "try {\n"
+ // Note that we have to load the immutable class dynamically here as
+ // we want the mutable code to be independent from the immutable code
+ // at compile time. It is required to implement dual-compile for
+ // mutable and immutable API in blaze.
+ " java.lang.Class immutableClass = java.lang.Class.forName(\n"
+ " \"$immutable_classname$\");\n"
+ "} catch (java.lang.ClassNotFoundException e) {\n"
+ // The immutable class can not be found. Custom options are left
+ // as unknown fields.
+ // TODO(xiaofeng): inform the user with a warning?
+ "}\n",
+ "immutable_classname", name_resolver_->GetImmutableClassName(file_));
+ }
+ // Force descriptor initialization of all dependencies.
for (int i = 0; i < file_->dependency_count(); i++) {
- if (ShouldIncludeDependency(file_->dependency(i))) {
+ if (ShouldIncludeDependency(file_->dependency(i), false)) {
+ string dependency = name_resolver_->GetMutableClassName(
+ file_->dependency(i));
printer->Print(
- " $dependency$.getDescriptor(),\n",
- "dependency", ClassName(file_->dependency(i)));
+ "$dependency$.getDescriptor();\n",
+ "dependency", dependency);
}
}
- printer->Print(
- " }, assigner);\n");
-
printer->Outdent();
printer->Print(
"}\n");
@@ -366,16 +439,19 @@ static void GenerateSibling(const string& package_dir,
GeneratorContext* context,
vector<string>* file_list,
const string& name_suffix,
+ GeneratorClass* generator,
void (GeneratorClass::*pfn)(io::Printer* printer)) {
string filename = package_dir + descriptor->name() + name_suffix + ".java";
file_list->push_back(filename);
- scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
io::Printer printer(output.get(), '$');
printer.Print(
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
- "\n");
+ "// source: $filename$\n"
+ "\n",
+ "filename", descriptor->file()->name());
if (!java_package.empty()) {
printer.Print(
"package $package$;\n"
@@ -383,42 +459,53 @@ static void GenerateSibling(const string& package_dir,
"package", java_package);
}
- GeneratorClass generator(descriptor);
- (generator.*pfn)(&printer);
+ (generator->*pfn)(&printer);
}
void FileGenerator::GenerateSiblings(const string& package_dir,
GeneratorContext* context,
vector<string>* file_list) {
- if (file_->options().java_multiple_files()) {
+ if (MultipleJavaFiles(file_, immutable_api_)) {
for (int i = 0; i < file_->enum_type_count(); i++) {
+ EnumGenerator generator(file_->enum_type(i), immutable_api_,
+ context_.get());
GenerateSibling<EnumGenerator>(package_dir, java_package_,
file_->enum_type(i),
context, file_list, "",
+ &generator,
&EnumGenerator::Generate);
}
for (int i = 0; i < file_->message_type_count(); i++) {
- GenerateSibling<MessageGenerator>(package_dir, java_package_,
- file_->message_type(i),
- context, file_list, "OrBuilder",
- &MessageGenerator::GenerateInterface);
+ if (immutable_api_) {
+ GenerateSibling<MessageGenerator>(package_dir, java_package_,
+ file_->message_type(i),
+ context, file_list,
+ "OrBuilder",
+ message_generators_[i].get(),
+ &MessageGenerator::GenerateInterface);
+ }
GenerateSibling<MessageGenerator>(package_dir, java_package_,
file_->message_type(i),
context, file_list, "",
+ message_generators_[i].get(),
&MessageGenerator::Generate);
}
if (HasGenericServices(file_)) {
for (int i = 0; i < file_->service_count(); i++) {
+ google::protobuf::scoped_ptr<ServiceGenerator> generator(
+ generator_factory_->NewServiceGenerator(file_->service(i)));
GenerateSibling<ServiceGenerator>(package_dir, java_package_,
file_->service(i),
context, file_list, "",
+ generator.get(),
&ServiceGenerator::Generate);
}
}
}
}
-bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) {
+bool FileGenerator::ShouldIncludeDependency(
+ const FileDescriptor* descriptor, bool immutable_api) {
return true;
}
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index 59911462..080b3424 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,18 +35,29 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
#define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
- class FileDescriptor; // descriptor.h
+ class FileDescriptor; // descriptor.h
namespace io {
- class Printer; // printer.h
+ class Printer; // printer.h
}
namespace compiler {
- class GeneratorContext; // code_generator.h
+ class GeneratorContext; // code_generator.h
+ namespace java {
+ class Context; // context.h
+ class MessageGenerator; // message.h
+ class GeneratorFactory; // generator_factory.h
+ class ExtensionGenerator; // extension.h
+ class ClassNameResolver; // name_resolver.h
+ }
}
}
@@ -56,7 +67,7 @@ namespace java {
class FileGenerator {
public:
- explicit FileGenerator(const FileDescriptor* file);
+ FileGenerator(const FileDescriptor* file, bool immutable_api = true);
~FileGenerator();
// Checks for problems that would otherwise lead to cryptic compile errors.
@@ -78,17 +89,23 @@ class FileGenerator {
private:
- // Returns whether the dependency should be included in the output file.
- // Always returns true for opensource, but used internally at Google to help
- // improve compatibility with version 1 of protocol buffers.
- bool ShouldIncludeDependency(const FileDescriptor* descriptor);
+ void GenerateDescriptorInitializationCodeForImmutable(io::Printer* printer);
+ void GenerateDescriptorInitializationCodeForMutable(io::Printer* printer);
+
+ bool ShouldIncludeDependency(const FileDescriptor* descriptor,
+ bool immutable_api_);
const FileDescriptor* file_;
string java_package_;
string classname_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
+ google::protobuf::scoped_ptr<GeneratorFactory> generator_factory_;
+ google::protobuf::scoped_ptr<Context> context_;
+ ClassNameResolver* name_resolver_;
+ bool immutable_api_;
- void GenerateEmbeddedDescriptor(io::Printer* printer);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
};
diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
index e6c79abc..6c6f7286 100644
--- a/src/google/protobuf/compiler/java/java_generator.cc
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,8 +33,16 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/java/java_generator.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
#include <google/protobuf/compiler/java/java_file.h>
+#include <google/protobuf/compiler/java/java_generator_factory.h>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_shared_code_generator.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.pb.h>
@@ -64,55 +72,84 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
vector<pair<string, string> > options;
ParseGeneratorParameter(parameter, &options);
+ bool generate_immutable_code = false;
+ bool generate_mutable_code = false;
+ bool generate_shared_code = false;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "output_list_file") {
output_list_file = options[i].second;
+ } else if (options[i].first == "immutable") {
+ generate_immutable_code = true;
+ } else if (options[i].first == "mutable") {
+ generate_mutable_code = true;
+ } else if (options[i].first == "shared") {
+ generate_shared_code = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
}
}
+ // By default we generate immutable code and shared code for immutable API.
+ if (!generate_immutable_code && !generate_mutable_code &&
+ !generate_shared_code) {
+ generate_immutable_code = true;
+ generate_shared_code = true;
+ }
+
// -----------------------------------------------------------------
- if (file->options().optimize_for() == FileOptions::LITE_RUNTIME &&
- file->options().java_generate_equals_and_hash()) {
- *error = "The \"java_generate_equals_and_hash\" option is incompatible "
- "with \"optimize_for = LITE_RUNTIME\". You must optimize for "
- "SPEED or CODE_SIZE if you want to use this option.";
- return false;
- }
+ vector<string> all_files;
- FileGenerator file_generator(file);
- if (!file_generator.Validate(error)) {
- return false;
+
+ vector<FileGenerator*> file_generators;
+ if (generate_immutable_code) {
+ file_generators.push_back(new FileGenerator(file, /* immutable = */ true));
+ }
+ if (generate_mutable_code) {
+ file_generators.push_back(new FileGenerator(file, /* mutable = */ false));
+ }
+ for (int i = 0; i < file_generators.size(); ++i) {
+ if (!file_generators[i]->Validate(error)) {
+ for (int j = 0; j < file_generators.size(); ++j) {
+ delete file_generators[j];
+ }
+ return false;
+ }
}
- string package_dir = JavaPackageToDir(file_generator.java_package());
+ for (int i = 0; i < file_generators.size(); ++i) {
+ FileGenerator* file_generator = file_generators[i];
- vector<string> all_files;
+ string package_dir = JavaPackageToDir(file_generator->java_package());
- string java_filename = package_dir;
- java_filename += file_generator.classname();
- java_filename += ".java";
- all_files.push_back(java_filename);
+ string java_filename = package_dir;
+ java_filename += file_generator->classname();
+ java_filename += ".java";
+ all_files.push_back(java_filename);
- // Generate main java file.
- scoped_ptr<io::ZeroCopyOutputStream> output(
- context->Open(java_filename));
- io::Printer printer(output.get(), '$');
- file_generator.Generate(&printer);
+ // Generate main java file.
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->Open(java_filename));
+ io::Printer printer(output.get(), '$');
+ file_generator->Generate(&printer);
- // Generate sibling files.
- file_generator.GenerateSiblings(package_dir, context, &all_files);
+ // Generate sibling files.
+ file_generator->GenerateSiblings(package_dir, context, &all_files);
+ }
+
+ for (int i = 0; i < file_generators.size(); ++i) {
+ delete file_generators[i];
+ }
+ file_generators.clear();
// Generate output list if requested.
if (!output_list_file.empty()) {
// Generate output list. This is just a simple text file placed in a
// deterministic location which lists the .java files being generated.
- scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
- context->Open(output_list_file));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
+ context->Open(output_list_file));
io::Printer srclist_printer(srclist_raw_output.get(), '$');
for (int i = 0; i < all_files.size(); i++) {
srclist_printer.Print("$filename$\n", "filename", all_files[i]);
diff --git a/src/google/protobuf/compiler/java/java_generator.h b/src/google/protobuf/compiler/java/java_generator.h
index 888b8d85..47f76be9 100644
--- a/src/google/protobuf/compiler/java/java_generator.h
+++ b/src/google/protobuf/compiler/java/java_generator.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc
new file mode 100644
index 00000000..2d1437f0
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_generator_factory.cc
@@ -0,0 +1,77 @@
+// 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: liujisi@google.com (Pherl Liu)
+
+#include <google/protobuf/compiler/java/java_generator_factory.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_enum_field.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_message.h>
+#include <google/protobuf/compiler/java/java_service.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+GeneratorFactory::GeneratorFactory() {}
+GeneratorFactory::~GeneratorFactory() {}
+
+// ===================================================================
+
+ImmutableGeneratorFactory::ImmutableGeneratorFactory(
+ Context* context) : context_(context) {
+}
+ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {}
+
+MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator(
+ const Descriptor* descriptor) const {
+ return new ImmutableMessageGenerator(descriptor, context_);
+}
+
+ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator(
+ const FieldDescriptor* descriptor) const {
+ return new ImmutableExtensionGenerator(descriptor, context_);
+}
+
+ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator(
+ const ServiceDescriptor* descriptor) const {
+ return new ImmutableServiceGenerator(descriptor, context_);
+}
+
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_generator_factory.h b/src/google/protobuf/compiler/java/java_generator_factory.h
new file mode 100644
index 00000000..55365a9d
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_generator_factory.h
@@ -0,0 +1,101 @@
+// 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: liujisi@google.com (Pherl Liu)
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+ class FieldDescriptor; // descriptor.h
+ class Descriptor; // descriptor.h
+ class ServiceDescriptor; // descriptor.h
+ namespace compiler {
+ namespace java {
+ class MessageGenerator; // message.h
+ class ExtensionGenerator; // extension.h
+ class ServiceGenerator; // service.h
+ class Context; // context.h
+ }
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class GeneratorFactory {
+ public:
+ GeneratorFactory();
+ virtual ~GeneratorFactory();
+
+ virtual MessageGenerator* NewMessageGenerator(
+ const Descriptor* descriptor) const = 0;
+
+ virtual ExtensionGenerator* NewExtensionGenerator(
+ const FieldDescriptor* descriptor) const = 0;
+
+ virtual ServiceGenerator* NewServiceGenerator(
+ const ServiceDescriptor* descriptor) const = 0;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorFactory);
+};
+
+// Factory that creates generators for immutable-default messages.
+class ImmutableGeneratorFactory : public GeneratorFactory {
+ public:
+ ImmutableGeneratorFactory(Context* context);
+ virtual ~ImmutableGeneratorFactory();
+
+ virtual MessageGenerator* NewMessageGenerator(
+ const Descriptor* descriptor) const;
+
+ virtual ExtensionGenerator* NewExtensionGenerator(
+ const FieldDescriptor* descriptor) const;
+
+ virtual ServiceGenerator* NewServiceGenerator(
+ const ServiceDescriptor* descriptor) const;
+
+ private:
+ Context* context_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableGeneratorFactory);
+};
+
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index 1b6f1653..e24894b1 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,11 +32,15 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
#include <limits>
#include <vector>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
@@ -45,6 +49,9 @@ namespace protobuf {
namespace compiler {
namespace java {
+using internal::WireFormat;
+using internal::WireFormatLite;
+
const char kThickSeparator[] =
"// ===================================================================\n";
const char kThinSeparator[] =
@@ -54,18 +61,47 @@ namespace {
const char* kDefaultPackage = "";
-const string& FieldName(const FieldDescriptor* field) {
+// Names that should be avoided as field names.
+// Using them will cause the compiler to generate accessors whose names are
+// colliding with methods defined in base classes.
+const char* kForbiddenWordList[] = {
+ // message base class:
+ "cached_size", "serialized_size",
+ // java.lang.Object:
+ "class",
+};
+
+bool IsForbidden(const string& field_name) {
+ for (int i = 0; i < GOOGLE_ARRAYSIZE(kForbiddenWordList); ++i) {
+ if (field_name == kForbiddenWordList[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+string FieldName(const FieldDescriptor* field) {
+ string field_name;
// Groups are hacky: The name of the field is just the lower-cased name
// of the group type. In Java, though, we would like to retain the original
// capitalization of the type name.
if (GetType(field) == FieldDescriptor::TYPE_GROUP) {
- return field->message_type()->name();
+ field_name = field->message_type()->name();
} else {
- return field->name();
+ field_name = field->name();
+ }
+ if (IsForbidden(field_name)) {
+ // Append a trailing "#" to indicate that the name should be decorated to
+ // avoid collision with other names.
+ field_name += "#";
}
+ return field_name;
}
-string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) {
+
+} // namespace
+
+string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
string result;
// Note: I distrust ctype.h due to locales.
for (int i = 0; i < input.size(); i++) {
@@ -93,21 +129,27 @@ string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) {
cap_next_letter = true;
}
}
+ // Add a trailing "_" if the name should be altered.
+ if (input[input.size() - 1] == '#') {
+ result += '_';
+ }
return result;
}
-} // namespace
-
string UnderscoresToCamelCase(const FieldDescriptor* field) {
- return UnderscoresToCamelCaseImpl(FieldName(field), false);
+ return UnderscoresToCamelCase(FieldName(field), false);
}
string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
- return UnderscoresToCamelCaseImpl(FieldName(field), true);
+ return UnderscoresToCamelCase(FieldName(field), true);
}
string UnderscoresToCamelCase(const MethodDescriptor* method) {
- return UnderscoresToCamelCaseImpl(method->name(), false);
+ return UnderscoresToCamelCase(method->name(), false);
+}
+
+string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
+ return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
}
string StripProto(const string& filename) {
@@ -118,22 +160,12 @@ string StripProto(const string& filename) {
}
}
-string FileClassName(const FileDescriptor* file) {
- if (file->options().has_java_outer_classname()) {
- return file->options().java_outer_classname();
- } else {
- string basename;
- string::size_type last_slash = file->name().find_last_of('/');
- if (last_slash == string::npos) {
- basename = file->name();
- } else {
- basename = file->name().substr(last_slash + 1);
- }
- return UnderscoresToCamelCaseImpl(StripProto(basename), true);
- }
+string FileClassName(const FileDescriptor* file, bool immutable) {
+ ClassNameResolver name_resolver;
+ return name_resolver.GetFileClassName(file, immutable);
}
-string FileJavaPackage(const FileDescriptor* file) {
+string FileJavaPackage(const FileDescriptor* file, bool immutable) {
string result;
if (file->options().has_java_package()) {
@@ -146,7 +178,6 @@ string FileJavaPackage(const FileDescriptor* file) {
}
}
-
return result;
}
@@ -157,7 +188,10 @@ string JavaPackageToDir(string package_name) {
return package_dir;
}
-string ToJavaName(const string& full_name, const FileDescriptor* file) {
+// TODO(xiaofeng): This function is only kept for it's publicly referenced.
+// It should be removed after mutable API up-integration.
+string ToJavaName(const string& full_name,
+ const FileDescriptor* file) {
string result;
if (file->options().java_multiple_files()) {
result = FileJavaPackage(file);
@@ -177,11 +211,43 @@ string ToJavaName(const string& full_name, const FileDescriptor* file) {
return result;
}
+string ClassName(const Descriptor* descriptor) {
+ ClassNameResolver name_resolver;
+ return name_resolver.GetClassName(descriptor, true);
+}
+
+string ClassName(const EnumDescriptor* descriptor) {
+ ClassNameResolver name_resolver;
+ return name_resolver.GetClassName(descriptor, true);
+}
+
+string ClassName(const ServiceDescriptor* descriptor) {
+ ClassNameResolver name_resolver;
+ return name_resolver.GetClassName(descriptor, true);
+}
+
string ClassName(const FileDescriptor* descriptor) {
- string result = FileJavaPackage(descriptor);
- if (!result.empty()) result += '.';
- result += FileClassName(descriptor);
- return result;
+ ClassNameResolver name_resolver;
+ return name_resolver.GetClassName(descriptor, true);
+}
+
+string ExtraMessageInterfaces(const Descriptor* descriptor) {
+ string interfaces = "// @@protoc_insertion_point(message_implements:"
+ + descriptor->full_name() + ")";
+ return interfaces;
+}
+
+
+string ExtraBuilderInterfaces(const Descriptor* descriptor) {
+ string interfaces = "// @@protoc_insertion_point(builder_implements:"
+ + descriptor->full_name() + ")";
+ return interfaces;
+}
+
+string ExtraMessageOrBuilderInterfaces(const Descriptor* descriptor) {
+ string interfaces = "// @@protoc_insertion_point(interface_extends:"
+ + descriptor->full_name() + ")";
+ return interfaces;
}
string FieldConstantName(const FieldDescriptor *field) {
@@ -240,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";
@@ -260,6 +346,35 @@ const char* BoxedPrimitiveTypeName(JavaType type) {
return NULL;
}
+const char* FieldTypeName(FieldDescriptor::Type field_type) {
+ switch (field_type) {
+ case FieldDescriptor::TYPE_INT32 : return "INT32";
+ case FieldDescriptor::TYPE_UINT32 : return "UINT32";
+ case FieldDescriptor::TYPE_SINT32 : return "SINT32";
+ case FieldDescriptor::TYPE_FIXED32 : return "FIXED32";
+ case FieldDescriptor::TYPE_SFIXED32: return "SFIXED32";
+ case FieldDescriptor::TYPE_INT64 : return "INT64";
+ case FieldDescriptor::TYPE_UINT64 : return "UINT64";
+ case FieldDescriptor::TYPE_SINT64 : return "SINT64";
+ case FieldDescriptor::TYPE_FIXED64 : return "FIXED64";
+ case FieldDescriptor::TYPE_SFIXED64: return "SFIXED64";
+ case FieldDescriptor::TYPE_FLOAT : return "FLOAT";
+ case FieldDescriptor::TYPE_DOUBLE : return "DOUBLE";
+ case FieldDescriptor::TYPE_BOOL : return "BOOL";
+ case FieldDescriptor::TYPE_STRING : return "STRING";
+ case FieldDescriptor::TYPE_BYTES : return "BYTES";
+ case FieldDescriptor::TYPE_ENUM : return "ENUM";
+ case FieldDescriptor::TYPE_GROUP : return "GROUP";
+ case FieldDescriptor::TYPE_MESSAGE : return "MESSAGE";
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
bool AllAscii(const string& text) {
for (int i = 0; i < text.size(); i++) {
if ((text[i] & 0x80) != 0) {
@@ -269,7 +384,8 @@ bool AllAscii(const string& text) {
return true;
}
-string DefaultValue(const FieldDescriptor* field) {
+string DefaultValue(const FieldDescriptor* field, bool immutable,
+ ClassNameResolver* name_resolver) {
// Switch on CppType since we need to know which default_value_* method
// of FieldDescriptor to call.
switch (field->cpp_type()) {
@@ -326,17 +442,18 @@ string DefaultValue(const FieldDescriptor* field) {
} else {
// See comments in Internal.java for gory details.
return strings::Substitute(
- "com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
- CEscape(field->default_value_string()));
+ "com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
+ CEscape(field->default_value_string()));
}
}
case FieldDescriptor::CPPTYPE_ENUM:
- return ClassName(field->enum_type()) + "." +
- field->default_value_enum()->name();
+ return name_resolver->GetClassName(field->enum_type(), immutable) + "." +
+ field->default_value_enum()->name();
case FieldDescriptor::CPPTYPE_MESSAGE:
- return ClassName(field->message_type()) + ".getDefaultInstance()";
+ return name_resolver->GetClassName(field->message_type(), immutable) +
+ ".getDefaultInstance()";
// No default because we want the compiler to complain if any new
// types are added.
@@ -427,8 +544,10 @@ string GetBitFieldNameForBit(int bitIndex) {
return GetBitFieldName(bitIndex / 32);
}
-string GenerateGetBit(int bitIndex) {
- string varName = GetBitFieldNameForBit(bitIndex);
+namespace {
+
+string GenerateGetBitInternal(const string& prefix, int bitIndex) {
+ string varName = prefix + GetBitFieldNameForBit(bitIndex);
int bitInVarIndex = bitIndex % 32;
string mask = bit_masks[bitInVarIndex];
@@ -436,8 +555,8 @@ string GenerateGetBit(int bitIndex) {
return result;
}
-string GenerateSetBit(int bitIndex) {
- string varName = GetBitFieldNameForBit(bitIndex);
+string GenerateSetBitInternal(const string& prefix, int bitIndex) {
+ string varName = prefix + GetBitFieldNameForBit(bitIndex);
int bitInVarIndex = bitIndex % 32;
string mask = bit_masks[bitInVarIndex];
@@ -445,6 +564,16 @@ string GenerateSetBit(int bitIndex) {
return result;
}
+} // namespace
+
+string GenerateGetBit(int bitIndex) {
+ return GenerateGetBitInternal("", bitIndex);
+}
+
+string GenerateSetBit(int bitIndex) {
+ return GenerateSetBitInternal("", bitIndex);
+}
+
string GenerateClearBit(int bitIndex) {
string varName = GetBitFieldNameForBit(bitIndex);
int bitInVarIndex = bitIndex % 32;
@@ -455,21 +584,171 @@ string GenerateClearBit(int bitIndex) {
}
string GenerateGetBitFromLocal(int bitIndex) {
- string varName = "from_" + GetBitFieldNameForBit(bitIndex);
- int bitInVarIndex = bitIndex % 32;
-
- string mask = bit_masks[bitInVarIndex];
- string result = "((" + varName + " & " + mask + ") == " + mask + ")";
- return result;
+ return GenerateGetBitInternal("from_", bitIndex);
}
string GenerateSetBitToLocal(int bitIndex) {
- string varName = "to_" + GetBitFieldNameForBit(bitIndex);
- int bitInVarIndex = bitIndex % 32;
+ return GenerateSetBitInternal("to_", bitIndex);
+}
- string mask = bit_masks[bitInVarIndex];
- string result = varName + " |= " + mask;
- return result;
+string GenerateGetBitMutableLocal(int bitIndex) {
+ return GenerateGetBitInternal("mutable_", bitIndex);
+}
+
+string GenerateSetBitMutableLocal(int bitIndex) {
+ return GenerateSetBitInternal("mutable_", bitIndex);
+}
+
+bool IsReferenceType(JavaType type) {
+ switch (type) {
+ case JAVATYPE_INT : return false;
+ case JAVATYPE_LONG : return false;
+ case JAVATYPE_FLOAT : return false;
+ case JAVATYPE_DOUBLE : return false;
+ case JAVATYPE_BOOLEAN: return false;
+ case JAVATYPE_STRING : return true;
+ case JAVATYPE_BYTES : return true;
+ case JAVATYPE_ENUM : return true;
+ case JAVATYPE_MESSAGE: return true;
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return false;
+}
+
+const char* GetCapitalizedType(const FieldDescriptor* field, bool immutable) {
+ switch (GetType(field)) {
+ case FieldDescriptor::TYPE_INT32 : return "Int32";
+ case FieldDescriptor::TYPE_UINT32 : return "UInt32";
+ case FieldDescriptor::TYPE_SINT32 : return "SInt32";
+ case FieldDescriptor::TYPE_FIXED32 : return "Fixed32";
+ case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
+ case FieldDescriptor::TYPE_INT64 : return "Int64";
+ case FieldDescriptor::TYPE_UINT64 : return "UInt64";
+ case FieldDescriptor::TYPE_SINT64 : return "SInt64";
+ case FieldDescriptor::TYPE_FIXED64 : return "Fixed64";
+ case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
+ case FieldDescriptor::TYPE_FLOAT : return "Float";
+ case FieldDescriptor::TYPE_DOUBLE : return "Double";
+ case FieldDescriptor::TYPE_BOOL : return "Bool";
+ case FieldDescriptor::TYPE_STRING : return "String";
+ case FieldDescriptor::TYPE_BYTES : {
+ return "Bytes";
+ }
+ case FieldDescriptor::TYPE_ENUM : return "Enum";
+ case FieldDescriptor::TYPE_GROUP : return "Group";
+ case FieldDescriptor::TYPE_MESSAGE : return "Message";
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+// For encodings with fixed sizes, returns that size in bytes. Otherwise
+// returns -1.
+int FixedSize(FieldDescriptor::Type type) {
+ switch (type) {
+ case FieldDescriptor::TYPE_INT32 : return -1;
+ case FieldDescriptor::TYPE_INT64 : return -1;
+ case FieldDescriptor::TYPE_UINT32 : return -1;
+ case FieldDescriptor::TYPE_UINT64 : return -1;
+ case FieldDescriptor::TYPE_SINT32 : return -1;
+ case FieldDescriptor::TYPE_SINT64 : return -1;
+ case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
+ case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
+ case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
+ case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
+ case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize;
+ case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize;
+
+ case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
+ case FieldDescriptor::TYPE_ENUM : return -1;
+
+ case FieldDescriptor::TYPE_STRING : return -1;
+ case FieldDescriptor::TYPE_BYTES : return -1;
+ case FieldDescriptor::TYPE_GROUP : return -1;
+ case FieldDescriptor::TYPE_MESSAGE : return -1;
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return -1;
+}
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it. The caller should delete the returned array.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
+ const FieldDescriptor** fields =
+ new const FieldDescriptor*[descriptor->field_count()];
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ fields[i] = descriptor->field(i);
+ }
+ std::sort(fields, fields + descriptor->field_count(),
+ FieldOrderingByNumber());
+ return fields;
+}
+
+// Returns true if the message type has any required fields. If it doesn't,
+// we can optimize out calls to its isInitialized() method.
+//
+// already_seen is used to avoid checking the same type multiple times
+// (and also to protect against recursion).
+bool HasRequiredFields(
+ const Descriptor* type,
+ hash_set<const Descriptor*>* already_seen) {
+ if (already_seen->count(type) > 0) {
+ // The type is already in cache. This means that either:
+ // a. The type has no required fields.
+ // b. We are in the midst of checking if the type has required fields,
+ // somewhere up the stack. In this case, we know that if the type
+ // has any required fields, they'll be found when we return to it,
+ // and the whole call to HasRequiredFields() will return true.
+ // Therefore, we don't have to check if this type has required fields
+ // here.
+ return false;
+ }
+ already_seen->insert(type);
+
+ // If the type has extensions, an extension with message type could contain
+ // required fields, so we have to be conservative and assume such an
+ // extension exists.
+ if (type->extension_range_count() > 0) return true;
+
+ for (int i = 0; i < type->field_count(); i++) {
+ const FieldDescriptor* field = type->field(i);
+ if (field->is_required()) {
+ return true;
+ }
+ if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+ if (HasRequiredFields(field->message_type(), already_seen)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool HasRequiredFields(const Descriptor* type) {
+ hash_set<const Descriptor*> already_seen;
+ return HasRequiredFields(type, &already_seen);
+}
+
+bool HasRepeatedFields(const Descriptor* descriptor) {
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ const FieldDescriptor* field = descriptor->field(i);
+ if (field->is_repeated()) {
+ return true;
+ }
+ }
+ return false;
}
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 4ae07f15..62efbefa 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -49,6 +49,9 @@ namespace java {
extern const char kThickSeparator[];
extern const char kThinSeparator[];
+// Converts a name to camel-case. If cap_first_letter is true, capitalize the
+// first letter.
+string UnderscoresToCamelCase(const string& name, bool cap_first_letter);
// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
// "fooBarBaz" or "FooBarBaz", respectively.
string UnderscoresToCamelCase(const FieldDescriptor* field);
@@ -58,15 +61,22 @@ string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field);
// of lower-casing the first letter of the name.)
string UnderscoresToCamelCase(const MethodDescriptor* method);
+// Get an identifier that uniquely identifies this type within the file.
+// This is used to declare static variables related to this type at the
+// outermost file scope.
+string UniqueFileScopeIdentifier(const Descriptor* descriptor);
+
// Strips ".proto" or ".protodevel" from the end of a filename.
string StripProto(const string& filename);
-// Gets the unqualified class name for the file. Each .proto file becomes a
-// single Java class, with all its contents nested in that class.
-string FileClassName(const FileDescriptor* file);
+// Gets the unqualified class name for the file. For each .proto file, there
+// will be one Java class containing all the immutable messages and another
+// Java class containing all the mutable messages.
+// TODO(xiaofeng): remove the default value after updating client code.
+string FileClassName(const FileDescriptor* file, bool immutable = true);
// Returns the file's Java package name.
-string FileJavaPackage(const FileDescriptor* file);
+string FileJavaPackage(const FileDescriptor* file, bool immutable = true);
// Returns output directory for the given package name.
string JavaPackageToDir(string package_name);
@@ -74,23 +84,47 @@ string JavaPackageToDir(string package_name);
// Converts the given fully-qualified name in the proto namespace to its
// fully-qualified name in the Java namespace, given that it is in the given
// file.
-string ToJavaName(const string& full_name, const FileDescriptor* file);
+// TODO(xiaofeng): this method is deprecated and should be removed in the
+// future.
+string ToJavaName(const string& full_name,
+ const FileDescriptor* file);
+
+// TODO(xiaofeng): the following methods are kept for they are exposed
+// publicly in //google/protobuf/compiler/java/names.h. They return
+// immutable names only and should be removed after mutable API is
+// integrated into google3.
+string ClassName(const Descriptor* descriptor);
+string ClassName(const EnumDescriptor* descriptor);
+string ClassName(const ServiceDescriptor* descriptor);
+string ClassName(const FileDescriptor* descriptor);
-// These return the fully-qualified class name corresponding to the given
-// descriptor.
-inline string ClassName(const Descriptor* descriptor) {
- return ToJavaName(descriptor->full_name(), descriptor->file());
-}
-inline string ClassName(const EnumDescriptor* descriptor) {
- return ToJavaName(descriptor->full_name(), descriptor->file());
+// Comma-separate list of option-specified interfaces implemented by the
+// Message, to follow the "implements" declaration of the Message definition.
+string ExtraMessageInterfaces(const Descriptor* descriptor);
+// Comma-separate list of option-specified interfaces implemented by the
+// MutableMessage, to follow the "implements" declaration of the MutableMessage
+// definition.
+string ExtraMutableMessageInterfaces(const Descriptor* descriptor);
+// Comma-separate list of option-specified interfaces implemented by the
+// Builder, to follow the "implements" declaration of the Builder definition.
+string ExtraBuilderInterfaces(const Descriptor* descriptor);
+// Comma-separate list of option-specified interfaces extended by the
+// MessageOrBuilder, to follow the "extends" declaration of the
+// MessageOrBuilder definition.
+string ExtraMessageOrBuilderInterfaces(const Descriptor* descriptor);
+
+// Get the unqualified Java class name for mutable messages. i.e. without
+// package or outer classnames.
+inline string ShortMutableJavaClassName(const Descriptor* descriptor) {
+ return descriptor->name();
}
-inline string ClassName(const ServiceDescriptor* descriptor) {
- return ToJavaName(descriptor->full_name(), descriptor->file());
-}
-inline string ExtensionIdentifierName(const FieldDescriptor* descriptor) {
- return ToJavaName(descriptor->full_name(), descriptor->file());
+
+
+// Whether we should generate multiple java files for messages.
+inline bool MultipleJavaFiles(
+ const FileDescriptor* descriptor, bool immutable) {
+ return descriptor->options().java_multiple_files();
}
-string ClassName(const FileDescriptor* descriptor);
// Get the unqualified name that should be used for a field's field
// number constant.
@@ -98,7 +132,7 @@ string FieldConstantName(const FieldDescriptor *field);
// Returns the type of the FieldDescriptor.
// This does nothing interesting for the open source release, but is used for
-// hacks that improve compatability with version 1 protocol buffers at Google.
+// hacks that improve compatibility with version 1 protocol buffers at Google.
FieldDescriptor::Type GetType(const FieldDescriptor* field);
enum JavaType {
@@ -115,19 +149,26 @@ 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.
const char* BoxedPrimitiveTypeName(JavaType type);
-string DefaultValue(const FieldDescriptor* field);
-bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
-
-// Does this message class keep track of unknown fields?
-inline bool HasUnknownFields(const Descriptor* descriptor) {
- return descriptor->file()->options().optimize_for() !=
- FileOptions::LITE_RUNTIME;
+// Get the name of the java enum constant representing this type. E.g.,
+// "INT32" for FieldDescriptor::TYPE_INT32. The enum constant's full
+// name is "com.google.protobuf.WireFormat.FieldType.INT32".
+const char* FieldTypeName(const FieldDescriptor::Type field_type);
+
+class ClassNameResolver;
+string DefaultValue(const FieldDescriptor* field, bool immutable,
+ ClassNameResolver* name_resolver);
+inline string ImmutableDefaultValue(const FieldDescriptor* field,
+ ClassNameResolver* name_resolver) {
+ return DefaultValue(field, true, name_resolver);
}
+bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
// Does this message class have generated parsing, serialization, and other
// standard methods for which reflection-based fallback implementations exist?
@@ -168,6 +209,15 @@ inline bool HasGenericServices(const FileDescriptor *file) {
file->options().java_generic_services();
}
+inline bool IsLazy(const FieldDescriptor* descriptor) {
+ // Currently, the proto-lite version suports lazy field.
+ // TODO(niwasaki): Support lazy fields also for other proto runtimes.
+ if (descriptor->file()->options().optimize_for() !=
+ FileOptions::LITE_RUNTIME) {
+ return false;
+ }
+ return descriptor->options().lazy();
+}
// Methods for shared bitfields.
@@ -205,6 +255,85 @@ string GenerateGetBitFromLocal(int bitIndex);
// Example: "to_bitField1_ = (to_bitField1_ | 0x04)"
string GenerateSetBitToLocal(int bitIndex);
+// Does the same as GenerateGetBit but operates on the bit field on a local
+// variable. This is used by the parsing constructor to record if a repeated
+// field is mutable.
+// Example: "((mutable_bitField1_ & 0x04) == 0x04)"
+string GenerateGetBitMutableLocal(int bitIndex);
+
+// Does the same as GenerateSetBit but operates on the bit field on a local
+// variable. This is used by the parsing constructor to record if a repeated
+// field is mutable.
+// Example: "mutable_bitField1_ = (mutable_bitField1_ | 0x04)"
+string GenerateSetBitMutableLocal(int bitIndex);
+
+// Returns whether the JavaType is a reference type.
+bool IsReferenceType(JavaType type);
+
+// Returns the capitalized name for calling relative functions in
+// CodedInputStream
+const char* GetCapitalizedType(const FieldDescriptor* field, bool immutable);
+
+// For encodings with fixed sizes, returns that size in bytes. Otherwise
+// returns -1.
+int FixedSize(FieldDescriptor::Type type);
+
+// Comparators used to sort fields in MessageGenerator
+struct FieldOrderingByNumber {
+ inline bool operator()(const FieldDescriptor* a,
+ const FieldDescriptor* b) const {
+ return a->number() < b->number();
+ }
+};
+
+struct ExtensionRangeOrdering {
+ bool operator()(const Descriptor::ExtensionRange* a,
+ const Descriptor::ExtensionRange* b) const {
+ return a->start < b->start;
+ }
+};
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it. The caller should delete the returned array.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor);
+
+// Does this message class have any packed fields?
+inline bool HasPackedFields(const Descriptor* descriptor) {
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ if (descriptor->field(i)->is_packed()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Check a message type and its sub-message types recursively to see if any of
+// them has a required field. Return true if a required field is found.
+bool HasRequiredFields(const Descriptor* descriptor);
+
+// Whether a .proto file supports field presence test for non-message types.
+inline bool SupportFieldPresence(const FileDescriptor* descriptor) {
+ 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_lazy_message_field.cc b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
new file mode 100644
index 00000000..6e29a40b
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
@@ -0,0 +1,824 @@
+// 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: niwasaki@google.com (Naoki Iwasaki)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_lazy_message_field.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ImmutableLazyMessageFieldGenerator::
+ImmutableLazyMessageFieldGenerator(
+ const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableMessageFieldGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+}
+
+ImmutableLazyMessageFieldGenerator::~ImmutableLazyMessageFieldGenerator() {}
+
+void ImmutableLazyMessageFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private com.google.protobuf.LazyFieldLite $name$_ =\n"
+ " new com.google.protobuf.LazyFieldLite();\n");
+
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_message$;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return ($type$) $name$_.getValue($type$.getDefaultInstance());\n"
+ "}\n");
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+ " return $name$_;\n"
+ "}\n");
+ }
+}
+
+void ImmutableLazyMessageFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // When using nested-builders, the code initially works just like the
+ // non-nested builder case. It only creates a nested builder lazily on
+ // demand and then forever delegates to it after creation.
+
+ printer->Print(variables_,
+ "private com.google.protobuf.LazyFieldLite $name$_ =\n"
+ " new com.google.protobuf.LazyFieldLite();\n");
+
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ printer->Print(variables_,
+ // If this builder is non-null, it is used and the other fields are
+ // ignored.
+ "private com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
+ "\n");
+ }
+
+ // The comments above the methods below are based on a hypothetical
+ // field of type "Field" called "Field".
+
+ // boolean hasField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_builder$;\n"
+ "}\n");
+
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return ($type$) $name$_.getValue($type$.getDefaultInstance());\n"
+ "}\n");
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder set$capitalized_name$($type$ value)",
+
+ "if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ "}\n"
+ "$name$_.setValue(value);\n"
+ "$on_changed$\n",
+
+ NULL, // Lazy fields are supported only for lite-runtime.
+
+ "$set_has_field_bit_builder$;\n"
+ "return this;\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " $type$.Builder builderForValue)",
+
+ "$name$_.setValue(builderForValue.build());\n"
+ "$on_changed$\n",
+
+ NULL,
+
+ "$set_has_field_bit_builder$;\n"
+ "return this;\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder merge$capitalized_name$($type$ value)",
+
+ "if ($get_has_field_bit_builder$ &&\n"
+ " !$name$_.containsDefaultInstance()) {\n"
+ " $name$_.setValue(\n"
+ " $type$.newBuilder(\n"
+ " get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
+ "} else {\n"
+ " $name$_.setValue(value);\n"
+ "}\n"
+ "$on_changed$\n",
+
+ NULL,
+
+ "$set_has_field_bit_builder$;\n"
+ "return this;\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder clear$capitalized_name$()",
+
+ "$name$_.clear();\n"
+ "$on_changed$\n",
+
+ NULL,
+
+ "$clear_has_field_bit_builder$;\n"
+ "return this;\n");
+
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
+ " $set_has_field_bit_builder$;\n"
+ " $on_changed$\n"
+ " return get$capitalized_name$FieldBuilder().getBuilder();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+ " if ($name$Builder_ != null) {\n"
+ " return $name$Builder_.getMessageOrBuilder();\n"
+ " } else {\n"
+ " return $name$_;\n"
+ " }\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> \n"
+ " get$capitalized_name$FieldBuilder() {\n"
+ " if ($name$Builder_ == null) {\n"
+ " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder>(\n"
+ " $name$_,\n"
+ " getParentForChildren(),\n"
+ " isClean());\n"
+ " $name$_ = null;\n"
+ " }\n"
+ " return $name$Builder_;\n"
+ "}\n");
+ }
+}
+
+
+void ImmutableLazyMessageFieldGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.clear();\n");
+}
+
+void ImmutableLazyMessageFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.clear();\n");
+ printer->Print(variables_, "$clear_has_field_bit_builder$;\n");
+}
+
+void ImmutableLazyMessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " $name$_.merge(other.$name$_);\n"
+ " $set_has_field_bit_builder$;\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has_field_bit_from_local$) {\n"
+ " $set_has_field_bit_to_local$;\n"
+ "}\n");
+
+ printer->Print(variables_,
+ "result.$name$_.set(\n"
+ " $name$_);\n");
+}
+
+void ImmutableLazyMessageFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_.setByteString(input.readBytes(), extensionRegistry);\n");
+ printer->Print(variables_,
+ "$set_has_field_bit_message$;\n");
+}
+
+void ImmutableLazyMessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ // Do not de-serialize lazy fields.
+ printer->Print(variables_,
+ "if ($get_has_field_bit_message$) {\n"
+ " output.writeBytes($number$, $name$_.toByteString());\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has_field_bit_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeLazyFieldSize($number$, $name$_);\n"
+ "}\n");
+}
+
+// ===================================================================
+
+ImmutableLazyMessageOneofFieldGenerator::
+ImmutableLazyMessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableLazyMessageFieldGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+ variables_["lazy_type"] = "com.google.protobuf.LazyFieldLite";
+}
+
+ImmutableLazyMessageOneofFieldGenerator::
+~ImmutableLazyMessageOneofFieldGenerator() {}
+
+void ImmutableLazyMessageOneofFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($type$) (($lazy_type$) $oneof_name$_).getValue(\n"
+ " $type$.getDefaultInstance());\n"
+ " }\n"
+ " return $type$.getDefaultInstance();\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // boolean hasField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($type$) (($lazy_type$) $oneof_name$_).getValue(\n"
+ " $type$.getDefaultInstance());\n"
+ " }\n"
+ " return $type$.getDefaultInstance();\n"
+ "}\n");
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder set$capitalized_name$($type$ value)",
+
+ "if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ "}\n"
+ "if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ " $set_oneof_case_message$;\n"
+ "}\n"
+ "(($lazy_type$) $oneof_name$_).setValue(value);\n"
+ "$on_changed$\n",
+
+ NULL, // Lazy fields are supported only for lite-runtime.
+
+ "return this;\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " $type$.Builder builderForValue)",
+
+ "if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ " $set_oneof_case_message$;\n"
+ "}\n"
+ "(($lazy_type$) $oneof_name$_).setValue(builderForValue.build());\n"
+ "$on_changed$\n",
+
+ NULL,
+
+ "return this;\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder merge$capitalized_name$($type$ value)",
+
+ "if ($has_oneof_case_message$ &&\n"
+ " !(($lazy_type$) $oneof_name$_).containsDefaultInstance()) {\n"
+ " (($lazy_type$) $oneof_name$_).setValue(\n"
+ " $type$.newBuilder(\n"
+ " get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
+ "} else {\n"
+ " if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ " $set_oneof_case_message$;\n"
+ " }\n"
+ " (($lazy_type$) $oneof_name$_).setValue(value);\n"
+ "}\n"
+ "$on_changed$\n",
+
+ NULL,
+
+ "return this;\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder clear$capitalized_name$()",
+
+ "if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " $on_changed$\n"
+ "}\n",
+
+ NULL,
+
+ "return this;\n");
+}
+
+void ImmutableLazyMessageOneofFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ "}\n"
+ "(($lazy_type$) $oneof_name$_).merge(\n"
+ " ($lazy_type$) other.$oneof_name$_);\n"
+ "$set_oneof_case_message$;\n");
+}
+
+void ImmutableLazyMessageOneofFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n");
+ printer->Indent();
+
+ printer->Print(variables_,
+ "result.$oneof_name$_ = new $lazy_type$();\n"
+ "(($lazy_type$) result.$oneof_name$_).set(\n"
+ " (($lazy_type$) $oneof_name$_));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableLazyMessageOneofFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = new $lazy_type$();\n"
+ "}\n"
+ "(($lazy_type$) $oneof_name$_).setByteString(\n"
+ " input.readBytes(), extensionRegistry);\n"
+ "$set_oneof_case_message$;\n");
+}
+
+void ImmutableLazyMessageOneofFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ // Do not de-serialize lazy fields.
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.writeBytes(\n"
+ " $number$, (($lazy_type$) $oneof_name$_).toByteString());\n"
+ "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeLazyFieldSize($number$, ($lazy_type$) $oneof_name$_);\n"
+ "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableLazyMessageFieldGenerator::
+RepeatedImmutableLazyMessageFieldGenerator(
+ const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : RepeatedImmutableMessageFieldGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+}
+
+
+RepeatedImmutableLazyMessageFieldGenerator::
+~RepeatedImmutableLazyMessageFieldGenerator() {}
+
+void RepeatedImmutableLazyMessageFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private java.util.List<com.google.protobuf.LazyFieldLite> $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<$type$>\n"
+ " get$capitalized_name$List() {\n"
+ " java.util.List<$type$> list =\n"
+ " new java.util.ArrayList<$type$>($name$_.size());\n"
+ " for (com.google.protobuf.LazyFieldLite lf : $name$_) {\n"
+ " list.add(($type$) lf.getValue($type$.getDefaultInstance()));\n"
+ " }\n"
+ " return list;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<? extends $type$OrBuilder>\n"
+ " get$capitalized_name$OrBuilderList() {\n"
+ " return get$capitalized_name$List();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public int get$capitalized_name$Count() {\n"
+ " return $name$_.size();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+ " return ($type$)\n"
+ " $name$_.get(index).getValue($type$.getDefaultInstance());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+ " int index) {\n"
+ " return ($type$OrBuilder)\n"
+ " $name$_.get(index).getValue($type$.getDefaultInstance());\n"
+ "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // When using nested-builders, the code initially works just like the
+ // non-nested builder case. It only creates a nested builder lazily on
+ // demand and then forever delegates to it after creation.
+
+ printer->Print(variables_,
+ "private java.util.List<com.google.protobuf.LazyFieldLite> $name$_ =\n"
+ " java.util.Collections.emptyList();\n"
+
+ "private void ensure$capitalized_name$IsMutable() {\n"
+ " if (!$get_mutable_bit_builder$) {\n"
+ " $name$_ =\n"
+ " new java.util.ArrayList<com.google.protobuf.LazyFieldLite>(\n"
+ " $name$_);\n"
+ " $set_mutable_bit_builder$;\n"
+ " }\n"
+ "}\n"
+ "\n");
+
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ printer->Print(variables_,
+ // If this builder is non-null, it is used and the other fields are
+ // ignored.
+ "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
+ "\n");
+ }
+
+ // The comments above the methods below are based on a hypothetical
+ // repeated field of type "Field" called "RepeatedField".
+
+ // List<Field> getRepeatedFieldList()
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public java.util.List<$type$> get$capitalized_name$List()",
+
+ "java.util.List<$type$> list =\n"
+ " new java.util.ArrayList<$type$>($name$_.size());\n"
+ "for (com.google.protobuf.LazyFieldLite lf : $name$_) {\n"
+ " list.add(($type$) lf.getValue($type$.getDefaultInstance()));\n"
+ "}\n"
+ "return java.util.Collections.unmodifiableList(list);\n",
+
+ "return $name$Builder_.getMessageList();\n",
+
+ NULL);
+
+ // int getRepeatedFieldCount()
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public int get$capitalized_name$Count()",
+
+ "return $name$_.size();\n",
+ "return $name$Builder_.getCount();\n",
+
+ NULL);
+
+ // Field getRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public $type$ get$capitalized_name$(int index)",
+
+ "return ($type$) $name$_.get(index).getValue(\n"
+ " $type$.getDefaultInstance());\n",
+
+ "return $name$Builder_.getMessage(index);\n",
+
+ NULL);
+
+ // Builder setRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " int index, $type$ value)",
+ "if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ "}\n"
+ "ensure$capitalized_name$IsMutable();\n"
+ "$name$_.set(index, com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+ "$on_changed$\n",
+ "$name$Builder_.setMessage(index, value);\n",
+ "return this;\n");
+
+ // Builder setRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue)",
+
+ "ensure$capitalized_name$IsMutable();\n"
+ "$name$_.set(index, com.google.protobuf.LazyFieldLite.fromValue(\n"
+ " builderForValue.build()));\n"
+ "$on_changed$\n",
+
+ "$name$Builder_.setMessage(index, builderForValue.build());\n",
+
+ "return this;\n");
+
+ // Builder addRepeatedField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder add$capitalized_name$($type$ value)",
+
+ "if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ "}\n"
+ "ensure$capitalized_name$IsMutable();\n"
+ "$name$_.add(com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+
+ "$on_changed$\n",
+
+ "$name$Builder_.addMessage(value);\n",
+
+ "return this;\n");
+
+ // Builder addRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " int index, $type$ value)",
+
+ "if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ "}\n"
+ "ensure$capitalized_name$IsMutable();\n"
+ "$name$_.add(index, com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+ "$on_changed$\n",
+
+ "$name$Builder_.addMessage(index, value);\n",
+
+ "return this;\n");
+
+ // Builder addRepeatedField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " $type$.Builder builderForValue)",
+
+ "ensure$capitalized_name$IsMutable();\n"
+ "$name$_.add(com.google.protobuf.LazyFieldLite.fromValue(\n"
+ " builderForValue.build()));\n"
+ "$on_changed$\n",
+
+ "$name$Builder_.addMessage(builderForValue.build());\n",
+
+ "return this;\n");
+
+ // Builder addRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " int index, $type$.Builder builderForValue)",
+
+ "ensure$capitalized_name$IsMutable();\n"
+ "$name$_.add(index, com.google.protobuf.LazyFieldLite.fromValue(\n"
+ " builderForValue.build()));\n"
+ "$on_changed$\n",
+
+ "$name$Builder_.addMessage(index, builderForValue.build());\n",
+
+ "return this;\n");
+
+ // Builder addAllRepeatedField(Iterable<Field> values)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $type$> values)",
+
+ "ensure$capitalized_name$IsMutable();\n"
+ "for (com.google.protobuf.MessageLite v : values) {\n"
+ " $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(v));\n"
+ "}\n"
+ "$on_changed$\n",
+
+ "$name$Builder_.addAllMessages(values);\n",
+
+ "return this;\n");
+
+ // Builder clearAllRepeatedField()
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder clear$capitalized_name$()",
+
+ "$name$_ = java.util.Collections.emptyList();\n"
+ "$clear_mutable_bit_builder$;\n"
+ "$on_changed$\n",
+
+ "$name$Builder_.clear();\n",
+
+ "return this;\n");
+
+ // Builder removeRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder remove$capitalized_name$(int index)",
+
+ "ensure$capitalized_name$IsMutable();\n"
+ "$name$_.remove(index);\n"
+ "$on_changed$\n",
+
+ "$name$Builder_.remove(index);\n",
+
+ "return this;\n");
+
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
+ " int index) {\n"
+ " return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+ " int index) {\n"
+ " if ($name$Builder_ == null) {\n"
+ " return $name$_.get(index);"
+ " } else {\n"
+ " return $name$Builder_.getMessageOrBuilder(index);\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+ " get$capitalized_name$OrBuilderList() {\n"
+ " if ($name$Builder_ != null) {\n"
+ " return $name$Builder_.getMessageOrBuilderList();\n"
+ " } else {\n"
+ " return java.util.Collections.unmodifiableList($name$_);\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
+ " return get$capitalized_name$FieldBuilder().addBuilder(\n"
+ " $type$.getDefaultInstance());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
+ " int index) {\n"
+ " return get$capitalized_name$FieldBuilder().addBuilder(\n"
+ " index, $type$.getDefaultInstance());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.util.List<$type$.Builder> \n"
+ " get$capitalized_name$BuilderList() {\n"
+ " return get$capitalized_name$FieldBuilder().getBuilderList();\n"
+ "}\n"
+ "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> \n"
+ " get$capitalized_name$FieldBuilder() {\n"
+ " if ($name$Builder_ == null) {\n"
+ " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder>(\n"
+ " $name$_,\n"
+ " $get_mutable_bit_builder$,\n"
+ " getParentForChildren(),\n"
+ " isClean());\n"
+ " $name$_ = null;\n"
+ " }\n"
+ " return $name$Builder_;\n"
+ "}\n");
+ }
+}
+
+void RepeatedImmutableLazyMessageFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ =\n"
+ " new java.util.ArrayList<com.google.protobuf.LazyFieldLite>();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n"
+ "$name$_.add(new com.google.protobuf.LazyFieldLite(\n"
+ " extensionRegistry, input.readBytes()));\n");
+}
+
+void RepeatedImmutableLazyMessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.writeBytes($number$, $name$_.get(i).toByteString());\n"
+ "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeLazyFieldSize($number$, $name$_.get(i));\n"
+ "}\n");
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field.h b/src/google/protobuf/compiler/java/java_lazy_message_field.h
new file mode 100644
index 00000000..b1b7f282
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field.h
@@ -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.
+
+// Author: niwasaki@google.com (Naoki Iwasaki)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_H__
+
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_message_field.h>
+
+namespace google {
+namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ }
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableLazyMessageFieldGenerator
+ : public ImmutableMessageFieldGenerator {
+ public:
+ explicit ImmutableLazyMessageFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableLazyMessageFieldGenerator();
+
+ // overroads ImmutableMessageFieldGenerator ---------------------------------
+ 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 GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageFieldGenerator);
+};
+
+class ImmutableLazyMessageOneofFieldGenerator
+ : public ImmutableLazyMessageFieldGenerator {
+ public:
+ ImmutableLazyMessageOneofFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableLazyMessageOneofFieldGenerator();
+
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageOneofFieldGenerator);
+};
+
+class RepeatedImmutableLazyMessageFieldGenerator
+ : public RepeatedImmutableMessageFieldGenerator {
+ public:
+ explicit RepeatedImmutableLazyMessageFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~RepeatedImmutableLazyMessageFieldGenerator();
+
+ // overroads RepeatedImmutableMessageFieldGenerator -------------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableLazyMessageFieldGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_H__
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..cf1ef589
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -0,0 +1,484 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/java/java_map_field.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+ const Descriptor* message = descriptor->message_type();
+ GOOGLE_CHECK(message->options().map_entry());
+ return message->FindFieldByName("key");
+}
+
+const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+ const Descriptor* message = descriptor->message_type();
+ GOOGLE_CHECK(message->options().map_entry());
+ return message->FindFieldByName("value");
+}
+
+string TypeName(const FieldDescriptor* field,
+ ClassNameResolver* name_resolver,
+ bool boxed) {
+ if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+ return name_resolver->GetImmutableClassName(field->message_type());
+ } else if (GetJavaType(field) == JAVATYPE_ENUM) {
+ return name_resolver->GetImmutableClassName(field->enum_type());
+ } else {
+ return boxed ? BoxedPrimitiveTypeName(GetJavaType(field))
+ : PrimitiveTypeName(GetJavaType(field));
+ }
+}
+
+string WireType(const FieldDescriptor* field) {
+ return "com.google.protobuf.WireFormat.FieldType." +
+ string(FieldTypeName(field->type()));
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
+ map<string, string>* variables) {
+ SetCommonFieldVariables(descriptor, info, variables);
+
+ (*variables)["type"] =
+ name_resolver->GetImmutableClassName(descriptor->message_type());
+ const FieldDescriptor* key = KeyField(descriptor);
+ const FieldDescriptor* value = ValueField(descriptor);
+ (*variables)["key_type"] = TypeName(key, name_resolver, false);
+ (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
+ (*variables)["key_wire_type"] = WireType(key);
+ (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
+ if (GetJavaType(value) == JAVATYPE_ENUM) {
+ // We store enums as Integers internally.
+ (*variables)["value_type"] = "int";
+ (*variables)["boxed_value_type"] = "java.lang.Integer";
+ (*variables)["value_wire_type"] = WireType(value);
+ (*variables)["value_default_value"] =
+ DefaultValue(value, true, name_resolver) + ".getNumber()";
+
+ (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
+
+ if (SupportUnknownEnumValue(descriptor->file())) {
+ // Map unknown values to a special UNRECOGNIZED value if supported.
+ (*variables)["unrecognized_value"] =
+ (*variables)["value_enum_type"] + ".UNRECOGNIZED";
+ } else {
+ // Map unknown values to the default value if we don't have UNRECOGNIZED.
+ (*variables)["unrecognized_value"] =
+ DefaultValue(value, true, name_resolver);
+ }
+ } else {
+ (*variables)["value_type"] = TypeName(value, name_resolver, false);
+ (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
+ (*variables)["value_wire_type"] = WireType(value);
+ (*variables)["value_default_value"] =
+ DefaultValue(value, true, name_resolver);
+ }
+ (*variables)["type_parameters"] =
+ (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
+ // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+ // by the proto compiler
+ (*variables)["deprecation"] = descriptor->options().deprecated()
+ ? "@java.lang.Deprecated " : "";
+ (*variables)["on_changed"] =
+ HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+ // For repeated fields, one bit is used for whether the array is immutable
+ // in the parsing constructor.
+ (*variables)["get_mutable_bit_parser"] =
+ GenerateGetBitMutableLocal(builderBitIndex);
+ (*variables)["set_mutable_bit_parser"] =
+ GenerateSetBitMutableLocal(builderBitIndex);
+
+ if (HasDescriptorMethods(descriptor->file())) {
+ (*variables)["lite"] = "";
+ (*variables)["map_field_parameter"] = (*variables)["name"] + "DefaultEntry";
+ (*variables)["descriptor"] =
+ name_resolver->GetImmutableClassName(descriptor->file()) +
+ ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
+ "_descriptor, ";
+ } else {
+ (*variables)["lite"] = "Lite";
+ (*variables)["map_field_parameter"] = "";
+ (*variables)["descriptor"] = "";
+ }
+}
+
+} // namespace
+
+ImmutableMapFieldGenerator::
+ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
+}
+
+ImmutableMapFieldGenerator::
+~ImmutableMapFieldGenerator() {}
+
+int ImmutableMapFieldGenerator::GetNumBitsForMessage() const {
+ return 0;
+}
+
+int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const {
+ return 1;
+}
+
+void ImmutableMapFieldGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+ if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$();\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$java.util.Map<$type_parameters$>\n"
+ "get$capitalized_name$Value();\n");
+ }
+ } else {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$java.util.Map<$type_parameters$>\n"
+ "get$capitalized_name$();\n");
+ }
+}
+
+void ImmutableMapFieldGenerator::
+GenerateStaticInitializationCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "$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"
+ "\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");
+ printer->Print(
+ variables_,
+ "private com.google.protobuf.MapField$lite$<\n"
+ " $type_parameters$> $name$_;\n"
+ "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "internalGet$capitalized_name$() {\n"
+ " if ($name$_ == null) {\n"
+ " return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+ " $map_field_parameter$);\n"
+ " }\n"
+ " return $name$_;\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 internalGet$capitalized_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"
+ " internalGet$capitalized_name$().getMap(),\n"
+ " $name$ValueConverter);\n"
+ "}\n");
+ } else {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+ " return internalGet$capitalized_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"
+ "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "internalGet$capitalized_name$() {\n"
+ " if ($name$_ == null) {\n"
+ " return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+ " $map_field_parameter$);\n"
+ " }\n"
+ " return $name$_;\n"
+ "}\n"
+ "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "internalGetMutable$capitalized_name$() {\n"
+ " $on_changed$;\n"
+ " if ($name$_ == null) {\n"
+ " $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
+ " $map_field_parameter$);\n"
+ " }\n"
+ " return $name$_;\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"
+ " internalGet$capitalized_name$().getMap(),\n"
+ " $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"
+ " return new com.google.protobuf.Internal.MapAdapter<\n"
+ " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+ " internalGetMutable$capitalized_name$().getMutableMap(),\n"
+ " $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 internalGet$capitalized_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"
+ " return internalGetMutable$capitalized_name$().getMutableMap();\n"
+ "}\n");
+ }
+ } else {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+ " return internalGet$capitalized_name$().getMap();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "public java.util.Map<$type_parameters$>\n"
+ "getMutable$capitalized_name$() {\n"
+ " return internalGetMutable$capitalized_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_,
+ "internalGetMutable$capitalized_name$().clear();\n");
+}
+
+void ImmutableMapFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "internalGetMutable$capitalized_name$().mergeFrom(\n"
+ " other.internalGet$capitalized_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$_ = internalGet$capitalized_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"
+ " : internalGet$capitalized_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"
+ " : internalGet$capitalized_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 && internalGet$capitalized_name$().equals(\n"
+ " other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldGenerator::
+GenerateHashCode(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
+ " hash = (37 * hash) + $constant_name$;\n"
+ " hash = (53 * hash) + internalGet$capitalized_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..3e6dd973
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field.h
@@ -0,0 +1,83 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__
+
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
+ public:
+ explicit ImmutableMapFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableMapFieldGenerator();
+
+ // implements ImmutableFieldGenerator ---------------------------------------
+ int GetNumBitsForMessage() const;
+ int GetNumBitsForBuilder() const;
+ void GenerateInterfaceMembers(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateInitializationCode(io::Printer* printer) const;
+ void GenerateBuilderClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateParsingDoneCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+ void GenerateStaticInitializationCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ const int messageBitIndex_;
+ const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 4c087db5..e982a17b 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,17 +32,30 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/compiler/java/java_message.h>
+
#include <algorithm>
#include <google/protobuf/stubs/hash.h>
-#include <google/protobuf/compiler/java/java_message.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_enum.h>
#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_generator_factory.h>
#include <google/protobuf/compiler/java/java_helpers.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/io/printer.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/wire_format.h>
+#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
namespace google {
namespace protobuf {
@@ -53,107 +66,38 @@ using internal::WireFormat;
using internal::WireFormatLite;
namespace {
-
-void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
- // Print the field's proto-syntax definition as a comment. We don't want to
- // print group bodies so we cut off after the first line.
- string def = field->DebugString();
- printer->Print("// $def$\n",
- "def", def.substr(0, def.find_first_of('\n')));
+bool GenerateHasBits(const Descriptor* descriptor) {
+ return SupportFieldPresence(descriptor->file()) ||
+ HasRepeatedFields(descriptor);
}
-struct FieldOrderingByNumber {
- inline bool operator()(const FieldDescriptor* a,
- const FieldDescriptor* b) const {
- return a->number() < b->number();
- }
-};
-
-struct ExtensionRangeOrdering {
- bool operator()(const Descriptor::ExtensionRange* a,
- const Descriptor::ExtensionRange* b) const {
- return a->start < b->start;
- }
-};
-
-// Sort the fields of the given Descriptor by number into a new[]'d array
-// and return it.
-const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
- const FieldDescriptor** fields =
- new const FieldDescriptor*[descriptor->field_count()];
- for (int i = 0; i < descriptor->field_count(); i++) {
- fields[i] = descriptor->field(i);
- }
- sort(fields, fields + descriptor->field_count(),
- FieldOrderingByNumber());
- return fields;
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+ ClassNameResolver* name_resolver) {
+ const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+ GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+ return name_resolver->GetImmutableClassName(value_field->message_type());
}
-
-// Get an identifier that uniquely identifies this type within the file.
-// This is used to declare static variables related to this type at the
-// outermost file scope.
-string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
- return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
-}
-
-// Returns true if the message type has any required fields. If it doesn't,
-// we can optimize out calls to its isInitialized() method.
-//
-// already_seen is used to avoid checking the same type multiple times
-// (and also to protect against recursion).
-static bool HasRequiredFields(
- const Descriptor* type,
- hash_set<const Descriptor*>* already_seen) {
- if (already_seen->count(type) > 0) {
- // The type is already in cache. This means that either:
- // a. The type has no required fields.
- // b. We are in the midst of checking if the type has required fields,
- // somewhere up the stack. In this case, we know that if the type
- // has any required fields, they'll be found when we return to it,
- // and the whole call to HasRequiredFields() will return true.
- // Therefore, we don't have to check if this type has required fields
- // here.
- return false;
- }
- already_seen->insert(type);
-
- // If the type has extensions, an extension with message type could contain
- // required fields, so we have to be conservative and assume such an
- // extension exists.
- if (type->extension_range_count() > 0) return true;
-
- for (int i = 0; i < type->field_count(); i++) {
- const FieldDescriptor* field = type->field(i);
- if (field->is_required()) {
- return true;
- }
- if (GetJavaType(field) == JAVATYPE_MESSAGE) {
- if (HasRequiredFields(field->message_type(), already_seen)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static bool HasRequiredFields(const Descriptor* type) {
- hash_set<const Descriptor*> already_seen;
- return HasRequiredFields(type, &already_seen);
-}
-
} // namespace
// ===================================================================
MessageGenerator::MessageGenerator(const Descriptor* descriptor)
- : descriptor_(descriptor),
- field_generators_(descriptor) {
-}
+ : descriptor_(descriptor) {}
MessageGenerator::~MessageGenerator() {}
-void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
+// ===================================================================
+// TODO(api): Move this class to a separate immutable_message.cc file.
+ImmutableMessageGenerator::ImmutableMessageGenerator(
+ const Descriptor* descriptor, Context* context)
+ : MessageGenerator(descriptor), context_(context),
+ name_resolver_(context->GetNameResolver()),
+ field_generators_(descriptor, context_) {
+}
+
+ImmutableMessageGenerator::~ImmutableMessageGenerator() {}
+
+void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) {
if (HasDescriptorMethods(descriptor_)) {
// Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
// used in the construction of descriptors, we have a tricky bootstrapping
@@ -165,12 +109,12 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
map<string, string> vars;
vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
vars["index"] = SimpleItoa(descriptor_->index());
- vars["classname"] = ClassName(descriptor_);
+ vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
if (descriptor_->containing_type() != NULL) {
vars["parent"] = UniqueFileScopeIdentifier(
descriptor_->containing_type());
}
- if (descriptor_->file()->options().java_multiple_files()) {
+ if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
// We can only make these package-private since the classes that use them
// are in separate files.
vars["private"] = "";
@@ -180,31 +124,28 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
// The descriptor for this type.
printer->Print(vars,
- "$private$static com.google.protobuf.Descriptors.Descriptor\n"
+ "$private$static final com.google.protobuf.Descriptors.Descriptor\n"
" internal_$identifier$_descriptor;\n");
// And the FieldAccessorTable.
- printer->Print(vars,
- "$private$static\n"
- " com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
- " internal_$identifier$_fieldAccessorTable;\n");
+ GenerateFieldAccessorTable(printer);
}
// Generate static members for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
- MessageGenerator(descriptor_->nested_type(i))
+ ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
.GenerateStaticVariables(printer);
}
}
-void MessageGenerator::GenerateStaticVariableInitializers(
+void ImmutableMessageGenerator::GenerateStaticVariableInitializers(
io::Printer* printer) {
if (HasDescriptorMethods(descriptor_)) {
map<string, string> vars;
vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
vars["index"] = SimpleItoa(descriptor_->index());
- vars["classname"] = ClassName(descriptor_);
+ vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
if (descriptor_->containing_type() != NULL) {
vars["parent"] = UniqueFileScopeIdentifier(
descriptor_->containing_type());
@@ -222,59 +163,96 @@ void MessageGenerator::GenerateStaticVariableInitializers(
}
// And the FieldAccessorTable.
- printer->Print(vars,
- "internal_$identifier$_fieldAccessorTable = new\n"
- " com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
- " internal_$identifier$_descriptor,\n"
- " new java.lang.String[] { ");
- for (int i = 0; i < descriptor_->field_count(); i++) {
- printer->Print(
- "\"$field_name$\", ",
- "field_name",
- UnderscoresToCapitalizedCamelCase(descriptor_->field(i)));
- }
- printer->Print("},\n"
- " $classname$.class,\n"
- " $classname$.Builder.class);\n",
- "classname", ClassName(descriptor_));
+ GenerateFieldAccessorTableInitializer(printer);
}
// Generate static member initializers for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
- MessageGenerator(descriptor_->nested_type(i))
+ ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
.GenerateStaticVariableInitializers(printer);
}
}
-// ===================================================================
+void ImmutableMessageGenerator::
+GenerateFieldAccessorTable(io::Printer* printer) {
+ map<string, string> vars;
+ vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+ if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
+ // We can only make these package-private since the classes that use them
+ // are in separate files.
+ vars["private"] = "";
+ } else {
+ vars["private"] = "private ";
+ }
+ printer->Print(vars,
+ "$private$static\n"
+ " com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+ " internal_$identifier$_fieldAccessorTable;\n");
+}
+
+void ImmutableMessageGenerator::
+GenerateFieldAccessorTableInitializer(io::Printer* printer) {
+ printer->Print(
+ "internal_$identifier$_fieldAccessorTable = new\n"
+ " com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
+ " internal_$identifier$_descriptor,\n"
+ " new java.lang.String[] { ",
+ "identifier",
+ UniqueFileScopeIdentifier(descriptor_));
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ printer->Print(
+ "\"$field_name$\", ",
+ "field_name", info->capitalized_name);
+ }
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+ const OneofGeneratorInfo* info = context_->GetOneofGeneratorInfo(oneof);
+ printer->Print(
+ "\"$oneof_name$\", ",
+ "oneof_name", info->capitalized_name);
+ }
+ printer->Print("});\n");
+}
-void MessageGenerator::GenerateInterface(io::Printer* printer) {
+// ===================================================================
+void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) {
if (descriptor_->extension_range_count() > 0) {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public interface $classname$OrBuilder extends\n"
+ " $extra_interfaces$\n"
" com.google.protobuf.GeneratedMessage.\n"
" ExtendableMessageOrBuilder<$classname$> {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
"classname", descriptor_->name());
} else {
printer->Print(
"public interface $classname$OrBuilder extends \n"
+ " $extra_interfaces$\n"
" com.google.protobuf.GeneratedMessageLite.\n"
- " ExtendableMessageOrBuilder<$classname$> {\n",
+ " ExtendableMessageOrBuilder<\n"
+ " $classname$, $classname$.Builder> {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
"classname", descriptor_->name());
}
} else {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
- "public interface $classname$OrBuilder\n"
- " extends com.google.protobuf.MessageOrBuilder {\n",
+ "public interface $classname$OrBuilder extends\n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.MessageOrBuilder {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
"classname", descriptor_->name());
} else {
printer->Print(
- "public interface $classname$OrBuilder\n"
- " extends com.google.protobuf.MessageLiteOrBuilder {\n",
+ "public interface $classname$OrBuilder extends\n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.MessageLiteOrBuilder {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
"classname", descriptor_->name());
}
}
@@ -282,7 +260,6 @@ void MessageGenerator::GenerateInterface(io::Printer* printer) {
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
printer->Print("\n");
- PrintFieldComment(printer, descriptor_->field(i));
field_generators_.get(descriptor_->field(i))
.GenerateInterfaceMembers(printer);
}
@@ -293,93 +270,208 @@ void MessageGenerator::GenerateInterface(io::Printer* printer) {
// ===================================================================
-void MessageGenerator::Generate(io::Printer* printer) {
+void ImmutableMessageGenerator::Generate(io::Printer* printer) {
bool is_own_file =
descriptor_->containing_type() == NULL &&
- descriptor_->file()->options().java_multiple_files();
+ MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+ map<string, string> variables;
+ variables["static"] = is_own_file ? " " : " static ";
+ variables["classname"] = descriptor_->name();
+ variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
+ variables["lite"] = HasDescriptorMethods(descriptor_) ? "" : "Lite";
+
+ WriteMessageDocComment(printer, descriptor_);
+
+ // The builder_type stores the super type name of the nested Builder class.
+ string builder_type;
if (descriptor_->extension_range_count() > 0) {
if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public $static$ final class $classname$ extends\n"
+ printer->Print(variables,
+ "public $static$final class $classname$ extends\n"
" com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
- " $classname$> implements $classname$OrBuilder {\n",
- "static", is_own_file ? "" : "static",
- "classname", descriptor_->name());
+ " $classname$> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n");
} else {
- printer->Print(
- "public $static$ final class $classname$ extends\n"
+ printer->Print(variables,
+ "public $static$final class $classname$ extends\n"
" com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
- " $classname$> implements $classname$OrBuilder {\n",
- "static", is_own_file ? "" : "static",
- "classname", descriptor_->name());
+ " $classname$, $classname$.Builder> 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(variables,
+ "public $static$final class $classname$ extends\n"
+ " com.google.protobuf.GeneratedMessage implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n");
+ } else {
+ printer->Print(variables,
+ "public $static$final class $classname$ extends\n"
+ " com.google.protobuf.GeneratedMessageLite<\n"
+ " $classname$, $classname$.Builder> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n");
+ }
+
+ builder_type = strings::Substitute(
+ "com.google.protobuf.GeneratedMessage$0.Builder",
+ variables["lite"]);
+ }
+ printer->Indent();
+ if (HasDescriptorMethods(descriptor_)) {
+ // Using builder_type, instead of Builder, prevents the Builder class from
+ // being loaded into PermGen space when the default instance is created.
+ // This optimizes the PermGen space usage for clients that do not modify
+ // messages.
+ printer->Print(
+ "// Use $classname$.newBuilder() to construct.\n"
+ "private $classname$($buildertype$ builder) {\n"
+ " super(builder);\n"
+ "}\n",
+ "classname", descriptor_->name(),
+ "buildertype", builder_type);
+ printer->Print(
+ "private $classname$() {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+ GenerateInitializers(printer);
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+ }
+
+ if (HasDescriptorMethods(descriptor_)) {
+ printer->Print(
+ "@java.lang.Override\n"
+ "public final com.google.protobuf.UnknownFieldSet\n"
+ "getUnknownFields() {\n");
+ if (PreserveUnknownFields(descriptor_)) {
printer->Print(
- "public $static$ final class $classname$ extends\n"
- " com.google.protobuf.GeneratedMessage\n"
- " implements $classname$OrBuilder {\n",
- "static", is_own_file ? "" : "static",
- "classname", descriptor_->name());
+ " return this.unknownFields;\n");
} else {
printer->Print(
- "public $static$ final class $classname$ extends\n"
- " com.google.protobuf.GeneratedMessageLite\n"
- " implements $classname$OrBuilder {\n",
- "static", is_own_file ? "" : "static",
- "classname", descriptor_->name());
+ " return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n");
}
+ printer->Print(
+ "}\n");
}
- printer->Indent();
- printer->Print(
- "// Use $classname$.newBuilder() to construct.\n"
- "private $classname$(Builder builder) {\n"
- " super(builder);\n"
- "}\n"
- // Used when constructing the default instance, which cannot be initialized
- // immediately because it may cyclically refer to other default instances.
- "private $classname$(boolean noInit) {}\n"
- "\n"
- "private static final $classname$ defaultInstance;\n"
- "public static $classname$ getDefaultInstance() {\n"
- " return defaultInstance;\n"
- "}\n"
- "\n"
- "public $classname$ getDefaultInstanceForType() {\n"
- " return defaultInstance;\n"
- "}\n"
- "\n",
- "classname", descriptor_->name());
- GenerateDescriptorMethods(printer);
+ if (HasGeneratedMethods(descriptor_)) {
+ GenerateParsingConstructor(printer);
+ }
+
+ GenerateDescriptorMethods(printer, false);
+ GenerateParser(printer);
// Nested types
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
- EnumGenerator(descriptor_->enum_type(i)).Generate(printer);
+ EnumGenerator(descriptor_->enum_type(i), true, context_)
+ .Generate(printer);
}
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
- MessageGenerator messageGenerator(descriptor_->nested_type(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);
messageGenerator.Generate(printer);
}
- // Integers for bit fields.
- int totalBits = 0;
- for (int i = 0; i < descriptor_->field_count(); i++) {
- totalBits += field_generators_.get(descriptor_->field(i))
- .GetNumBitsForMessage();
+ if (GenerateHasBits(descriptor_)) {
+ // Integers for bit fields.
+ int totalBits = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ totalBits += field_generators_.get(descriptor_->field(i))
+ .GetNumBitsForMessage();
+ }
+ int totalInts = (totalBits + 31) / 32;
+ for (int i = 0; i < totalInts; i++) {
+ printer->Print("private int $bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
}
- int totalInts = (totalBits + 31) / 32;
- for (int i = 0; i < totalInts; i++) {
- printer->Print("private int $bit_field_name$;\n",
- "bit_field_name", GetBitFieldName(i));
+
+ // oneof
+ map<string, string> vars;
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name;
+ vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->capitalized_name;
+ vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+ // oneofCase_ and oneof_
+ printer->Print(vars,
+ "private int $oneof_name$Case_ = 0;\n"
+ "private java.lang.Object $oneof_name$_;\n");
+ // OneofCase enum
+ printer->Print(vars,
+ "public enum $oneof_capitalized_name$Case\n"
+ " implements com.google.protobuf.Internal.EnumLite {\n");
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ "$field_name$($field_number$),\n",
+ "field_name",
+ ToUpper(field->name()),
+ "field_number",
+ SimpleItoa(field->number()));
+ }
+ printer->Print(
+ "$cap_oneof_name$_NOT_SET(0);\n",
+ "cap_oneof_name",
+ ToUpper(vars["oneof_name"]));
+ printer->Print(vars,
+ "private int value = 0;\n"
+ "private $oneof_capitalized_name$Case(int value) {\n"
+ " this.value = value;\n"
+ "}\n");
+ printer->Print(vars,
+ "public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+ " switch (value) {\n");
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ " case $field_number$: return $field_name$;\n",
+ "field_number",
+ SimpleItoa(field->number()),
+ "field_name",
+ ToUpper(field->name()));
+ }
+ printer->Print(
+ " case 0: return $cap_oneof_name$_NOT_SET;\n"
+ " default: throw new java.lang.IllegalArgumentException(\n"
+ " \"Value is undefined for this oneof enum.\");\n"
+ " }\n"
+ "}\n"
+ "public int getNumber() {\n"
+ " return this.value;\n"
+ "}\n",
+ "cap_oneof_name", ToUpper(vars["oneof_name"]));
+ printer->Outdent();
+ printer->Print("};\n\n");
+ // oneofCase()
+ printer->Print(vars,
+ "public $oneof_capitalized_name$Case\n"
+ "get$oneof_capitalized_name$Case() {\n"
+ " return $oneof_capitalized_name$Case.valueOf(\n"
+ " $oneof_name$Case_);\n"
+ "}\n"
+ "\n");
}
// Fields
for (int i = 0; i < descriptor_->field_count(); i++) {
- PrintFieldComment(printer, descriptor_->field(i));
printer->Print("public static final int $constant_name$ = $number$;\n",
"constant_name", FieldConstantName(descriptor_->field(i)),
"number", SimpleItoa(descriptor_->field(i)->number()));
@@ -387,17 +479,6 @@ void MessageGenerator::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++) {
- field_generators_.get(descriptor_->field(i))
- .GenerateInitializationCode(printer);
- }
- printer->Outdent();
- printer->Print("}\n");
-
if (HasGeneratedMethods(descriptor_)) {
GenerateIsInitialized(printer, MEMOIZE);
GenerateMessageSerializationMethods(printer);
@@ -407,29 +488,91 @@ void MessageGenerator::Generate(io::Printer* printer) {
GenerateEqualsAndHashCode(printer);
}
+
GenerateParseFromMethods(printer);
GenerateBuilder(printer);
- // Carefully initialize the default instance in such a way that it doesn't
- // conflict with other initialization.
printer->Print(
"\n"
- "static {\n"
- " defaultInstance = new $classname$(true);\n"
- " defaultInstance.initFields();\n"
- "}\n"
- "\n"
"// @@protoc_insertion_point(class_scope:$full_name$)\n",
- "classname", descriptor_->name(),
"full_name", descriptor_->full_name());
+
+ // Carefully initialize the default instance in such a way that it doesn't
+ // conflict with other initialization.
+ printer->Print(
+ "private static final $classname$ defaultInstance;\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ if (HasDescriptorMethods(descriptor_)) {
+ printer->Print(
+ "static {\n"
+ " defaultInstance = new $classname$();\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ } else {
+ // LITE_RUNTIME only has one constructor.
+ printer->Print(
+ "static {\n"
+ " defaultInstance = new $classname$(\n"
+ " com.google.protobuf.Internal\n"
+ " .EMPTY_CODED_INPUT_STREAM,\n"
+ " com.google.protobuf.ExtensionRegistryLite\n"
+ " .getEmptyRegistry());\n"
+ "}\n"
+ "\n",
+ "classname", descriptor_->name());
+ }
+ printer->Print(
+ "public static $classname$ getDefaultInstance() {\n"
+ " return defaultInstance;\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ if (HasDescriptorMethods(descriptor_)) {
+ // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+ printer->Print(
+ "public $classname$ getDefaultInstanceForType() {\n"
+ " return defaultInstance;\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ } else {
+ // LITE_RUNTIME uses this to implement the *ForType methods at the
+ // GeneratedMessageLite level.
+ printer->Print(
+ "static {"
+ " com.google.protobuf.GeneratedMessageLite.onLoad(\n"
+ " $classname$.class, new com.google.protobuf.GeneratedMessageLite\n"
+ " .PrototypeHolder<$classname$, Builder>(\n"
+ " defaultInstance, PARSER));"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ }
+
// Extensions must be declared after the defaultInstance is initialized
// because the defaultInstance is used by the extension to lazily retrieve
// the outer class's FileDescriptor.
for (int i = 0; i < descriptor_->extension_count(); i++) {
- ExtensionGenerator(descriptor_->extension(i)).Generate(printer);
+ ImmutableExtensionGenerator(descriptor_->extension(i), context_)
+ .Generate(printer);
}
+ // Some fields also have static members that must be initialized after we
+ // have the default instance available.
+ printer->Print(
+ "static {\n");
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateStaticInitializationCode(printer);
+ }
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+
printer->Outdent();
printer->Print("}\n\n");
}
@@ -437,46 +580,64 @@ void MessageGenerator::Generate(io::Printer* printer) {
// ===================================================================
-void MessageGenerator::
+void ImmutableMessageGenerator::
GenerateMessageSerializationMethods(io::Printer* printer) {
- scoped_array<const FieldDescriptor*> sorted_fields(
- SortFieldsByNumber(descriptor_));
+ google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
+ SortFieldsByNumber(descriptor_));
vector<const Descriptor::ExtensionRange*> sorted_extensions;
for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
sorted_extensions.push_back(descriptor_->extension_range(i));
}
- sort(sorted_extensions.begin(), sorted_extensions.end(),
- ExtensionRangeOrdering());
+ std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeOrdering());
printer->Print(
"public void writeTo(com.google.protobuf.CodedOutputStream output)\n"
" throws java.io.IOException {\n");
printer->Indent();
- // writeTo(CodedOutputStream output) might be invoked without
- // getSerializedSize() ever being called, but we need the memoized
- // sizes in case this message has packed fields. Rather than emit checks for
- // each packed field, just call getSerializedSize() up front for all messages.
- // In most cases, getSerializedSize() will have already been called anyway by
- // one of the wrapper writeTo() methods, making this call cheap.
- printer->Print(
- "getSerializedSize();\n");
+ if (HasPackedFields(descriptor_)) {
+ // writeTo(CodedOutputStream output) might be invoked without
+ // getSerializedSize() ever being called, but we need the memoized
+ // sizes in case this message has packed fields. Rather than emit checks for
+ // each packed field, just call getSerializedSize() up front.
+ // In most cases, getSerializedSize() will have already been called anyway
+ // by one of the wrapper writeTo() methods, making this call cheap.
+ printer->Print(
+ "getSerializedSize();\n");
+ }
if (descriptor_->extension_range_count() > 0) {
if (descriptor_->options().message_set_wire_format()) {
- printer->Print(
- "com.google.protobuf.GeneratedMessage$lite$\n"
- " .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n"
- " newMessageSetExtensionWriter();\n",
- "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite",
- "classname", ClassName(descriptor_));
+ if (HasDescriptorMethods(descriptor_)) {
+ printer->Print(
+ "com.google.protobuf.GeneratedMessage\n"
+ " .ExtendableMessage<$classname$>.ExtensionWriter\n"
+ " extensionWriter = newMessageSetExtensionWriter();\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ } else {
+ printer->Print(
+ "com.google.protobuf.GeneratedMessageLite\n"
+ " .ExtendableMessage<$classname$, $classname$.Builder>\n"
+ " .ExtensionWriter extensionWriter =\n"
+ " newMessageSetExtensionWriter();\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ }
} else {
- printer->Print(
- "com.google.protobuf.GeneratedMessage$lite$\n"
- " .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n"
- " newExtensionWriter();\n",
- "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite",
- "classname", ClassName(descriptor_));
+ if (HasDescriptorMethods(descriptor_)) {
+ printer->Print(
+ "com.google.protobuf.GeneratedMessage\n"
+ " .ExtendableMessage<$classname$>.ExtensionWriter\n"
+ " extensionWriter = newExtensionWriter();\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ } else {
+ printer->Print(
+ "com.google.protobuf.GeneratedMessageLite\n"
+ " .ExtendableMessage<$classname$, $classname$.Builder>\n"
+ " .ExtensionWriter extensionWriter =\n"
+ " newExtensionWriter();\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ }
}
}
@@ -495,13 +656,14 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
}
}
- if (HasUnknownFields(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");
}
}
@@ -531,13 +693,14 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
}
}
- if (HasUnknownFields(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");
}
}
@@ -549,16 +712,10 @@ 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 MessageGenerator::
+void ImmutableMessageGenerator::
GenerateParseFromMethods(io::Printer* printer) {
// Note: These are separate from GenerateMessageSerializationMethods()
// because they need to be generated even for messages that are optimized
@@ -567,79 +724,65 @@ GenerateParseFromMethods(io::Printer* printer) {
"public static $classname$ parseFrom(\n"
" com.google.protobuf.ByteString data)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return newBuilder().mergeFrom(data).buildParsed();\n"
+ " return PARSER.parseFrom(data);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.ByteString data,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return newBuilder().mergeFrom(data, extensionRegistry)\n"
- " .buildParsed();\n"
+ " return PARSER.parseFrom(data, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(byte[] data)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return newBuilder().mergeFrom(data).buildParsed();\n"
+ " return PARSER.parseFrom(data);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" byte[] data,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " return newBuilder().mergeFrom(data, extensionRegistry)\n"
- " .buildParsed();\n"
+ " return PARSER.parseFrom(data, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " return newBuilder().mergeFrom(input).buildParsed();\n"
+ " return PARSER.parseFrom(input);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return newBuilder().mergeFrom(input, extensionRegistry)\n"
- " .buildParsed();\n"
+ " return PARSER.parseFrom(input, extensionRegistry);\n"
"}\n"
"public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " Builder builder = newBuilder();\n"
- " if (builder.mergeDelimitedFrom(input)) {\n"
- " return builder.buildParsed();\n"
- " } else {\n"
- " return null;\n"
- " }\n"
+ " return PARSER.parseDelimitedFrom(input);\n"
"}\n"
"public static $classname$ parseDelimitedFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " Builder builder = newBuilder();\n"
- " if (builder.mergeDelimitedFrom(input, extensionRegistry)) {\n"
- " return builder.buildParsed();\n"
- " } else {\n"
- " return null;\n"
- " }\n"
+ " return PARSER.parseDelimitedFrom(input, extensionRegistry);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input)\n"
" throws java.io.IOException {\n"
- " return newBuilder().mergeFrom(input).buildParsed();\n"
+ " return PARSER.parseFrom(input);\n"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return newBuilder().mergeFrom(input, extensionRegistry)\n"
- " .buildParsed();\n"
+ " return PARSER.parseFrom(input, extensionRegistry);\n"
"}\n"
"\n",
- "classname", ClassName(descriptor_));
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
}
-void MessageGenerator::GenerateSerializeOneField(
+void ImmutableMessageGenerator::GenerateSerializeOneField(
io::Printer* printer, const FieldDescriptor* field) {
field_generators_.get(field).GenerateSerializationCode(printer);
}
-void MessageGenerator::GenerateSerializeOneExtensionRange(
+void ImmutableMessageGenerator::GenerateSerializeOneExtensionRange(
io::Printer* printer, const Descriptor::ExtensionRange* range) {
printer->Print(
"extensionWriter.writeUntil($end$, output);\n",
@@ -648,16 +791,26 @@ void MessageGenerator::GenerateSerializeOneExtensionRange(
// ===================================================================
-void MessageGenerator::GenerateBuilder(io::Printer* printer) {
+void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
+ if (HasDescriptorMethods(descriptor_)) {
+ // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+ printer->Print(
+ "public Builder newBuilderForType() { return newBuilder(); }\n");
+ }
+
printer->Print(
- "public static Builder newBuilder() { return Builder.create(); }\n"
- "public Builder newBuilderForType() { return newBuilder(); }\n"
+ "public static Builder newBuilder() {\n"
+ " return defaultInstance.toBuilder();\n"
+ "}\n"
"public static Builder newBuilder($classname$ prototype) {\n"
- " return newBuilder().mergeFrom(prototype);\n"
+ " return defaultInstance.toBuilder().mergeFrom(prototype);\n"
+ "}\n"
+ "public Builder toBuilder() {\n"
+ " return this == defaultInstance\n"
+ " ? new Builder() : new Builder().mergeFrom(this);\n"
"}\n"
- "public Builder toBuilder() { return newBuilder(this); }\n"
"\n",
- "classname", ClassName(descriptor_));
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
if (HasNestedBuilders(descriptor_)) {
printer->Print(
@@ -669,39 +822,52 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) {
"}\n");
}
+ WriteMessageDocComment(printer, descriptor_);
+
if (descriptor_->extension_range_count() > 0) {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public static final class Builder extends\n"
" com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
- " $classname$, Builder> implements $classname$OrBuilder {\n",
- "classname", ClassName(descriptor_));
+ " $classname$, Builder> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
} else {
printer->Print(
"public static final class Builder extends\n"
" com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<\n"
- " $classname$, Builder> implements $classname$OrBuilder {\n",
- "classname", ClassName(descriptor_));
+ " $classname$, Builder> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
}
} else {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public static final class Builder extends\n"
- " com.google.protobuf.GeneratedMessage.Builder<Builder>\n"
- " implements $classname$OrBuilder {\n",
- "classname", ClassName(descriptor_));
+ " com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
} else {
printer->Print(
"public static final class Builder extends\n"
" com.google.protobuf.GeneratedMessageLite.Builder<\n"
" $classname$, Builder>\n"
- " implements $classname$OrBuilder {\n",
- "classname", ClassName(descriptor_));
+ " implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
}
}
printer->Indent();
- GenerateDescriptorMethods(printer);
+ GenerateDescriptorMethods(printer, true);
GenerateCommonBuilderMethods(printer);
if (HasGeneratedMethods(descriptor_)) {
@@ -709,25 +875,72 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) {
GenerateBuilderParsingMethods(printer);
}
- // Integers for bit fields.
- int totalBits = 0;
- for (int i = 0; i < descriptor_->field_count(); i++) {
- totalBits += field_generators_.get(descriptor_->field(i))
- .GetNumBitsForBuilder();
+ // oneof
+ map<string, string> vars;
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name;
+ vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->capitalized_name;
+ vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+ // oneofCase_ and oneof_
+ printer->Print(vars,
+ "private int $oneof_name$Case_ = 0;\n"
+ "private java.lang.Object $oneof_name$_;\n");
+ // oneofCase() and clearOneof()
+ printer->Print(vars,
+ "public $oneof_capitalized_name$Case\n"
+ " get$oneof_capitalized_name$Case() {\n"
+ " return $oneof_capitalized_name$Case.valueOf(\n"
+ " $oneof_name$Case_);\n"
+ "}\n"
+ "\n"
+ "public Builder clear$oneof_capitalized_name$() {\n"
+ " $oneof_name$Case_ = 0;\n"
+ " $oneof_name$_ = null;\n");
+ if (HasDescriptorMethods(descriptor_)) {
+ printer->Print(" onChanged();\n");
+ }
+ printer->Print(
+ " return this;\n"
+ "}\n"
+ "\n");
}
- int totalInts = (totalBits + 31) / 32;
- for (int i = 0; i < totalInts; i++) {
- printer->Print("private int $bit_field_name$;\n",
- "bit_field_name", GetBitFieldName(i));
+
+ if (GenerateHasBits(descriptor_)) {
+ // Integers for bit fields.
+ int totalBits = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ totalBits += field_generators_.get(descriptor_->field(i))
+ .GetNumBitsForBuilder();
+ }
+ int totalInts = (totalBits + 31) / 32;
+ for (int i = 0; i < totalInts; i++) {
+ printer->Print("private int $bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
}
for (int i = 0; i < descriptor_->field_count(); i++) {
printer->Print("\n");
- PrintFieldComment(printer, descriptor_->field(i));
field_generators_.get(descriptor_->field(i))
.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",
@@ -737,42 +950,127 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) {
printer->Print("}\n");
}
-void MessageGenerator::GenerateDescriptorMethods(io::Printer* printer) {
+void ImmutableMessageGenerator::
+GenerateDescriptorMethods(io::Printer* printer, bool is_builder) {
if (HasDescriptorMethods(descriptor_)) {
+ if (!descriptor_->options().no_standard_descriptor_accessor()) {
+ printer->Print(
+ "public static final com.google.protobuf.Descriptors.Descriptor\n"
+ " getDescriptor() {\n"
+ " return $fileclass$.internal_$identifier$_descriptor;\n"
+ "}\n"
+ "\n",
+ "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+ "identifier", UniqueFileScopeIdentifier(descriptor_));
+ }
+ vector<const FieldDescriptor*> map_fields;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+ IsMapEntry(field->message_type())) {
+ map_fields.push_back(field);
+ }
+ }
+ if (!map_fields.empty()) {
+ printer->Print(
+ "@SuppressWarnings({\"rawtypes\"})\n"
+ "protected com.google.protobuf.MapField internalGetMapField(\n"
+ " int number) {\n"
+ " switch (number) {\n");
+ printer->Indent();
+ printer->Indent();
+ for (int i = 0; i < map_fields.size(); ++i) {
+ const FieldDescriptor* field = map_fields[i];
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ printer->Print(
+ "case $number$:\n"
+ " return internalGet$capitalized_name$();\n",
+ "number", SimpleItoa(field->number()),
+ "capitalized_name", info->capitalized_name);
+ }
+ printer->Print(
+ "default:\n"
+ " throw new RuntimeException(\n"
+ " \"Invalid map field number: \" + number);\n");
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n"
+ "}\n");
+ if (is_builder) {
+ printer->Print(
+ "@SuppressWarnings({\"rawtypes\"})\n"
+ "protected com.google.protobuf.MapField internalGetMutableMapField(\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 internalGetMutable$capitalized_name$();\n",
+ "number", SimpleItoa(field->number()),
+ "capitalized_name", info->capitalized_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(
- "public static final com.google.protobuf.Descriptors.Descriptor\n"
- " getDescriptor() {\n"
- " return $fileclass$.internal_$identifier$_descriptor;\n"
- "}\n"
- "\n"
"protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
" internalGetFieldAccessorTable() {\n"
- " return $fileclass$.internal_$identifier$_fieldAccessorTable;\n"
+ " return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
+ " .ensureFieldAccessorsInitialized(\n"
+ " $classname$.class, $classname$.Builder.class);\n"
"}\n"
"\n",
- "fileclass", ClassName(descriptor_->file()),
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
+ "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
"identifier", UniqueFileScopeIdentifier(descriptor_));
}
}
// ===================================================================
-void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
- printer->Print(
- "// Construct using $classname$.newBuilder()\n"
- "private Builder() {\n"
- " maybeForceBuilderInitialization();\n"
- "}\n"
- "\n",
- "classname", ClassName(descriptor_));
-
+void ImmutableMessageGenerator::
+GenerateCommonBuilderMethods(io::Printer* printer) {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
- "private Builder(BuilderParent parent) {\n"
+ "// Construct using $classname$.newBuilder()\n"
+ "private Builder() {\n"
+ " maybeForceBuilderInitialization();\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ printer->Print(
+ "private Builder(\n"
+ " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
" super(parent);\n"
" maybeForceBuilderInitialization();\n"
"}\n",
- "classname", ClassName(descriptor_));
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ } else {
+ // LITE runtime passes along the default instance to implement
+ // getDefaultInstanceForType() at the GeneratedMessageLite level.
+ printer->Print(
+ "// Construct using $classname$.newBuilder()\n"
+ "private Builder() {\n"
+ " super(defaultInstance);\n"
+ " maybeForceBuilderInitialization();\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
}
@@ -784,8 +1082,10 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
printer->Indent();
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
- field_generators_.get(descriptor_->field(i))
- .GenerateFieldBuilderInitializationCode(printer);
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateFieldBuilderInitializationCode(printer);
+ }
}
printer->Outdent();
printer->Outdent();
@@ -800,19 +1100,24 @@ void MessageGenerator::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", ClassName(descriptor_));
+ " super.clear();\n");
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
- field_generators_.get(descriptor_->field(i))
- .GenerateBuilderClearCode(printer);
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateBuilderClearCode(printer);
+ }
+ }
+
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "$oneof_name$Case_ = 0;\n"
+ "$oneof_name$_ = null;\n",
+ "oneof_name", context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name);
}
printer->Outdent();
@@ -820,75 +1125,92 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
printer->Print(
" return this;\n"
"}\n"
- "\n"
- "public Builder clone() {\n"
- " return create().mergeFrom(buildPartial());\n"
- "}\n"
- "\n",
- "classname", ClassName(descriptor_));
+ "\n");
+
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public com.google.protobuf.Descriptors.Descriptor\n"
" getDescriptorForType() {\n"
- " return $classname$.getDescriptor();\n"
+ " return $fileclass$.internal_$identifier$_descriptor;\n"
+ "}\n"
+ "\n",
+ "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+ "identifier", UniqueFileScopeIdentifier(descriptor_));
+
+ // LITE runtime implements this in GeneratedMessageLite.
+ printer->Print(
+ "public $classname$ getDefaultInstanceForType() {\n"
+ " return $classname$.getDefaultInstance();\n"
"}\n"
"\n",
- "classname", ClassName(descriptor_));
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
}
- printer->Print(
- "public $classname$ getDefaultInstanceForType() {\n"
- " return $classname$.getDefaultInstance();\n"
- "}\n"
- "\n",
- "classname", ClassName(descriptor_));
// -----------------------------------------------------------------
- printer->Print(
- "public $classname$ build() {\n"
- " $classname$ result = buildPartial();\n"
- " if (!result.isInitialized()) {\n"
- " throw newUninitializedMessageException(result);\n"
- " }\n"
- " return result;\n"
- "}\n"
- "\n"
- "private $classname$ buildParsed()\n"
- " throws com.google.protobuf.InvalidProtocolBufferException {\n"
- " $classname$ result = buildPartial();\n"
- " if (!result.isInitialized()) {\n"
- " throw newUninitializedMessageException(\n"
- " result).asInvalidProtocolBufferException();\n"
- " }\n"
- " return result;\n"
- "}\n"
- "\n"
- "public $classname$ buildPartial() {\n"
- " $classname$ result = new $classname$(this);\n",
- "classname", ClassName(descriptor_));
+ if (HasDescriptorMethods(descriptor_)) {
+ // LITE implements build in GeneratedMessageLite to save methods.
+ printer->Print(
+ "public $classname$ build() {\n"
+ " $classname$ result = buildPartial();\n"
+ " if (!result.isInitialized()) {\n"
+ " throw newUninitializedMessageException(result);\n"
+ " }\n"
+ " return result;\n"
+ "}\n"
+ "\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ }
+
+ if (HasDescriptorMethods(descriptor_)) {
+ printer->Print(
+ "public $classname$ buildPartial() {\n"
+ " $classname$ result = new $classname$(this);\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ } else {
+ // LITE_RUNTIME only provides a single message constructor.
+ printer->Print(
+ "public $classname$ buildPartial() {\n"
+ " $classname$ result = new $classname$(\n"
+ " com.google.protobuf.Internal\n"
+ " .EMPTY_CODED_INPUT_STREAM,\n"
+ " com.google.protobuf.ExtensionRegistryLite\n"
+ " .getEmptyRegistry());\n"
+ " result.unknownFields = this.unknownFields;\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ " result.extensions = this.buildExtensions();\n");
+ }
+ }
printer->Indent();
- // Local vars for from and to bit fields to avoid accessing the builder and
- // message over and over for these fields. Seems to provide a slight
- // perforamance improvement in micro benchmark and this is also what proto1
- // code does.
int totalBuilderBits = 0;
int totalMessageBits = 0;
for (int i = 0; i < descriptor_->field_count(); i++) {
- const FieldGenerator& field = field_generators_.get(descriptor_->field(i));
+ const ImmutableFieldGenerator& field =
+ field_generators_.get(descriptor_->field(i));
totalBuilderBits += field.GetNumBitsForBuilder();
totalMessageBits += field.GetNumBitsForMessage();
}
int totalBuilderInts = (totalBuilderBits + 31) / 32;
int totalMessageInts = (totalMessageBits + 31) / 32;
- for (int i = 0; i < totalBuilderInts; i++) {
- printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
- "bit_field_name", GetBitFieldName(i));
- }
- for (int i = 0; i < totalMessageInts; i++) {
- printer->Print("int to_$bit_field_name$ = 0;\n",
- "bit_field_name", GetBitFieldName(i));
+
+ if (GenerateHasBits(descriptor_)) {
+ // Local vars for from and to bit fields to avoid accessing the builder and
+ // message over and over for these fields. Seems to provide a slight
+ // perforamance improvement in micro benchmark and this is also what proto1
+ // code does.
+ for (int i = 0; i < totalBuilderInts; i++) {
+ printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ for (int i = 0; i < totalMessageInts; i++) {
+ printer->Print("int to_$bit_field_name$ = 0;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
}
// Output generation code for each field.
@@ -896,10 +1218,18 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer);
}
- // Copy the bit field results to the generated message
- for (int i = 0; i < totalMessageInts; i++) {
- printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
- "bit_field_name", GetBitFieldName(i));
+ if (GenerateHasBits(descriptor_)) {
+ // Copy the bit field results to the generated message
+ for (int i = 0; i < totalMessageInts; i++) {
+ printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ }
+
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n",
+ "oneof_name", context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name);
}
printer->Outdent();
@@ -913,7 +1243,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
" return result;\n"
"}\n"
"\n",
- "classname", ClassName(descriptor_));
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
// -----------------------------------------------------------------
@@ -931,7 +1261,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
" }\n"
"}\n"
"\n",
- "classname", ClassName(descriptor_));
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
}
printer->Print(
@@ -939,11 +1269,48 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
// Optimization: If other is the default instance, we know none of its
// fields are set so we can skip the merge.
" if (other == $classname$.getDefaultInstance()) return this;\n",
- "classname", ClassName(descriptor_));
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
- field_generators_.get(descriptor_->field(i)).GenerateMergingCode(printer);
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(
+ descriptor_->field(i)).GenerateMergingCode(printer);
+ }
+ }
+
+ // Merge oneof fields.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+ printer->Print(
+ "switch (other.get$oneof_capitalized_name$Case()) {\n",
+ "oneof_capitalized_name",
+ context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->capitalized_name);
+ printer->Indent();
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ "case $field_name$: {\n",
+ "field_name",
+ ToUpper(field->name()));
+ printer->Indent();
+ field_generators_.get(field).GenerateMergingCode(printer);
+ printer->Print(
+ "break;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
+ printer->Print(
+ "case $cap_oneof_name$_NOT_SET: {\n"
+ " break;\n"
+ "}\n",
+ "cap_oneof_name",
+ ToUpper(context_->GetOneofGeneratorInfo(
+ descriptor_->oneof_decl(i))->name));
+ printer->Outdent();
+ printer->Print(
+ "}\n");
}
printer->Outdent();
@@ -954,9 +1321,13 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
" this.mergeExtensionFields(other);\n");
}
- if (HasUnknownFields(descriptor_)) {
+ if (PreserveUnknownFields(descriptor_)) {
printer->Print(
- " this.mergeUnknownFields(other.getUnknownFields());\n");
+ " this.mergeUnknownFields(other.unknownFields);\n");
+ }
+
+ if (HasDescriptorMethods(descriptor_)) {
+ printer->Print(" onChanged();\n");
}
printer->Print(
@@ -968,115 +1339,42 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
// ===================================================================
-void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) {
- scoped_array<const FieldDescriptor*> sorted_fields(
- SortFieldsByNumber(descriptor_));
-
- printer->Print(
- "public Builder mergeFrom(\n"
- " com.google.protobuf.CodedInputStream input,\n"
- " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
- " throws java.io.IOException {\n");
- printer->Indent();
-
- if (HasUnknownFields(descriptor_)) {
- printer->Print(
- "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
- " com.google.protobuf.UnknownFieldSet.newBuilder(\n"
- " this.getUnknownFields());\n");
- }
-
- printer->Print(
- "while (true) {\n");
- printer->Indent();
-
- printer->Print(
- "int tag = input.readTag();\n"
- "switch (tag) {\n");
- printer->Indent();
-
- if (HasUnknownFields(descriptor_)) {
+void ImmutableMessageGenerator::
+GenerateBuilderParsingMethods(io::Printer* printer) {
+ if (HasDescriptorMethods(descriptor_)) {
+ // LITE_RUNTIME implements this at the GeneratedMessageLite level.
printer->Print(
- "case 0:\n" // zero signals EOF / limit reached
- " this.setUnknownFields(unknownFields.build());\n"
- " $on_changed$\n"
- " return this;\n"
- "default: {\n"
- " if (!parseUnknownField(input, unknownFields,\n"
- " extensionRegistry, tag)) {\n"
- " this.setUnknownFields(unknownFields.build());\n"
- " $on_changed$\n"
- " return this;\n" // it's an endgroup tag
+ "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"
- " break;\n"
- "}\n",
- "on_changed", HasDescriptorMethods(descriptor_) ? "onChanged();" : "");
- } else {
- printer->Print(
- "case 0:\n" // zero signals EOF / limit reached
- " $on_changed$\n"
" return this;\n"
- "default: {\n"
- " if (!parseUnknownField(input, extensionRegistry, tag)) {\n"
- " $on_changed$\n"
- " return this;\n" // it's an endgroup tag
- " }\n"
- " break;\n"
"}\n",
- "on_changed", HasDescriptorMethods(descriptor_) ? "onChanged();" : "");
- }
-
- for (int i = 0; i < descriptor_->field_count(); i++) {
- const FieldDescriptor* field = sorted_fields[i];
- uint32 tag = WireFormatLite::MakeTag(field->number(),
- WireFormat::WireTypeForFieldType(field->type()));
-
- printer->Print(
- "case $tag$: {\n",
- "tag", SimpleItoa(tag));
- printer->Indent();
-
- field_generators_.get(field).GenerateParsingCode(printer);
-
- printer->Outdent();
- printer->Print(
- " break;\n"
- "}\n");
-
- if (field->is_packable()) {
- // To make packed = true wire compatible, we generate parsing code from a
- // packed version of this field regardless of field->options().packed().
- uint32 packed_tag = WireFormatLite::MakeTag(field->number(),
- WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
- printer->Print(
- "case $tag$: {\n",
- "tag", SimpleItoa(packed_tag));
- printer->Indent();
-
- field_generators_.get(field).GenerateParsingCodeFromPacked(printer);
-
- printer->Outdent();
- printer->Print(
- " break;\n"
- "}\n");
- }
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
}
-
- printer->Outdent();
- printer->Outdent();
- printer->Outdent();
- printer->Print(
- " }\n" // switch (tag)
- " }\n" // while (true)
- "}\n"
-
- "\n");
}
// ===================================================================
-void MessageGenerator::GenerateIsInitialized(
+void ImmutableMessageGenerator::GenerateIsInitialized(
io::Printer* printer, UseMemoization useMemoization) {
+ // LITE_RUNTIME avoids generating isInitialized if it's not needed.
+ if (!HasDescriptorMethods(descriptor_)
+ && !HasRequiredFields(descriptor_)) {
+ return;
+ }
+
bool memoization = useMemoization == MEMOIZE;
if (memoization) {
// Memoizes whether the protocol buffer is fully initialized (has all
@@ -1090,9 +1388,11 @@ void MessageGenerator::GenerateIsInitialized(
printer->Indent();
if (memoization) {
+ // Don't directly compare to -1 to avoid an Android x86 JIT bug.
printer->Print(
"byte isInitialized = memoizedIsInitialized;\n"
- "if (isInitialized != -1) return isInitialized == 1;\n"
+ "if (isInitialized == 1) return true;\n"
+ "if (isInitialized == 0) return false;\n"
"\n");
}
@@ -1101,6 +1401,7 @@ void MessageGenerator::GenerateIsInitialized(
// "has" fields into a single bitfield.
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
if (field->is_required()) {
printer->Print(
@@ -1108,7 +1409,7 @@ void MessageGenerator::GenerateIsInitialized(
" $memoize$\n"
" return false;\n"
"}\n",
- "name", UnderscoresToCapitalizedCamelCase(field),
+ "name", info->capitalized_name,
"memoize", memoization ? "memoizedIsInitialized = 0;" : "");
}
}
@@ -1116,6 +1417,7 @@ void MessageGenerator::GenerateIsInitialized(
// Now check that all embedded messages are initialized.
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
if (GetJavaType(field) == JAVATYPE_MESSAGE &&
HasRequiredFields(field->message_type())) {
switch (field->label()) {
@@ -1125,33 +1427,61 @@ void MessageGenerator::GenerateIsInitialized(
" $memoize$\n"
" return false;\n"
"}\n",
- "type", ClassName(field->message_type()),
- "name", UnderscoresToCapitalizedCamelCase(field),
+ "type", name_resolver_->GetImmutableClassName(
+ field->message_type()),
+ "name", info->capitalized_name,
"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", ClassName(field->message_type()),
- "name", UnderscoresToCapitalizedCamelCase(field),
+ "name", info->capitalized_name,
"memoize", memoization ? "memoizedIsInitialized = 0;" : "");
break;
case FieldDescriptor::LABEL_REPEATED:
- printer->Print(
- "for (int i = 0; i < get$name$Count(); i++) {\n"
- " if (!get$name$(i).isInitialized()) {\n"
- " $memoize$\n"
- " return false;\n"
- " }\n"
- "}\n",
- "type", ClassName(field->message_type()),
- "name", UnderscoresToCapitalizedCamelCase(field),
- "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+ if (IsMapEntry(field->message_type())) {
+ printer->Print(
+ "for ($type$ item : get$name$().values()) {\n"
+ " if (!item.isInitialized()) {\n"
+ " $memoize$\n"
+ " return false;\n"
+ " }\n"
+ "}\n",
+ "type", MapValueImmutableClassdName(field->message_type(),
+ name_resolver_),
+ "name", info->capitalized_name,
+ "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+ } else {
+ printer->Print(
+ "for (int i = 0; i < get$name$Count(); i++) {\n"
+ " if (!get$name$(i).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;
}
}
@@ -1181,7 +1511,21 @@ void MessageGenerator::GenerateIsInitialized(
// ===================================================================
-void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) {
+namespace {
+bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) {
+ if (field->is_repeated()) {
+ return false;
+ }
+ if (SupportFieldPresence(field->file())) {
+ return true;
+ }
+ return GetJavaType(field) == JAVATYPE_MESSAGE &&
+ field->containing_oneof() == NULL;
+}
+} // namespace
+
+void ImmutableMessageGenerator::
+GenerateEqualsAndHashCode(io::Printer* printer) {
printer->Print(
"@java.lang.Override\n"
"public boolean equals(final java.lang.Object obj) {\n");
@@ -1195,29 +1539,35 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) {
"}\n"
"$classname$ other = ($classname$) obj;\n"
"\n",
- "classname", ClassName(descriptor_));
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
printer->Print("boolean result = true;\n");
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
- if (!field->is_repeated()) {
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+ if (check_has_bits) {
printer->Print(
"result = result && (has$name$() == other.has$name$());\n"
"if (has$name$()) {\n",
- "name", UnderscoresToCapitalizedCamelCase(field));
+ "name", info->capitalized_name);
printer->Indent();
}
field_generators_.get(field).GenerateEqualsCode(printer);
- if (!field->is_repeated()) {
+ if (check_has_bits) {
printer->Outdent();
printer->Print(
"}\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"
@@ -1236,18 +1586,36 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) {
"public int hashCode() {\n");
printer->Indent();
printer->Print(
- "int hash = 41;\n"
- "hash = (19 * hash) + getDescriptorForType().hashCode();\n");
+ "if (memoizedHashCode != 0) {\n");
+ printer->Indent();
+ printer->Print(
+ "return memoizedHashCode;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "int hash = 41;\n");
+
+ if (HasDescriptorMethods(descriptor_)) {
+ printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
+ } else {
+ // Include the hash of the class so that two objects with different types
+ // but the same field values will probably have different hashes.
+ printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n",
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
+ }
+
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
- if (!field->is_repeated()) {
+ const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+ bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+ if (check_has_bits) {
printer->Print(
"if (has$name$()) {\n",
- "name", UnderscoresToCapitalizedCamelCase(field));
+ "name", info->capitalized_name);
printer->Indent();
}
field_generators_.get(field).GenerateHashCode(printer);
- if (!field->is_repeated()) {
+ if (check_has_bits) {
printer->Outdent();
printer->Print("}\n");
}
@@ -1258,8 +1626,11 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) {
"hash = hashFields(hash, getExtensionFields());\n");
}
}
+
+ printer->Print(
+ "hash = (29 * hash) + unknownFields.hashCode();\n");
printer->Print(
- "hash = (29 * hash) + getUnknownFields().hashCode();\n"
+ "memoizedHashCode = hash;\n"
"return hash;\n");
printer->Outdent();
printer->Print(
@@ -1269,18 +1640,279 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) {
// ===================================================================
-void MessageGenerator::GenerateExtensionRegistrationCode(io::Printer* printer) {
+void ImmutableMessageGenerator::
+GenerateExtensionRegistrationCode(io::Printer* printer) {
for (int i = 0; i < descriptor_->extension_count(); i++) {
- ExtensionGenerator(descriptor_->extension(i))
+ ImmutableExtensionGenerator(descriptor_->extension(i), context_)
.GenerateRegistrationCode(printer);
}
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
- MessageGenerator(descriptor_->nested_type(i))
+ ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
.GenerateExtensionRegistrationCode(printer);
}
}
+// ===================================================================
+void ImmutableMessageGenerator::
+GenerateParsingConstructor(io::Printer* printer) {
+ google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ printer->Print(
+ "private $classname$(\n"
+ " com.google.protobuf.CodedInputStream input,\n"
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+
+ // Initialize all fields to default.
+ if (HasDescriptorMethods(descriptor_)) {
+ printer->Print(
+ "this();\n");
+ } else {
+ // LITE_RUNTIME only has one constructor.
+ GenerateInitializers(printer);
+ }
+
+ // Use builder bits to track mutable repeated fields.
+ int totalBuilderBits = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const ImmutableFieldGenerator& field =
+ field_generators_.get(descriptor_->field(i));
+ totalBuilderBits += field.GetNumBitsForBuilder();
+ }
+ int totalBuilderInts = (totalBuilderBits + 31) / 32;
+ for (int i = 0; i < totalBuilderInts; i++) {
+ printer->Print("int mutable_$bit_field_name$ = 0;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+
+ 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(
+ "try {\n");
+ printer->Indent();
+
+ printer->Print(
+ "boolean done = false;\n"
+ "while (!done) {\n");
+ printer->Indent();
+
+ printer->Print(
+ "int tag = input.readTag();\n"
+ "switch (tag) {\n");
+ printer->Indent();
+
+ printer->Print(
+ "case 0:\n" // zero signals EOF / limit reached
+ " done = true;\n"
+ " 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];
+ uint32 tag = WireFormatLite::MakeTag(field->number(),
+ WireFormat::WireTypeForFieldType(field->type()));
+
+ printer->Print(
+ "case $tag$: {\n",
+ "tag", SimpleItoa(tag));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateParsingCode(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " break;\n"
+ "}\n");
+
+ if (field->is_packable()) {
+ // To make packed = true wire compatible, we generate parsing code from a
+ // packed version of this field regardless of field->options().packed().
+ uint32 packed_tag = WireFormatLite::MakeTag(field->number(),
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+ printer->Print(
+ "case $tag$: {\n",
+ "tag", SimpleItoa(packed_tag));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateParsingCodeFromPacked(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " break;\n"
+ "}\n");
+ }
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n" // switch (tag)
+ "}\n"); // while (!done)
+
+ printer->Outdent();
+ printer->Print(
+ "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+ " throw new RuntimeException(e.setUnfinishedMessage(this));\n"
+ "} catch (java.io.IOException e) {\n"
+ " throw new RuntimeException(\n"
+ " new com.google.protobuf.InvalidProtocolBufferException(\n"
+ " e.getMessage()).setUnfinishedMessage(this));\n"
+ "} finally {\n");
+ printer->Indent();
+
+ // Make repeated field list immutable.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = sorted_fields[i];
+ field_generators_.get(field).GenerateParsingDoneCode(printer);
+ }
+
+ if (PreserveUnknownFields(descriptor_)) {
+ // Make unknown fields immutable.
+ printer->Print("this.unknownFields = unknownFields.build();\n");
+ }
+
+ if (!HasDescriptorMethods(descriptor_)) {
+ // LITE runtime uses a static method to reduce method count.
+ if (descriptor_->extension_range_count() > 0) {
+ // Make extensions immutable.
+ printer->Print(
+ "makeExtensionsImmutable(extensions);\n");
+ }
+ } else {
+ // Make extensions immutable.
+ printer->Print(
+ "makeExtensionsImmutable();\n");
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n" // finally
+ "}\n");
+}
+
+// ===================================================================
+void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
+ printer->Print(
+ "public static final com.google.protobuf.Parser<$classname$> PARSER =\n"
+ " new com.google.protobuf.AbstractParser<$classname$>() {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+ printer->Print(
+ "public $classname$ parsePartialFrom(\n"
+ " com.google.protobuf.CodedInputStream input,\n"
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n",
+ "classname", descriptor_->name());
+ if (HasGeneratedMethods(descriptor_)) {
+ // The parsing constructor throws an InvalidProtocolBufferException via a
+ // RuntimeException to aid in method pruning. We unwrap it here.
+ printer->Print(
+ " try {\n"
+ " return new $classname$(input, extensionRegistry);\n"
+ " } catch (RuntimeException e) {\n"
+ " if (e.getCause() instanceof\n"
+ " com.google.protobuf.InvalidProtocolBufferException) {\n"
+ " throw (com.google.protobuf.InvalidProtocolBufferException)\n"
+ " e.getCause();\n"
+ " }\n"
+ " throw e;\n"
+ " }\n",
+ "classname", descriptor_->name());
+ } else {
+ // When parsing constructor isn't generated, use builder to parse messages.
+ // Note, will fallback to use reflection based mergeFieldFrom() in
+ // AbstractMessage.Builder.
+ printer->Indent();
+ printer->Print(
+ "Builder builder = newBuilder();\n"
+ "try {\n"
+ " builder.mergeFrom(input, extensionRegistry);\n"
+ "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+ " throw e.setUnfinishedMessage(builder.buildPartial());\n"
+ "} catch (java.io.IOException e) {\n"
+ " throw new com.google.protobuf.InvalidProtocolBufferException(\n"
+ " e.getMessage()).setUnfinishedMessage(builder.buildPartial());\n"
+ "}\n"
+ "return builder.buildPartial();\n");
+ printer->Outdent();
+ }
+ printer->Print(
+ "}\n");
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "\n");
+
+ if (HasDescriptorMethods(descriptor_)) {
+ // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+ printer->Print(
+ "@java.lang.Override\n"
+ "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
+ " return PARSER;\n"
+ "}\n"
+ "\n",
+ "classname", descriptor_->name());
+ }
+}
+
+// ===================================================================
+void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (!descriptor_->field(i)->containing_oneof()) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateInitializationCode(printer);
+ }
+ }
+}
+
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index 4c6fbbe5..016fdd5d 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -36,11 +36,17 @@
#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
#include <string>
-#include <google/protobuf/stubs/common.h>
+#include <map>
#include <google/protobuf/compiler/java/java_field.h>
namespace google {
namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
namespace io {
class Printer; // printer.h
}
@@ -53,26 +59,45 @@ namespace java {
class MessageGenerator {
public:
explicit MessageGenerator(const Descriptor* descriptor);
- ~MessageGenerator();
+ virtual ~MessageGenerator();
// All static variables have to be declared at the top-level of the file
// so that we can control initialization order, which is important for
// DescriptorProto bootstrapping to work.
- void GenerateStaticVariables(io::Printer* printer);
+ virtual void GenerateStaticVariables(io::Printer* printer) = 0;
// Output code which initializes the static variables generated by
// GenerateStaticVariables().
- void GenerateStaticVariableInitializers(io::Printer* printer);
+ virtual void GenerateStaticVariableInitializers(io::Printer* printer) = 0;
// Generate the class itself.
- void Generate(io::Printer* printer);
+ virtual void Generate(io::Printer* printer) = 0;
// Generates the base interface that both the class and its builder implement
- void GenerateInterface(io::Printer* printer);
+ virtual void GenerateInterface(io::Printer* printer) = 0;
// Generate code to register all contained extensions with an
// ExtensionRegistry.
- void GenerateExtensionRegistrationCode(io::Printer* printer);
+ virtual void GenerateExtensionRegistrationCode(io::Printer* printer) = 0;
+
+ protected:
+ const Descriptor* descriptor_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+
+class ImmutableMessageGenerator : public MessageGenerator {
+ public:
+ explicit ImmutableMessageGenerator(const Descriptor* descriptor,
+ Context* context);
+ virtual ~ImmutableMessageGenerator();
+
+ virtual void Generate(io::Printer* printer);
+ virtual void GenerateInterface(io::Printer* printer);
+ virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
+ virtual void GenerateStaticVariables(io::Printer* printer);
+ virtual void GenerateStaticVariableInitializers(io::Printer* printer);
private:
enum UseMemoization {
@@ -80,6 +105,9 @@ class MessageGenerator {
DONT_MEMOIZE
};
+ void GenerateFieldAccessorTable(io::Printer* printer);
+ void GenerateFieldAccessorTableInitializer(io::Printer* printer);
+
void GenerateMessageSerializationMethods(io::Printer* printer);
void GenerateParseFromMethods(io::Printer* printer);
void GenerateSerializeOneField(io::Printer* printer,
@@ -89,16 +117,20 @@ class MessageGenerator {
void GenerateBuilder(io::Printer* printer);
void GenerateCommonBuilderMethods(io::Printer* printer);
- void GenerateDescriptorMethods(io::Printer* printer);
+ void GenerateDescriptorMethods(io::Printer* printer, bool is_builder);
void GenerateBuilderParsingMethods(io::Printer* printer);
void GenerateIsInitialized(io::Printer* printer,
UseMemoization useMemoization);
+ void GenerateInitializers(io::Printer* printer);
void GenerateEqualsAndHashCode(io::Printer* printer);
+ void GenerateParser(io::Printer* printer);
+ void GenerateParsingConstructor(io::Printer* printer);
- const Descriptor* descriptor_;
- FieldGeneratorMap field_generators_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+ FieldGeneratorMap<ImmutableFieldGenerator> field_generators_;
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageGenerator);
};
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index 251945af..a2d12a38 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,8 +35,11 @@
#include <map>
#include <string>
+#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_message_field.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
@@ -48,19 +51,18 @@ namespace java {
namespace {
-// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
-// repeat code between this and the other field types.
void SetMessageVariables(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
map<string, string>* variables) {
- (*variables)["name"] =
- UnderscoresToCamelCase(descriptor);
- (*variables)["capitalized_name"] =
- UnderscoresToCapitalizedCamelCase(descriptor);
- (*variables)["constant_name"] = FieldConstantName(descriptor);
- (*variables)["number"] = SimpleItoa(descriptor->number());
- (*variables)["type"] = ClassName(descriptor->message_type());
+ SetCommonFieldVariables(descriptor, info, variables);
+
+ (*variables)["type"] =
+ name_resolver->GetImmutableClassName(descriptor->message_type());
+ (*variables)["mutable_type"] =
+ name_resolver->GetMutableClassName(descriptor->message_type());
(*variables)["group_or_message"] =
(GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ?
"Group" : "Message";
@@ -71,19 +73,41 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["on_changed"] =
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
- // For singular messages and builders, one bit is used for the hasField bit.
- (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ if (SupportFieldPresence(descriptor->file())) {
+ // For singular messages and builders, one bit is used for the hasField bit.
+ (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+
+ // Note that these have a trailing ";".
+ (*variables)["set_has_field_bit_message"] =
+ GenerateSetBit(messageBitIndex) + ";";
+ (*variables)["set_has_field_bit_builder"] =
+ GenerateSetBit(builderBitIndex) + ";";
+ (*variables)["clear_has_field_bit_builder"] =
+ GenerateClearBit(builderBitIndex) + ";";
- (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
- (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
- (*variables)["clear_has_field_bit_builder"] =
- GenerateClearBit(builderBitIndex);
+ (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+ } else {
+ (*variables)["set_has_field_bit_message"] = "";
+ (*variables)["set_has_field_bit_builder"] = "";
+ (*variables)["clear_has_field_bit_builder"] = "";
+
+ (*variables)["is_field_present_message"] =
+ (*variables)["name"] + "_ != null";
+ }
// For repated builders, one bit is used for whether the array is immutable.
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+ // 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);
+
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
(*variables)["set_has_field_bit_to_local"] =
@@ -94,62 +118,102 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
// ===================================================================
-MessageFieldGenerator::
-MessageFieldGenerator(const FieldDescriptor* descriptor,
+ImmutableMessageFieldGenerator::
+ImmutableMessageFieldGenerator(const FieldDescriptor* descriptor,
int messageBitIndex,
- int builderBitIndex)
+ int builderBitIndex,
+ Context* context)
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
- builderBitIndex_(builderBitIndex) {
- SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
- &variables_);
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
+ SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
}
-MessageFieldGenerator::~MessageFieldGenerator() {}
+ImmutableMessageFieldGenerator::~ImmutableMessageFieldGenerator() {}
-int MessageFieldGenerator::GetNumBitsForMessage() const {
+int ImmutableMessageFieldGenerator::GetNumBitsForMessage() const {
return 1;
}
-int MessageFieldGenerator::GetNumBitsForBuilder() const {
+int ImmutableMessageFieldGenerator::GetNumBitsForBuilder() const {
return 1;
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
// TODO(jonp): In the future, consider having a method specific to the
// interface so that builders can choose dynamically to either return a
// message or a nested builder, so that asking for the interface doesn't
// cause a message to ever be built.
+ if (SupportFieldPresence(descriptor_->file()) ||
+ descriptor_->containing_oneof() == NULL) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$boolean has$capitalized_name$();\n"
"$deprecation$$type$ get$capitalized_name$();\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
}
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $type$ $name$_;\n"
- "$deprecation$public boolean has$capitalized_name$() {\n"
- " return $get_has_field_bit_message$;\n"
- "}\n"
- "$deprecation$public $type$ get$capitalized_name$() {\n"
- " return $name$_;\n"
- "}\n");
+ "private $type$ $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
- if (HasNestedBuilders(descriptor_->containing_type())) {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
- " return $name$_;\n"
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_message$;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
"}\n");
+
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder "
+ "get$capitalized_name$OrBuilder() {\n"
+ " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+ "}\n");
+ }
+ } else {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $name$_ != null;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+ "}\n");
+
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder "
+ "get$capitalized_name$OrBuilder() {\n"
+ " return get$capitalized_name$();\n"
+ "}\n");
+ }
}
}
-void MessageFieldGenerator::PrintNestedBuilderCondition(
+void ImmutableMessageFieldGenerator::PrintNestedBuilderCondition(
io::Printer* printer,
const char* regular_case,
const char* nested_builder_case) const {
@@ -168,7 +232,7 @@ void MessageFieldGenerator::PrintNestedBuilderCondition(
}
}
-void MessageFieldGenerator::PrintNestedBuilderFunction(
+void ImmutableMessageFieldGenerator::PrintNestedBuilderFunction(
io::Printer* printer,
const char* method_prototype,
const char* regular_case,
@@ -185,15 +249,16 @@ void MessageFieldGenerator::PrintNestedBuilderFunction(
printer->Print("}\n");
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
// When using nested-builders, the code initially works just like the
// non-nested builder case. It only creates a nested builder lazily on
// demand and then forever delegates to it after creation.
+ bool support_field_presence = SupportFieldPresence(descriptor_->file());
+
printer->Print(variables_,
- // Used when the builder is null.
- "private $type$ $name$_ = $type$.getDefaultInstance();\n");
+ "private $type$ $name$_ = null;\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
printer->Print(variables_,
@@ -208,22 +273,29 @@ GenerateBuilderMembers(io::Printer* printer) const {
// field of type "Field" called "Field".
// boolean hasField()
- printer->Print(variables_,
- "$deprecation$public boolean has$capitalized_name$() {\n"
- " return $get_has_field_bit_builder$;\n"
- "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ if (support_field_presence) {
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_builder$;\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $name$Builder_ != null || $name$_ != null;\n"
+ "}\n");
+ }
// Field getField()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public $type$ get$capitalized_name$()",
-
- "return $name$_;\n",
-
+ "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n",
"return $name$Builder_.getMessage();\n",
-
NULL);
// Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder set$capitalized_name$($type$ value)",
@@ -235,10 +307,11 @@ GenerateBuilderMembers(io::Printer* printer) const {
"$name$Builder_.setMessage(value);\n",
- "$set_has_field_bit_builder$;\n"
+ "$set_has_field_bit_builder$\n"
"return this;\n");
// Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder set$capitalized_name$(\n"
" $type$.Builder builderForValue)",
@@ -248,60 +321,80 @@ GenerateBuilderMembers(io::Printer* printer) const {
"$name$Builder_.setMessage(builderForValue.build());\n",
- "$set_has_field_bit_builder$;\n"
+ "$set_has_field_bit_builder$\n"
"return this;\n");
// Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder merge$capitalized_name$($type$ value)",
- "if ($get_has_field_bit_builder$ &&\n"
- " $name$_ != $type$.getDefaultInstance()) {\n"
- " $name$_ =\n"
- " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n"
- "} else {\n"
- " $name$_ = value;\n"
- "}\n"
- "$on_changed$\n",
+ 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"
+ "} else {\n"
+ " $name$_ = value;\n"
+ "}\n"
+ "$on_changed$\n"
+ : "if ($name$_ != null) {\n"
+ " $name$_ =\n"
+ " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n"
+ "} else {\n"
+ " $name$_ = value;\n"
+ "}\n"
+ "$on_changed$\n",
"$name$Builder_.mergeFrom(value);\n",
- "$set_has_field_bit_builder$;\n"
+ "$set_has_field_bit_builder$\n"
"return this;\n");
// Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder clear$capitalized_name$()",
- "$name$_ = $type$.getDefaultInstance();\n"
+ "$name$_ = null;\n"
"$on_changed$\n",
- "$name$Builder_.clear();\n",
+ support_field_presence
+ ? "$name$Builder_.clear();\n"
+ : "$name$_ = null;\n"
+ "$name$Builder_ = null;\n",
- "$clear_has_field_bit_builder$;\n"
+ "$clear_has_field_bit_builder$\n"
"return this;\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
- " $set_has_field_bit_builder$;\n"
+ " $set_has_field_bit_builder$\n"
" $on_changed$\n"
" return get$capitalized_name$FieldBuilder().getBuilder();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
" if ($name$Builder_ != null) {\n"
" return $name$Builder_.getMessageOrBuilder();\n"
" } else {\n"
- " return $name$_;\n"
+ " return $name$_ == null ?\n"
+ " $type$.getDefaultInstance() : $name$_;\n"
" }\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"private com.google.protobuf.SingleFieldBuilder<\n"
" $type$, $type$.Builder, $type$OrBuilder> \n"
" get$capitalized_name$FieldBuilder() {\n"
" if ($name$Builder_ == null) {\n"
" $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
" $type$, $type$.Builder, $type$OrBuilder>(\n"
- " $name$_,\n"
+ " get$capitalized_name$(),\n"
" getParentForChildren(),\n"
" isClean());\n"
" $name$_ = null;\n"
@@ -311,28 +404,36 @@ GenerateBuilderMembers(io::Printer* printer) const {
}
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
- printer->Print(variables_,
- "get$capitalized_name$FieldBuilder();\n");
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "get$capitalized_name$FieldBuilder();\n");
+ }
}
-void MessageFieldGenerator::
-GenerateInitializationCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n");
-}
+void ImmutableMessageFieldGenerator::
+GenerateInitializationCode(io::Printer* printer) const {}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateBuilderClearCode(io::Printer* printer) const {
- PrintNestedBuilderCondition(printer,
- "$name$_ = $type$.getDefaultInstance();\n",
+ if (SupportFieldPresence(descriptor_->file())) {
+ PrintNestedBuilderCondition(printer,
+ "$name$_ = null;\n",
- "$name$Builder_.clear();\n");
- printer->Print(variables_, "$clear_has_field_bit_builder$;\n");
+ "$name$Builder_.clear();\n");
+ printer->Print(variables_, "$clear_has_field_bit_builder$\n");
+ } else {
+ PrintNestedBuilderCondition(printer,
+ "$name$_ = null;\n",
+
+ "$name$_ = null;\n"
+ "$name$Builder_ = null;\n");
+ }
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
printer->Print(variables_,
"if (other.has$capitalized_name$()) {\n"
@@ -340,13 +441,14 @@ GenerateMergingCode(io::Printer* printer) const {
"}\n");
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
-
- printer->Print(variables_,
- "if ($get_has_field_bit_from_local$) {\n"
- " $set_has_field_bit_to_local$;\n"
- "}\n");
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "if ($get_has_field_bit_from_local$) {\n"
+ " $set_has_field_bit_to_local$;\n"
+ "}\n");
+ }
PrintNestedBuilderCondition(printer,
"result.$name$_ = $name$_;\n",
@@ -354,120 +456,421 @@ GenerateBuildingCode(io::Printer* printer) const {
"result.$name$_ = $name$Builder_.build();\n");
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "$type$.Builder subBuilder = $type$.newBuilder();\n"
- "if (has$capitalized_name$()) {\n"
- " subBuilder.mergeFrom(get$capitalized_name$());\n"
+ "$type$.Builder subBuilder = null;\n"
+ "if ($is_field_present_message$) {\n"
+ " subBuilder = $name$_.toBuilder();\n"
"}\n");
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
printer->Print(variables_,
- "input.readGroup($number$, subBuilder, extensionRegistry);\n");
+ "$name$_ = input.readGroup($number$, $type$.PARSER,\n"
+ " extensionRegistry);\n");
} else {
printer->Print(variables_,
- "input.readMessage(subBuilder, extensionRegistry);\n");
+ "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
}
printer->Print(variables_,
- "set$capitalized_name$(subBuilder.buildPartial());\n");
+ "if (subBuilder != null) {\n"
+ " subBuilder.mergeFrom($name$_);\n"
+ " $name$_ = subBuilder.buildPartial();\n"
+ "}\n"
+ "$set_has_field_bit_message$\n");
+}
+
+void ImmutableMessageFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for messages.
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
- " output.write$group_or_message$($number$, $name$_);\n"
+ "if ($is_field_present_message$) {\n"
+ " output.write$group_or_message$($number$, get$capitalized_name$());\n"
"}\n");
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
+ "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");
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"result = result && get$capitalized_name$()\n"
" .equals(other.get$capitalized_name$());\n");
}
-void MessageFieldGenerator::
+void ImmutableMessageFieldGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(variables_,
"hash = (37 * hash) + $constant_name$;\n"
"hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
}
-string MessageFieldGenerator::GetBoxedType() const {
- return ClassName(descriptor_->message_type());
+string ImmutableMessageFieldGenerator::GetBoxedType() const {
+ return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+// ===================================================================
+
+ImmutableMessageOneofFieldGenerator::
+ImmutableMessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableMessageFieldGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableMessageOneofFieldGenerator::
+~ImmutableMessageOneofFieldGenerator() {}
+
+void ImmutableMessageOneofFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\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"
+ " }\n"
+ " return $type$.getDefaultInstance();\n"
+ "}\n");
+
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($type$) $oneof_name$_;\n"
+ " }\n"
+ " return $type$.getDefaultInstance();\n"
+ "}\n");
+ }
+}
+
+void ImmutableMessageOneofFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ // When using nested-builders, the code initially works just like the
+ // non-nested builder case. It only creates a nested builder lazily on
+ // demand and then forever delegates to it after creation.
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ printer->Print(variables_,
+ // If this builder is non-null, it is used and the other fields are
+ // ignored.
+ "private com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
+ "\n");
+ }
+
+ // The comments above the methods below are based on a hypothetical
+ // field of type "Field" called "Field".
+
+ if (SupportFieldPresence(descriptor_->file())) {
+ // boolean hasField()
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ }
+
+ // Field getField()
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public $type$ get$capitalized_name$()",
+
+ "if ($has_oneof_case_message$) {\n"
+ " return ($type$) $oneof_name$_;\n"
+ "}\n"
+ "return $type$.getDefaultInstance();\n",
+
+ "if ($has_oneof_case_message$) {\n"
+ " return $name$Builder_.getMessage();\n"
+ "}\n"
+ "return $type$.getDefaultInstance();\n",
+
+ NULL);
+
+ // Field.Builder setField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder set$capitalized_name$($type$ value)",
+
+ "if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ "}\n"
+ "$oneof_name$_ = value;\n"
+ "$on_changed$\n",
+
+ "$name$Builder_.setMessage(value);\n",
+
+ "$set_oneof_case_message$;\n"
+ "return this;\n");
+
+ // Field.Builder setField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " $type$.Builder builderForValue)",
+
+ "$oneof_name$_ = builderForValue.build();\n"
+ "$on_changed$\n",
+
+ "$name$Builder_.setMessage(builderForValue.build());\n",
+
+ "$set_oneof_case_message$;\n"
+ "return this;\n");
+
+ // Field.Builder mergeField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder merge$capitalized_name$($type$ value)",
+
+ "if ($has_oneof_case_message$ &&\n"
+ " $oneof_name$_ != $type$.getDefaultInstance()) {\n"
+ " $oneof_name$_ = $type$.newBuilder(($type$) $oneof_name$_)\n"
+ " .mergeFrom(value).buildPartial();\n"
+ "} else {\n"
+ " $oneof_name$_ = value;\n"
+ "}\n"
+ "$on_changed$\n",
+
+ "if ($has_oneof_case_message$) {\n"
+ " $name$Builder_.mergeFrom(value);\n"
+ "}\n"
+ "$name$Builder_.setMessage(value);\n",
+
+ "$set_oneof_case_message$;\n"
+ "return this;\n");
+
+ // Field.Builder clearField()
+ WriteFieldDocComment(printer, descriptor_);
+ PrintNestedBuilderFunction(printer,
+ "$deprecation$public Builder clear$capitalized_name$()",
+
+ "if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " $on_changed$\n"
+ "}\n",
+
+ "if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ "}\n"
+ "$name$Builder_.clear();\n",
+
+ "return this;\n");
+
+ if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
+ " return get$capitalized_name$FieldBuilder().getBuilder();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+ " if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n"
+ " return $name$Builder_.getMessageOrBuilder();\n"
+ " } else {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($type$) $oneof_name$_;\n"
+ " }\n"
+ " return $type$.getDefaultInstance();\n"
+ " }\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "private com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder> \n"
+ " get$capitalized_name$FieldBuilder() {\n"
+ " if ($name$Builder_ == null) {\n"
+ " if (!($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = $type$.getDefaultInstance();\n"
+ " }\n"
+ " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+ " $type$, $type$.Builder, $type$OrBuilder>(\n"
+ " ($type$) $oneof_name$_,\n"
+ " getParentForChildren(),\n"
+ " isClean());\n"
+ " $oneof_name$_ = null;\n"
+ " }\n"
+ " $set_oneof_case_message$;\n"
+ " $on_changed$;\n"
+ " return $name$Builder_;\n"
+ "}\n");
+ }
+}
+
+void ImmutableMessageOneofFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n");
+ printer->Indent();
+
+ PrintNestedBuilderCondition(printer,
+ "result.$oneof_name$_ = $oneof_name$_;\n",
+
+ "result.$oneof_name$_ = $name$Builder_.build();\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableMessageOneofFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "merge$capitalized_name$(other.get$capitalized_name$());\n");
+}
+
+void ImmutableMessageOneofFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$type$.Builder subBuilder = null;\n"
+ "if ($has_oneof_case_message$) {\n"
+ " subBuilder = (($type$) $oneof_name$_).toBuilder();\n"
+ "}\n");
+
+ if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n"
+ " extensionRegistry);\n");
+ } else {
+ printer->Print(variables_,
+ "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
+ }
+
+ printer->Print(variables_,
+ "if (subBuilder != null) {\n"
+ " subBuilder.mergeFrom(($type$) $oneof_name$_);\n"
+ " $oneof_name$_ = subBuilder.buildPartial();\n"
+ "}\n");
+ printer->Print(variables_,
+ "$set_oneof_case_message$;\n");
+}
+
+void ImmutableMessageOneofFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.write$group_or_message$($number$, ($type$) $oneof_name$_);\n"
+ "}\n");
+}
+
+void ImmutableMessageOneofFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$group_or_message$Size($number$, ($type$) $oneof_name$_);\n"
+ "}\n");
}
// ===================================================================
-RepeatedMessageFieldGenerator::
-RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex,
- int builderBitIndex)
+RepeatedImmutableMessageFieldGenerator::
+RepeatedImmutableMessageFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
- builderBitIndex_(builderBitIndex) {
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
- &variables_);
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
}
-RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+RepeatedImmutableMessageFieldGenerator::
+~RepeatedImmutableMessageFieldGenerator() {}
-int RepeatedMessageFieldGenerator::GetNumBitsForMessage() const {
+int RepeatedImmutableMessageFieldGenerator::GetNumBitsForMessage() const {
return 0;
}
-int RepeatedMessageFieldGenerator::GetNumBitsForBuilder() const {
+int RepeatedImmutableMessageFieldGenerator::GetNumBitsForBuilder() const {
return 1;
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
// TODO(jonp): In the future, consider having methods specific to the
// interface so that builders can choose dynamically to either return a
// message or a nested builder, so that asking for the interface doesn't
// cause a message to ever be built.
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$java.util.List<$type$> \n"
- " get$capitalized_name$List();\n"
- "$deprecation$$type$ get$capitalized_name$(int index);\n"
+ " get$capitalized_name$List();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$$type$ get$capitalized_name$(int index);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$int get$capitalized_name$Count();\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$java.util.List<? extends $type$OrBuilder> \n"
- " get$capitalized_name$OrBuilderList();\n"
+ " get$capitalized_name$OrBuilderList();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n"
" int index);\n");
}
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private java.util.List<$type$> $name$_;\n"
+ "private java.util.List<$type$> $name$_;\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
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
" get$capitalized_name$OrBuilderList() {\n"
" return $name$_;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
" int index) {\n"
" return $name$_.get(index);\n"
@@ -475,7 +878,7 @@ GenerateMembers(io::Printer* printer) const {
}
-void RepeatedMessageFieldGenerator::PrintNestedBuilderCondition(
+void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderCondition(
io::Printer* printer,
const char* regular_case,
const char* nested_builder_case) const {
@@ -494,7 +897,7 @@ void RepeatedMessageFieldGenerator::PrintNestedBuilderCondition(
}
}
-void RepeatedMessageFieldGenerator::PrintNestedBuilderFunction(
+void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderFunction(
io::Printer* printer,
const char* method_prototype,
const char* regular_case,
@@ -511,7 +914,7 @@ void RepeatedMessageFieldGenerator::PrintNestedBuilderFunction(
printer->Print("}\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
// When using nested-builders, the code initially works just like the
// non-nested builder case. It only creates a nested builder lazily on
@@ -552,6 +955,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
// repeated field of type "Field" called "RepeatedField".
// List<Field> getRepeatedFieldList()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public java.util.List<$type$> get$capitalized_name$List()",
@@ -561,6 +965,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
NULL);
// int getRepeatedFieldCount()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public int get$capitalized_name$Count()",
@@ -570,6 +975,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
NULL);
// Field getRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public $type$ get$capitalized_name$(int index)",
@@ -580,6 +986,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
NULL);
// Builder setRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder set$capitalized_name$(\n"
" int index, $type$ value)",
@@ -593,6 +1000,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder setRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder set$capitalized_name$(\n"
" int index, $type$.Builder builderForValue)",
@@ -606,6 +1014,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addRepeatedField(Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder add$capitalized_name$($type$ value)",
@@ -622,6 +1031,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addRepeatedField(int index, Field value)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder add$capitalized_name$(\n"
" int index, $type$ value)",
@@ -638,6 +1048,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addRepeatedField(Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder add$capitalized_name$(\n"
" $type$.Builder builderForValue)",
@@ -651,6 +1062,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addRepeatedField(int index, Field.Builder builderForValue)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder add$capitalized_name$(\n"
" int index, $type$.Builder builderForValue)",
@@ -664,12 +1076,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder addAllRepeatedField(Iterable<Field> values)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder addAll$capitalized_name$(\n"
" java.lang.Iterable<? extends $type$> values)",
"ensure$capitalized_name$IsMutable();\n"
- "super.addAll(values, $name$_);\n"
+ "com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
+ " values, $name$_);\n"
"$on_changed$\n",
"$name$Builder_.addAllMessages(values);\n",
@@ -677,6 +1091,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder clearAllRepeatedField()
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder clear$capitalized_name$()",
@@ -689,6 +1104,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
// Builder removeRepeatedField(int index)
+ WriteFieldDocComment(printer, descriptor_);
PrintNestedBuilderFunction(printer,
"$deprecation$public Builder remove$capitalized_name$(int index)",
@@ -701,12 +1117,15 @@ GenerateBuilderMembers(io::Printer* printer) const {
"return this;\n");
if (HasNestedBuilders(descriptor_->containing_type())) {
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
" int index) {\n"
" return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
" int index) {\n"
" if ($name$Builder_ == null) {\n"
@@ -714,8 +1133,10 @@ GenerateBuilderMembers(io::Printer* printer) const {
" } else {\n"
" return $name$Builder_.getMessageOrBuilder(index);\n"
" }\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
" get$capitalized_name$OrBuilderList() {\n"
" if ($name$Builder_ != null) {\n"
@@ -723,17 +1144,23 @@ GenerateBuilderMembers(io::Printer* printer) const {
" } else {\n"
" return java.util.Collections.unmodifiableList($name$_);\n"
" }\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
" return get$capitalized_name$FieldBuilder().addBuilder(\n"
" $type$.getDefaultInstance());\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
" int index) {\n"
" return get$capitalized_name$FieldBuilder().addBuilder(\n"
" index, $type$.getDefaultInstance());\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<$type$.Builder> \n"
" get$capitalized_name$BuilderList() {\n"
" return get$capitalized_name$FieldBuilder().getBuilderList();\n"
@@ -755,18 +1182,18 @@ GenerateBuilderMembers(io::Printer* printer) const {
}
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
printer->Print(variables_,
"get$capitalized_name$FieldBuilder();\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateInitializationCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateBuilderClearCode(io::Printer* printer) const {
PrintNestedBuilderCondition(printer,
"$name$_ = java.util.Collections.emptyList();\n"
@@ -775,7 +1202,7 @@ GenerateBuilderClearCode(io::Printer* printer) const {
"$name$Builder_.clear();\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
// The code below does two optimizations (non-nested builder case):
// 1. If the other list is empty, there's nothing to do. This ensures we
@@ -809,7 +1236,7 @@ GenerateMergingCode(io::Printer* printer) const {
"}\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
// The code below (non-nested builder case) ensures that the result has an
// immutable list. If our list is immutable, we can just reuse it. If not,
@@ -824,24 +1251,33 @@ GenerateBuildingCode(io::Printer* printer) const {
"result.$name$_ = $name$Builder_.build();\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "$type$.Builder subBuilder = $type$.newBuilder();\n");
+ "if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ = new java.util.ArrayList<$type$>();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n");
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
printer->Print(variables_,
- "input.readGroup($number$, subBuilder, extensionRegistry);\n");
+ "$name$_.add(input.readGroup($number$, $type$.PARSER,\n"
+ " extensionRegistry));\n");
} else {
printer->Print(variables_,
- "input.readMessage(subBuilder, extensionRegistry);\n");
+ "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n");
}
+}
+void RepeatedImmutableMessageFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
printer->Print(variables_,
- "add$capitalized_name$(subBuilder.buildPartial());\n");
+ "if ($get_mutable_bit_parser$) {\n"
+ " $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+ "}\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
printer->Print(variables_,
"for (int i = 0; i < $name$_.size(); i++) {\n"
@@ -849,7 +1285,7 @@ GenerateSerializationCode(io::Printer* printer) const {
"}\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
"for (int i = 0; i < $name$_.size(); i++) {\n"
@@ -858,14 +1294,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"}\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"result = result && get$capitalized_name$List()\n"
" .equals(other.get$capitalized_name$List());\n");
}
-void RepeatedMessageFieldGenerator::
+void RepeatedImmutableMessageFieldGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(variables_,
"if (get$capitalized_name$Count() > 0) {\n"
@@ -874,8 +1310,8 @@ GenerateHashCode(io::Printer* printer) const {
"}\n");
}
-string RepeatedMessageFieldGenerator::GetBoxedType() const {
- return ClassName(descriptor_->message_type());
+string RepeatedImmutableMessageFieldGenerator::GetBoxedType() const {
+ return name_resolver_->GetImmutableClassName(descriptor_->message_type());
}
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h
index 2efbcd97..ea8225a5 100644
--- a/src/google/protobuf/compiler/java/java_message_field.h
+++ b/src/google/protobuf/compiler/java/java_message_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -41,16 +41,26 @@
namespace google {
namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+}
+
+namespace protobuf {
namespace compiler {
namespace java {
-class MessageFieldGenerator : public FieldGenerator {
+class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
public:
- explicit MessageFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex, int builderBitIndex);
- ~MessageFieldGenerator();
+ explicit ImmutableMessageFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableMessageFieldGenerator();
- // implements FieldGenerator ---------------------------------------
+ // implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const;
int GetNumBitsForBuilder() const;
void GenerateInterfaceMembers(io::Printer* printer) const;
@@ -61,6 +71,7 @@ class MessageFieldGenerator : public FieldGenerator {
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;
@@ -69,13 +80,13 @@ class MessageFieldGenerator : public FieldGenerator {
string GetBoxedType() const;
- private:
+ protected:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
const int messageBitIndex_;
const int builderBitIndex_;
-
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+ Context* context_;
+ ClassNameResolver* name_resolver_;
void PrintNestedBuilderCondition(io::Printer* printer,
const char* regular_case, const char* nested_builder_case) const;
@@ -83,15 +94,39 @@ class MessageFieldGenerator : public FieldGenerator {
const char* method_prototype, const char* regular_case,
const char* nested_builder_case,
const char* trailing_code) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldGenerator);
};
-class RepeatedMessageFieldGenerator : public FieldGenerator {
+class ImmutableMessageOneofFieldGenerator
+ : public ImmutableMessageFieldGenerator {
public:
- explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex, int builderBitIndex);
- ~RepeatedMessageFieldGenerator();
+ ImmutableMessageOneofFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableMessageOneofFieldGenerator();
- // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldGenerator);
+};
+
+class RepeatedImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
+ public:
+ explicit RepeatedImmutableMessageFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~RepeatedImmutableMessageFieldGenerator();
+
+ // implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const;
int GetNumBitsForBuilder() const;
void GenerateInterfaceMembers(io::Printer* printer) const;
@@ -102,6 +137,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
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;
@@ -110,13 +146,13 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
string GetBoxedType() const;
- private:
+ protected:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
const int messageBitIndex_;
const int builderBitIndex_;
-
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+ Context* context_;
+ ClassNameResolver* name_resolver_;
void PrintNestedBuilderCondition(io::Printer* printer,
const char* regular_case, const char* nested_builder_case) const;
@@ -124,6 +160,9 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
const char* method_prototype, const char* regular_case,
const char* nested_builder_case,
const char* trailing_code) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableMessageFieldGenerator);
};
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc
new file mode 100644
index 00000000..0c363f9f
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_name_resolver.cc
@@ -0,0 +1,266 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+// A suffix that will be appended to the file's outer class name if the name
+// conflicts with some other types defined in the file.
+const char* kOuterClassNameSuffix = "OuterClass";
+
+// Strip package name from a descriptor's full name.
+// For example:
+// Full name : foo.Bar.Baz
+// Package name: foo
+// After strip : Bar.Baz
+string StripPackageName(const string& full_name,
+ const FileDescriptor* file) {
+ if (file->package().empty()) {
+ return full_name;
+ } else {
+ // Strip package name
+ return full_name.substr(file->package().size() + 1);
+ }
+}
+
+// Get the name of a message's Java class without package name prefix.
+string ClassNameWithoutPackage(const Descriptor* descriptor,
+ bool immutable) {
+ return StripPackageName(descriptor->full_name(),
+ descriptor->file());
+}
+
+// Get the name of an enum's Java class without package name prefix.
+string ClassNameWithoutPackage(const EnumDescriptor* descriptor,
+ bool immutable) {
+ // Doesn't append "Mutable" for enum type's name.
+ const Descriptor* message_descriptor = descriptor->containing_type();
+ if (message_descriptor == NULL) {
+ return descriptor->name();
+ } else {
+ return ClassNameWithoutPackage(message_descriptor, immutable) +
+ "." + descriptor->name();
+ }
+}
+
+// Get the name of a service's Java class without package name prefix.
+string ClassNameWithoutPackage(const ServiceDescriptor* descriptor,
+ bool immutable) {
+ string full_name = StripPackageName(descriptor->full_name(),
+ descriptor->file());
+ // We don't allow nested service definitions.
+ GOOGLE_CHECK(full_name.find('.') == string::npos);
+ return full_name;
+}
+
+// Check whether a given message or its nested types has the given class name.
+bool MessageHasConflictingClassName(const Descriptor* message,
+ const string& classname) {
+ if (message->name() == classname) return true;
+ for (int i = 0; i < message->nested_type_count(); ++i) {
+ if (MessageHasConflictingClassName(message->nested_type(i), classname)) {
+ return true;
+ }
+ }
+ for (int i = 0; i < message->enum_type_count(); ++i) {
+ if (message->enum_type(i)->name() == classname) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+ClassNameResolver::ClassNameResolver() {
+}
+
+ClassNameResolver::~ClassNameResolver() {
+}
+
+string ClassNameResolver::GetFileDefaultImmutableClassName(
+ const FileDescriptor* file) {
+ string basename;
+ string::size_type last_slash = file->name().find_last_of('/');
+ if (last_slash == string::npos) {
+ basename = file->name();
+ } else {
+ basename = file->name().substr(last_slash + 1);
+ }
+ return UnderscoresToCamelCase(StripProto(basename), true);
+}
+
+string ClassNameResolver::GetFileImmutableClassName(
+ const FileDescriptor* file) {
+ string& class_name = file_immutable_outer_class_names_[file];
+ if (class_name.empty()) {
+ if (file->options().has_java_outer_classname()) {
+ class_name = file->options().java_outer_classname();
+ } else {
+ class_name = GetFileDefaultImmutableClassName(file);
+ if (HasConflictingClassName(file, class_name)) {
+ class_name += kOuterClassNameSuffix;
+ }
+ }
+ }
+ return class_name;
+}
+
+string ClassNameResolver::GetFileClassName(const FileDescriptor* file,
+ bool immutable) {
+ if (immutable) {
+ return GetFileImmutableClassName(file);
+ } else {
+ return "Mutable" + GetFileImmutableClassName(file);
+ }
+}
+
+// Check whether there is any type defined in the proto file that has
+// the given class name.
+bool ClassNameResolver::HasConflictingClassName(
+ const FileDescriptor* file, const string& classname) {
+ for (int i = 0; i < file->enum_type_count(); i++) {
+ if (file->enum_type(i)->name() == classname) {
+ return true;
+ }
+ }
+ for (int i = 0; i < file->service_count(); i++) {
+ if (file->service(i)->name() == classname) {
+ return true;
+ }
+ }
+ for (int i = 0; i < file->message_type_count(); i++) {
+ if (MessageHasConflictingClassName(file->message_type(i), classname)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+string ClassNameResolver::GetDescriptorClassName(
+ const FileDescriptor* descriptor) {
+ return GetFileImmutableClassName(descriptor);
+}
+
+string ClassNameResolver::GetClassName(const FileDescriptor* descriptor,
+ bool immutable) {
+ string result = FileJavaPackage(descriptor, immutable);
+ if (!result.empty()) result += '.';
+ result += GetFileClassName(descriptor, immutable);
+ return result;
+}
+
+// Get the full name of a Java class by prepending the Java package name
+// or outer class name.
+string ClassNameResolver::GetClassFullName(const string& name_without_package,
+ const FileDescriptor* file,
+ bool immutable,
+ bool multiple_files) {
+ string result;
+ if (multiple_files) {
+ result = FileJavaPackage(file, immutable);
+ } else {
+ result = GetClassName(file, immutable);
+ }
+ if (!result.empty()) {
+ result += '.';
+ }
+ result += name_without_package;
+ return result;
+}
+
+string ClassNameResolver::GetClassName(const Descriptor* descriptor,
+ bool immutable) {
+ return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
+ descriptor->file(), immutable,
+ MultipleJavaFiles(descriptor->file(), immutable));
+}
+
+string ClassNameResolver::GetClassName(const EnumDescriptor* descriptor,
+ bool immutable) {
+ return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
+ descriptor->file(), immutable,
+ MultipleJavaFiles(descriptor->file(), immutable));
+}
+
+string ClassNameResolver::GetClassName(const ServiceDescriptor* descriptor,
+ bool immutable) {
+ return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
+ descriptor->file(), immutable,
+ MultipleJavaFiles(descriptor->file(), immutable));
+}
+
+// Get the Java Class style full name of a message.
+string ClassNameResolver::GetJavaClassFullName(
+ const string& name_without_package,
+ const FileDescriptor* file,
+ bool immutable) {
+ string result;
+ if (MultipleJavaFiles(file, immutable)) {
+ result = FileJavaPackage(file, immutable);
+ if (!result.empty()) result += '.';
+ } else {
+ result = GetClassName(file, immutable);
+ if (!result.empty()) result += '$';
+ }
+ result += StringReplace(name_without_package, ".", "$", true);
+ return result;
+}
+
+string ClassNameResolver::GetExtensionIdentifierName(
+ const FieldDescriptor* descriptor, bool immutable) {
+ return GetClassName(descriptor->containing_type(), immutable) + "." +
+ descriptor->name();
+}
+
+
+string ClassNameResolver::GetJavaImmutableClassName(
+ const Descriptor* descriptor) {
+ return GetJavaClassFullName(
+ ClassNameWithoutPackage(descriptor, true),
+ descriptor->file(), true);
+}
+
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h
new file mode 100644
index 00000000..ab60b0a0
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_name_resolver.h
@@ -0,0 +1,124 @@
+// 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_NAME_RESOLVER_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+class Descriptor;
+class EnumDescriptor;
+class FieldDescriptor;
+class FileDescriptor;
+class ServiceDescriptor;
+
+namespace compiler {
+namespace java {
+
+// Used to get the Java class related names for a given descriptor. It caches
+// the results to avoid redundant calculation across multiple name queries.
+// Thread-safety note: This class is *not* thread-safe.
+class ClassNameResolver {
+ public:
+ ClassNameResolver();
+ ~ClassNameResolver();
+
+ // Gets the unqualified outer class name for the file.
+ string GetFileClassName(const FileDescriptor* file, bool immutable);
+ // Gets the unqualified immutable outer class name of a file.
+ string GetFileImmutableClassName(const FileDescriptor* file);
+ // Gets the unqualified default immutable outer class name of a file
+ // (converted from the proto file's name).
+ string GetFileDefaultImmutableClassName(const FileDescriptor* file);
+
+ // Check whether there is any type defined in the proto file that has
+ // the given class name.
+ bool HasConflictingClassName(const FileDescriptor* file,
+ const string& classname);
+
+ // Gets the name of the outer class that holds descriptor information.
+ // Descriptors are shared between immutable messages and mutable messages.
+ // Since both of them are generated optionally, the descriptors need to be
+ // put in another common place.
+ string GetDescriptorClassName(const FileDescriptor* file);
+
+ // Gets the fully-qualified class name corresponding to the given descriptor.
+ string GetClassName(const Descriptor* descriptor, bool immutable);
+ string GetClassName(const EnumDescriptor* descriptor, bool immutable);
+ string GetClassName(const ServiceDescriptor* descriptor, bool immutable);
+ string GetClassName(const FileDescriptor* descriptor, bool immutable);
+
+ template<class DescriptorType>
+ string GetImmutableClassName(const DescriptorType* descriptor) {
+ return GetClassName(descriptor, true);
+ }
+ template<class DescriptorType>
+ string GetMutableClassName(const DescriptorType* descriptor) {
+ return GetClassName(descriptor, false);
+ }
+
+ // Gets the fully qualified name of an extension identifier.
+ string GetExtensionIdentifierName(const FieldDescriptor* descriptor,
+ bool immutable);
+
+ // Gets the fully qualified name for generated classes in Java convention.
+ // Nested classes will be separated using '$' instead of '.'
+ // For example:
+ // com.package.OuterClass$OuterMessage$InnerMessage
+ string GetJavaImmutableClassName(const Descriptor* descriptor);
+ private:
+ // Get the full name of a Java class by prepending the Java package name
+ // or outer class name.
+ string GetClassFullName(const string& name_without_package,
+ const FileDescriptor* file,
+ bool immutable,
+ bool multiple_files);
+ // Get the Java Class style full name of a message.
+ string GetJavaClassFullName(
+ const string& name_without_package,
+ const FileDescriptor* file,
+ bool immutable);
+ // Caches the result to provide better performance.
+ map<const FileDescriptor*, string> file_immutable_outer_class_names_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ClassNameResolver);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__
diff --git a/src/google/protobuf/compiler/java/java_names.h b/src/google/protobuf/compiler/java/java_names.h
new file mode 100644
index 00000000..0d614335
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_names.h
@@ -0,0 +1,87 @@
+// 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.
+//
+// Provides a mechanism for mapping a descriptor to the
+// fully-qualified name of the corresponding Java class.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class FileDescriptor;
+class ServiceDescriptor;
+
+namespace compiler {
+namespace java {
+
+// Requires:
+// descriptor != NULL
+//
+// Returns:
+// The fully-qualified Java class name.
+string ClassName(const Descriptor* descriptor);
+
+// Requires:
+// descriptor != NULL
+//
+// Returns:
+// The fully-qualified Java class name.
+string ClassName(const EnumDescriptor* descriptor);
+
+// Requires:
+// descriptor != NULL
+//
+// Returns:
+// The fully-qualified Java class name.
+string ClassName(const FileDescriptor* descriptor);
+
+// Requires:
+// descriptor != NULL
+//
+// Returns:
+// The fully-qualified Java class name.
+string ClassName(const ServiceDescriptor* descriptor);
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc
index ccc94c9d..fe527623 100644
--- a/src/google/protobuf/compiler/java/java_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,6 +34,11 @@
// It seemed like parameterizing it would add more complexity than it is
// worth.
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
#include <google/protobuf/compiler/java/java_generator.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/io/zero_copy_stream.h>
@@ -70,8 +75,8 @@ class TestGenerator : public CodeGenerator {
void TryInsert(const string& filename, const string& insertion_point,
GeneratorContext* context) const {
- scoped_ptr<io::ZeroCopyOutputStream> output(
- context->OpenForInsert(filename, insertion_point));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->OpenForInsert(filename, insertion_point));
io::Printer printer(output.get(), '$');
printer.Print("// inserted $name$\n", "name", insertion_point);
}
@@ -81,16 +86,16 @@ class TestGenerator : public CodeGenerator {
// not verify that they are correctly-placed; that would require actually
// compiling the output which is a bit more than I care to do for this test.
TEST(JavaPluginTest, PluginTest) {
- File::WriteStringToFileOrDie(
- "syntax = \"proto2\";\n"
- "package foo;\n"
- "option java_package = \"\";\n"
- "option java_outer_classname = \"Test\";\n"
- "message Bar {\n"
- " message Baz {}\n"
- "}\n"
- "enum Qux { BLAH = 1; }\n",
- TestTempDir() + "/test.proto");
+ GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
+ "syntax = \"proto2\";\n"
+ "package foo;\n"
+ "option java_package = \"\";\n"
+ "option java_outer_classname = \"Test\";\n"
+ "message Bar {\n"
+ " message Baz {}\n"
+ "}\n"
+ "enum Qux { BLAH = 1; }\n",
+ true));
google::protobuf::compiler::CommandLineInterface cli;
cli.SetInputsAreProtoPathRelative(true);
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index addb8819..48757c60 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,9 +35,12 @@
#include <map>
#include <string>
-#include <google/protobuf/compiler/java/java_primitive_field.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_primitive_field.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
@@ -52,127 +55,25 @@ 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;
-}
-
-bool IsReferenceType(JavaType type) {
- switch (type) {
- case JAVATYPE_INT : return false;
- case JAVATYPE_LONG : return false;
- case JAVATYPE_FLOAT : return false;
- case JAVATYPE_DOUBLE : return false;
- case JAVATYPE_BOOLEAN: return false;
- case JAVATYPE_STRING : return true;
- case JAVATYPE_BYTES : return true;
- case JAVATYPE_ENUM : return true;
- case JAVATYPE_MESSAGE: return true;
-
- // No default because we want the compiler to complain if any new
- // JavaTypes are added.
- }
-
- GOOGLE_LOG(FATAL) << "Can't get here.";
- return false;
-}
-
-const char* GetCapitalizedType(const FieldDescriptor* field) {
- switch (GetType(field)) {
- case FieldDescriptor::TYPE_INT32 : return "Int32" ;
- case FieldDescriptor::TYPE_UINT32 : return "UInt32" ;
- case FieldDescriptor::TYPE_SINT32 : return "SInt32" ;
- case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ;
- case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
- case FieldDescriptor::TYPE_INT64 : return "Int64" ;
- case FieldDescriptor::TYPE_UINT64 : return "UInt64" ;
- case FieldDescriptor::TYPE_SINT64 : return "SInt64" ;
- case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ;
- case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
- case FieldDescriptor::TYPE_FLOAT : return "Float" ;
- case FieldDescriptor::TYPE_DOUBLE : return "Double" ;
- case FieldDescriptor::TYPE_BOOL : return "Bool" ;
- case FieldDescriptor::TYPE_STRING : return "String" ;
- case FieldDescriptor::TYPE_BYTES : return "Bytes" ;
- case FieldDescriptor::TYPE_ENUM : return "Enum" ;
- case FieldDescriptor::TYPE_GROUP : return "Group" ;
- case FieldDescriptor::TYPE_MESSAGE : return "Message" ;
-
- // No default because we want the compiler to complain if any new
- // types are added.
- }
-
- GOOGLE_LOG(FATAL) << "Can't get here.";
- return NULL;
-}
-
-// For encodings with fixed sizes, returns that size in bytes. Otherwise
-// returns -1.
-int FixedSize(FieldDescriptor::Type type) {
- switch (type) {
- case FieldDescriptor::TYPE_INT32 : return -1;
- case FieldDescriptor::TYPE_INT64 : return -1;
- case FieldDescriptor::TYPE_UINT32 : return -1;
- case FieldDescriptor::TYPE_UINT64 : return -1;
- case FieldDescriptor::TYPE_SINT32 : return -1;
- case FieldDescriptor::TYPE_SINT64 : return -1;
- case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
- case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
- case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
- case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
- case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize;
- case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize;
-
- case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
- case FieldDescriptor::TYPE_ENUM : return -1;
-
- case FieldDescriptor::TYPE_STRING : return -1;
- case FieldDescriptor::TYPE_BYTES : return -1;
- case FieldDescriptor::TYPE_GROUP : return -1;
- case FieldDescriptor::TYPE_MESSAGE : return -1;
-
- // No default because we want the compiler to complain if any new
- // types are added.
- }
- GOOGLE_LOG(FATAL) << "Can't get here.";
- return -1;
-}
-
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
map<string, string>* variables) {
- (*variables)["name"] =
- UnderscoresToCamelCase(descriptor);
- (*variables)["capitalized_name"] =
- UnderscoresToCapitalizedCamelCase(descriptor);
- (*variables)["constant_name"] = FieldConstantName(descriptor);
- (*variables)["number"] = SimpleItoa(descriptor->number());
+ SetCommonFieldVariables(descriptor, info, variables);
+
(*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
(*variables)["field_type"] = (*variables)["type"];
(*variables)["field_list_type"] = "java.util.List<" +
(*variables)["boxed_type"] + ">";
- (*variables)["empty_list"] = "java.util.Collections.emptyList();";
- (*variables)["default"] = DefaultValue(descriptor);
+ (*variables)["empty_list"] = "java.util.Collections.emptyList()";
+ (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
(*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ?
- "" : ("= " + DefaultValue(descriptor));
- (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
+ "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
+ (*variables)["capitalized_type"] =
+ GetCapitalizedType(descriptor, /* immutable = */ true);
(*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
@@ -195,19 +96,46 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["on_changed"] =
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
- // For singular messages and builders, one bit is used for the hasField bit.
- (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ if (SupportFieldPresence(descriptor->file())) {
+ // For singular messages and builders, one bit is used for the hasField bit.
+ (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
- (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
- (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
- (*variables)["clear_has_field_bit_builder"] =
- GenerateClearBit(builderBitIndex);
+ // Note that these have a trailing ";".
+ (*variables)["set_has_field_bit_message"] =
+ GenerateSetBit(messageBitIndex) + ";";
+ (*variables)["set_has_field_bit_builder"] =
+ GenerateSetBit(builderBitIndex) + ";";
+ (*variables)["clear_has_field_bit_builder"] =
+ GenerateClearBit(builderBitIndex) + ";";
+
+ (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+ } else {
+ (*variables)["set_has_field_bit_message"] = "";
+ (*variables)["set_has_field_bit_builder"] = "";
+ (*variables)["clear_has_field_bit_builder"] = "";
+
+ if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+ (*variables)["is_field_present_message"] =
+ "!" + (*variables)["name"] + "_.isEmpty()";
+ } else {
+ (*variables)["is_field_present_message"] =
+ (*variables)["name"] + "_ != " + (*variables)["default"];
+ }
+ }
// For repated builders, one bit is used for whether the array is immutable.
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+ // 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);
+
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
(*variables)["set_has_field_bit_to_local"] =
@@ -218,70 +146,94 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// ===================================================================
-PrimitiveFieldGenerator::
-PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex,
- int builderBitIndex)
+ImmutablePrimitiveFieldGenerator::
+ImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
- builderBitIndex_(builderBitIndex) {
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
- &variables_);
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
}
-PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
+ImmutablePrimitiveFieldGenerator::~ImmutablePrimitiveFieldGenerator() {}
-int PrimitiveFieldGenerator::GetNumBitsForMessage() const {
+int ImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
return 1;
}
-int PrimitiveFieldGenerator::GetNumBitsForBuilder() const {
+int ImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const {
return 1;
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$boolean has$capitalized_name$();\n"
"$deprecation$$type$ get$capitalized_name$();\n");
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $field_type$ $name$_;\n"
- "$deprecation$public boolean has$capitalized_name$() {\n"
- " return $get_has_field_bit_message$;\n"
- "}\n");
+ "private $field_type$ $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_message$;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" return $name$_;\n"
"}\n");
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $field_type$ $name$_ $default_init$;\n"
- "$deprecation$public boolean has$capitalized_name$() {\n"
- " return $get_has_field_bit_builder$;\n"
- "}\n");
+ "private $field_type$ $name$_ $default_init$;\n");
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_builder$;\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" return $name$_;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
"$null_check$"
- " $set_has_field_bit_builder$;\n"
+ " $set_has_field_bit_builder$\n"
" $name$_ = value;\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
- " $clear_has_field_bit_builder$;\n");
+ " $clear_has_field_bit_builder$\n");
JavaType type = GetJavaType(descriptor_);
if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) {
// The default value is not a simple literal so we want to avoid executing
@@ -298,65 +250,80 @@ GenerateBuilderMembers(io::Printer* printer) const {
"}\n");
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateInitializationCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = $default$;\n");
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateBuilderClearCode(io::Printer* printer) const {
printer->Print(variables_,
"$name$_ = $default$;\n"
- "$clear_has_field_bit_builder$;\n");
+ "$clear_has_field_bit_builder$\n");
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
- printer->Print(variables_,
- "if (other.has$capitalized_name$()) {\n"
- " set$capitalized_name$(other.get$capitalized_name$());\n"
- "}\n");
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " set$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "if (other.get$capitalized_name$() != $default$) {\n"
+ " set$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+ }
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "if ($get_has_field_bit_from_local$) {\n"
+ " $set_has_field_bit_to_local$;\n"
+ "}\n");
+ }
printer->Print(variables_,
- "if ($get_has_field_bit_from_local$) {\n"
- " $set_has_field_bit_to_local$;\n"
- "}\n"
"result.$name$_ = $name$_;\n");
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "$set_has_field_bit_builder$;\n"
+ "$set_has_field_bit_message$\n"
"$name$_ = input.read$capitalized_type$();\n");
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for primitives.
+}
+
+void ImmutablePrimitiveFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
+ "if ($is_field_present_message$) {\n"
" output.write$capitalized_type$($number$, $name$_);\n"
"}\n");
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
+ "if ($is_field_present_message$) {\n"
" size += com.google.protobuf.CodedOutputStream\n"
" .compute$capitalized_type$Size($number$, $name$_);\n"
"}\n");
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
switch (GetJavaType(descriptor_)) {
case JAVATYPE_INT:
@@ -369,14 +336,18 @@ GenerateEqualsCode(io::Printer* printer) const {
case JAVATYPE_FLOAT:
printer->Print(variables_,
- "result = result && (Float.floatToIntBits(get$capitalized_name$())"
- " == Float.floatToIntBits(other.get$capitalized_name$()));\n");
+ "result = result && (\n"
+ " java.lang.Float.floatToIntBits(get$capitalized_name$())\n"
+ " == java.lang.Float.floatToIntBits(\n"
+ " other.get$capitalized_name$()));\n");
break;
case JAVATYPE_DOUBLE:
printer->Print(variables_,
- "result = result && (Double.doubleToLongBits(get$capitalized_name$())"
- " == Double.doubleToLongBits(other.get$capitalized_name$()));\n");
+ "result = result && (\n"
+ " java.lang.Double.doubleToLongBits(get$capitalized_name$())\n"
+ " == java.lang.Double.doubleToLongBits(\n"
+ " other.get$capitalized_name$()));\n");
break;
case JAVATYPE_STRING:
@@ -394,7 +365,7 @@ GenerateEqualsCode(io::Printer* printer) const {
}
}
-void PrimitiveFieldGenerator::
+void ImmutablePrimitiveFieldGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(variables_,
"hash = (37 * hash) + $constant_name$;\n");
@@ -406,24 +377,26 @@ GenerateHashCode(io::Printer* printer) const {
case JAVATYPE_LONG:
printer->Print(variables_,
- "hash = (53 * hash) + hashLong(get$capitalized_name$());\n");
+ "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n"
+ " get$capitalized_name$());\n");
break;
case JAVATYPE_BOOLEAN:
printer->Print(variables_,
- "hash = (53 * hash) + hashBoolean(get$capitalized_name$());\n");
+ "hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n"
+ " get$capitalized_name$());\n");
break;
case JAVATYPE_FLOAT:
printer->Print(variables_,
- "hash = (53 * hash) + Float.floatToIntBits(\n"
+ "hash = (53 * hash) + java.lang.Float.floatToIntBits(\n"
" get$capitalized_name$());\n");
break;
case JAVATYPE_DOUBLE:
printer->Print(variables_,
- "hash = (53 * hash) + hashLong(\n"
- " Double.doubleToLongBits(get$capitalized_name$()));\n");
+ "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n"
+ " java.lang.Double.doubleToLongBits(get$capitalized_name$()));\n");
break;
case JAVATYPE_STRING:
@@ -440,52 +413,188 @@ GenerateHashCode(io::Printer* printer) const {
}
}
-string PrimitiveFieldGenerator::GetBoxedType() const {
+string ImmutablePrimitiveFieldGenerator::GetBoxedType() const {
return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
}
// ===================================================================
-RepeatedPrimitiveFieldGenerator::
-RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex,
- int builderBitIndex)
+ImmutablePrimitiveOneofFieldGenerator::
+ImmutablePrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutablePrimitiveFieldGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutablePrimitiveOneofFieldGenerator::
+~ImmutablePrimitiveOneofFieldGenerator() {}
+
+void ImmutablePrimitiveOneofFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($boxed_type$) $oneof_name$_;\n"
+ " }\n"
+ " return $default$;\n"
+ "}\n");
+}
+
+
+void ImmutablePrimitiveOneofFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " return ($boxed_type$) $oneof_name$_;\n"
+ " }\n"
+ " return $default$;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+ "$null_check$"
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = value;\n"
+ " $on_changed$\n"
+ " return this;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " $on_changed$\n"
+ " }\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " result.$oneof_name$_ = $oneof_name$_;\n"
+ "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "set$capitalized_name$(other.get$capitalized_name$());\n");
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = input.read$capitalized_type$();\n");
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.write$capitalized_type$(\n"
+ " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"
+ "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$capitalized_type$Size(\n"
+ " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"
+ "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutablePrimitiveFieldGenerator::
+RepeatedImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
- builderBitIndex_(builderBitIndex) {
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
- &variables_);
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
}
-RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+RepeatedImmutablePrimitiveFieldGenerator::
+~RepeatedImmutablePrimitiveFieldGenerator() {}
-int RepeatedPrimitiveFieldGenerator::GetNumBitsForMessage() const {
+int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
return 0;
}
-int RepeatedPrimitiveFieldGenerator::GetNumBitsForBuilder() const {
+int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const {
return 1;
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$int get$capitalized_name$Count();\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n"
- "$deprecation$int get$capitalized_name$Count();\n"
"$deprecation$$type$ get$capitalized_name$(int index);\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private $field_list_type$ $name$_;\n"
+ "private $field_list_type$ $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public java.util.List<$boxed_type$>\n"
" get$capitalized_name$List() {\n"
" return $name$_;\n" // note: unmodifiable list
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
"}\n");
@@ -497,7 +606,7 @@ GenerateMembers(io::Printer* printer) const {
}
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
// One field is the list and the bit field keeps track of whether the
// list is immutable. If it's immutable, the invariant is that it must
@@ -523,17 +632,24 @@ GenerateBuilderMembers(io::Printer* printer) const {
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable.
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public java.util.List<$boxed_type$>\n"
" get$capitalized_name$List() {\n"
" return java.util.Collections.unmodifiableList($name$_);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$(\n"
" int index, $type$ value) {\n"
"$null_check$"
@@ -541,21 +657,28 @@ GenerateBuilderMembers(io::Printer* printer) const {
" $name$_.set(index, value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
"$null_check$"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder addAll$capitalized_name$(\n"
" java.lang.Iterable<? extends $boxed_type$> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
- " super.addAll(values, $name$_);\n"
+ " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
+ " values, $name$_);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
" $name$_ = $empty_list$;\n"
" $clear_mutable_bit_builder$;\n"
@@ -564,24 +687,24 @@ GenerateBuilderMembers(io::Printer* printer) const {
"}\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateInitializationCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = $empty_list$;\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateBuilderClearCode(io::Printer* printer) const {
printer->Print(variables_,
"$name$_ = $empty_list$;\n"
"$clear_mutable_bit_builder$;\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
// The code below does two optimizations:
// 1. If the other list is empty, there's nothing to do. This ensures we
@@ -601,7 +724,7 @@ GenerateMergingCode(io::Printer* printer) const {
"}\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
// The code below ensures that the result has an immutable list. If our
// list is immutable, we can just reuse it. If not, we make it immutable.
@@ -613,27 +736,45 @@ GenerateBuildingCode(io::Printer* printer) const {
"result.$name$_ = $name$_;\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
- "ensure$capitalized_name$IsMutable();\n"
+ "if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ = new java.util.ArrayList<$boxed_type$>();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n"
"$name$_.add(input.read$capitalized_type$());\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateParsingCodeFromPacked(io::Printer* printer) const {
printer->Print(variables_,
"int length = input.readRawVarint32();\n"
"int limit = input.pushLimit(length);\n"
+ "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n"
+ " $name$_ = new java.util.ArrayList<$boxed_type$>();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n"
"while (input.getBytesUntilLimit() > 0) {\n"
- " add$capitalized_name$(input.read$capitalized_type$());\n"
+ " $name$_.add(input.read$capitalized_type$());\n"
"}\n"
"input.popLimit(limit);\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_mutable_bit_parser$) {\n"
+ " $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+ "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
if (descriptor_->options().packed()) {
+ // We invoke getSerializedSize in writeTo for messages that have packed
+ // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
+ // That makes it safe to rely on the memoized size here.
printer->Print(variables_,
"if (get$capitalized_name$List().size() > 0) {\n"
" output.writeRawVarint32($tag$);\n"
@@ -650,7 +791,7 @@ GenerateSerializationCode(io::Printer* printer) const {
}
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
"{\n"
@@ -693,14 +834,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print("}\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"result = result && get$capitalized_name$List()\n"
" .equals(other.get$capitalized_name$List());\n");
}
-void RepeatedPrimitiveFieldGenerator::
+void RepeatedImmutablePrimitiveFieldGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(variables_,
"if (get$capitalized_name$Count() > 0) {\n"
@@ -709,7 +850,7 @@ GenerateHashCode(io::Printer* printer) const {
"}\n");
}
-string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
+string RepeatedImmutablePrimitiveFieldGenerator::GetBoxedType() const {
return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
}
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h
index 7900fac5..d0cd12d9 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.h
+++ b/src/google/protobuf/compiler/java/java_primitive_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -41,16 +41,26 @@
namespace google {
namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+}
+
+namespace protobuf {
namespace compiler {
namespace java {
-class PrimitiveFieldGenerator : public FieldGenerator {
+class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
public:
- explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex, int builderBitIndex);
- ~PrimitiveFieldGenerator();
+ explicit ImmutablePrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutablePrimitiveFieldGenerator();
- // implements FieldGenerator ---------------------------------------
+ // implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const;
int GetNumBitsForBuilder() const;
void GenerateInterfaceMembers(io::Printer* printer) const;
@@ -61,6 +71,7 @@ class PrimitiveFieldGenerator : public FieldGenerator {
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;
@@ -69,22 +80,47 @@ class PrimitiveFieldGenerator : public FieldGenerator {
string GetBoxedType() const;
- private:
+ protected:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
const int messageBitIndex_;
const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldGenerator);
+};
+
+class ImmutablePrimitiveOneofFieldGenerator
+ : public ImmutablePrimitiveFieldGenerator {
+ public:
+ ImmutablePrimitiveOneofFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutablePrimitiveOneofFieldGenerator();
+
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldGenerator);
};
-class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
+class RepeatedImmutablePrimitiveFieldGenerator
+ : public ImmutableFieldGenerator {
public:
- explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex, int builderBitIndex);
- ~RepeatedPrimitiveFieldGenerator();
+ explicit RepeatedImmutablePrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ virtual ~RepeatedImmutablePrimitiveFieldGenerator();
- // implements FieldGenerator ---------------------------------------
+ // implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const;
int GetNumBitsForBuilder() const;
void GenerateInterfaceMembers(io::Printer* printer) const;
@@ -96,6 +132,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
void GenerateBuildingCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
void GenerateParsingCodeFromPacked(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;
@@ -109,8 +146,10 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
map<string, string> variables_;
const int messageBitIndex_;
const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutablePrimitiveFieldGenerator);
};
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
index 1ae4f461..7baead15 100644
--- a/src/google/protobuf/compiler/java/java_service.cc
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,7 +33,11 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/java/java_service.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/strutil.h>
@@ -48,8 +52,18 @@ ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor)
ServiceGenerator::~ServiceGenerator() {}
-void ServiceGenerator::Generate(io::Printer* printer) {
- bool is_own_file = descriptor_->file()->options().java_multiple_files();
+// ===================================================================
+ImmutableServiceGenerator::ImmutableServiceGenerator(
+ const ServiceDescriptor* descriptor, Context* context)
+ : ServiceGenerator(descriptor), context_(context),
+ name_resolver_(context->GetNameResolver()) {}
+
+ImmutableServiceGenerator::~ImmutableServiceGenerator() {}
+
+void ImmutableServiceGenerator::Generate(io::Printer* printer) {
+ bool is_own_file =
+ MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+ WriteServiceDocComment(printer, descriptor_);
printer->Print(
"public $static$ abstract class $classname$\n"
" implements com.google.protobuf.Service {\n",
@@ -75,7 +89,7 @@ void ServiceGenerator::Generate(io::Printer* printer) {
" getDescriptor() {\n"
" return $file$.getDescriptor().getServices().get($index$);\n"
"}\n",
- "file", ClassName(descriptor_->file()),
+ "file", name_resolver_->GetImmutableClassName(descriptor_->file()),
"index", SimpleItoa(descriptor_->index()));
GenerateGetDescriptorForType(printer);
@@ -86,11 +100,18 @@ void ServiceGenerator::Generate(io::Printer* printer) {
GenerateStub(printer);
GenerateBlockingStub(printer);
+ // Add an insertion point.
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(class_scope:$full_name$)\n",
+ "full_name", descriptor_->full_name());
+
printer->Outdent();
printer->Print("}\n\n");
}
-void ServiceGenerator::GenerateGetDescriptorForType(io::Printer* printer) {
+void ImmutableServiceGenerator::GenerateGetDescriptorForType(
+ io::Printer* printer) {
printer->Print(
"public final com.google.protobuf.Descriptors.ServiceDescriptor\n"
" getDescriptorForType() {\n"
@@ -98,7 +119,7 @@ void ServiceGenerator::GenerateGetDescriptorForType(io::Printer* printer) {
"}\n");
}
-void ServiceGenerator::GenerateInterface(io::Printer* printer) {
+void ImmutableServiceGenerator::GenerateInterface(io::Printer* printer) {
printer->Print("public interface Interface {\n");
printer->Indent();
GenerateAbstractMethods(printer);
@@ -106,7 +127,7 @@ void ServiceGenerator::GenerateInterface(io::Printer* printer) {
printer->Print("}\n\n");
}
-void ServiceGenerator::GenerateNewReflectiveServiceMethod(
+void ImmutableServiceGenerator::GenerateNewReflectiveServiceMethod(
io::Printer* printer) {
printer->Print(
"public static com.google.protobuf.Service newReflectiveService(\n"
@@ -133,7 +154,7 @@ void ServiceGenerator::GenerateNewReflectiveServiceMethod(
printer->Print("}\n\n");
}
-void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
+void ImmutableServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
io::Printer* printer) {
printer->Print(
"public static com.google.protobuf.BlockingService\n"
@@ -154,15 +175,16 @@ void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
printer->Print("}\n\n");
}
-void ServiceGenerator::GenerateAbstractMethods(io::Printer* printer) {
+void ImmutableServiceGenerator::GenerateAbstractMethods(io::Printer* printer) {
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor* method = descriptor_->method(i);
+ WriteMethodDocComment(printer, method);
GenerateMethodSignature(printer, method, IS_ABSTRACT);
printer->Print(";\n\n");
}
}
-void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
+void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) {
printer->Print(
"\n"
"public final void callMethod(\n"
@@ -185,8 +207,10 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
map<string, string> vars;
vars["index"] = SimpleItoa(i);
vars["method"] = UnderscoresToCamelCase(method);
- vars["input"] = ClassName(method->input_type());
- vars["output"] = ClassName(method->output_type());
+ vars["input"] = name_resolver_->GetImmutableClassName(
+ method->input_type());
+ vars["output"] = name_resolver_->GetImmutableClassName(
+ method->output_type());
printer->Print(vars,
"case $index$:\n"
" this.$method$(controller, ($input$)request,\n"
@@ -208,7 +232,8 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
"\n");
}
-void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) {
+void ImmutableServiceGenerator::GenerateCallBlockingMethod(
+ io::Printer* printer) {
printer->Print(
"\n"
"public final com.google.protobuf.Message callBlockingMethod(\n"
@@ -230,8 +255,10 @@ void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) {
map<string, string> vars;
vars["index"] = SimpleItoa(i);
vars["method"] = UnderscoresToCamelCase(method);
- vars["input"] = ClassName(method->input_type());
- vars["output"] = ClassName(method->output_type());
+ vars["input"] = name_resolver_->GetImmutableClassName(
+ method->input_type());
+ vars["output"] = name_resolver_->GetImmutableClassName(
+ method->output_type());
printer->Print(vars,
"case $index$:\n"
" return impl.$method$(controller, ($input$)request);\n");
@@ -250,7 +277,7 @@ void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) {
"\n");
}
-void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
+void ImmutableServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
io::Printer* printer) {
/*
* TODO(cpovirk): The exception message says "Service.foo" when it may be
@@ -274,7 +301,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
const MethodDescriptor* method = descriptor_->method(i);
map<string, string> vars;
vars["index"] = SimpleItoa(i);
- vars["type"] = ClassName(
+ vars["type"] = name_resolver_->GetImmutableClassName(
(which == REQUEST) ? method->input_type() : method->output_type());
printer->Print(vars,
"case $index$:\n"
@@ -294,7 +321,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
"\n");
}
-void ServiceGenerator::GenerateStub(io::Printer* printer) {
+void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) {
printer->Print(
"public static Stub newStub(\n"
" com.google.protobuf.RpcChannel channel) {\n"
@@ -303,7 +330,7 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) {
"\n"
"public static final class Stub extends $classname$ implements Interface {"
"\n",
- "classname", ClassName(descriptor_));
+ "classname", name_resolver_->GetImmutableClassName(descriptor_));
printer->Indent();
printer->Print(
@@ -326,7 +353,8 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) {
map<string, string> vars;
vars["index"] = SimpleItoa(i);
- vars["output"] = ClassName(method->output_type());
+ vars["output"] = name_resolver_->GetImmutableClassName(
+ method->output_type());
printer->Print(vars,
"channel.callMethod(\n"
" getDescriptor().getMethods().get($index$),\n"
@@ -348,7 +376,7 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) {
"\n");
}
-void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
+void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
printer->Print(
"public static BlockingInterface newBlockingStub(\n"
" com.google.protobuf.BlockingRpcChannel channel) {\n"
@@ -390,7 +418,8 @@ void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
map<string, string> vars;
vars["index"] = SimpleItoa(i);
- vars["output"] = ClassName(method->output_type());
+ vars["output"] = name_resolver_->GetImmutableClassName(
+ method->output_type());
printer->Print(vars,
"return ($output$) channel.callBlockingMethod(\n"
" getDescriptor().getMethods().get($index$),\n"
@@ -408,13 +437,13 @@ void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
printer->Print("}\n");
}
-void ServiceGenerator::GenerateMethodSignature(io::Printer* printer,
+void ImmutableServiceGenerator::GenerateMethodSignature(io::Printer* printer,
const MethodDescriptor* method,
IsAbstract is_abstract) {
map<string, string> vars;
vars["name"] = UnderscoresToCamelCase(method);
- vars["input"] = ClassName(method->input_type());
- vars["output"] = ClassName(method->output_type());
+ vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
+ vars["output"] = name_resolver_->GetImmutableClassName(method->output_type());
vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : "";
printer->Print(vars,
"public $abstract$ void $name$(\n"
@@ -423,13 +452,13 @@ void ServiceGenerator::GenerateMethodSignature(io::Printer* printer,
" com.google.protobuf.RpcCallback<$output$> done)");
}
-void ServiceGenerator::GenerateBlockingMethodSignature(
+void ImmutableServiceGenerator::GenerateBlockingMethodSignature(
io::Printer* printer,
const MethodDescriptor* method) {
map<string, string> vars;
vars["method"] = UnderscoresToCamelCase(method);
- vars["input"] = ClassName(method->input_type());
- vars["output"] = ClassName(method->output_type());
+ vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
+ vars["output"] = name_resolver_->GetImmutableClassName(method->output_type());
printer->Print(vars,
"\n"
"public $output$ $method$(\n"
diff --git a/src/google/protobuf/compiler/java/java_service.h b/src/google/protobuf/compiler/java/java_service.h
index e07eebf7..6707e821 100644
--- a/src/google/protobuf/compiler/java/java_service.h
+++ b/src/google/protobuf/compiler/java/java_service.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -40,8 +40,14 @@
namespace google {
namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
namespace io {
- class Printer; // printer.h
+ class Printer; // printer.h
}
}
@@ -52,9 +58,27 @@ namespace java {
class ServiceGenerator {
public:
explicit ServiceGenerator(const ServiceDescriptor* descriptor);
- ~ServiceGenerator();
+ virtual ~ServiceGenerator();
+
+ virtual void Generate(io::Printer* printer) = 0;
+
+ enum RequestOrResponse { REQUEST, RESPONSE };
+ enum IsAbstract { IS_ABSTRACT, IS_CONCRETE };
+
+ protected:
+ const ServiceDescriptor* descriptor_;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator);
+};
- void Generate(io::Printer* printer);
+class ImmutableServiceGenerator : public ServiceGenerator {
+ public:
+ explicit ImmutableServiceGenerator(const ServiceDescriptor* descriptor,
+ Context* context);
+ virtual ~ImmutableServiceGenerator();
+
+ virtual void Generate(io::Printer* printer);
private:
@@ -80,7 +104,6 @@ class ServiceGenerator {
void GenerateCallBlockingMethod(io::Printer* printer);
// Generate the implementations of Service.get{Request,Response}Prototype().
- enum RequestOrResponse { REQUEST, RESPONSE };
void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer);
// Generate a stub implementation of the service.
@@ -88,7 +111,6 @@ class ServiceGenerator {
// Generate a method signature, possibly abstract, without body or trailing
// semicolon.
- enum IsAbstract { IS_ABSTRACT, IS_CONCRETE };
void GenerateMethodSignature(io::Printer* printer,
const MethodDescriptor* method,
IsAbstract is_abstract);
@@ -100,9 +122,9 @@ class ServiceGenerator {
void GenerateBlockingMethodSignature(io::Printer* printer,
const MethodDescriptor* method);
- const ServiceDescriptor* descriptor_;
-
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator);
+ Context* context_;
+ ClassNameResolver* name_resolver_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableServiceGenerator);
};
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
new file mode 100644
index 00000000..70177367
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
@@ -0,0 +1,205 @@
+// 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: xiaofeng@google.com (Feng Xiao)
+
+#include <google/protobuf/compiler/java/java_shared_code_generator.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file)
+ : name_resolver_(new ClassNameResolver), file_(file) {
+}
+
+SharedCodeGenerator::~SharedCodeGenerator() {
+}
+
+void SharedCodeGenerator::Generate(GeneratorContext* context,
+ vector<string>* file_list) {
+ string java_package = FileJavaPackage(file_);
+ string package_dir = JavaPackageToDir(java_package);
+
+ if (HasDescriptorMethods(file_)) {
+ // Generate descriptors.
+ string classname = name_resolver_->GetDescriptorClassName(file_);
+ string filename = package_dir + classname + ".java";
+ file_list->push_back(filename);
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+ google::protobuf::scoped_ptr<io::Printer> printer(new io::Printer(output.get(), '$'));
+
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
+ "\n",
+ "filename", file_->name());
+ if (!java_package.empty()) {
+ printer->Print(
+ "package $package$;\n"
+ "\n",
+ "package", java_package);
+ }
+ printer->Print(
+ "public final class $classname$ {\n"
+ " public static com.google.protobuf.Descriptors.FileDescriptor\n"
+ " descriptor;\n"
+ " static {\n",
+ "classname", classname);
+ printer->Indent();
+ printer->Indent();
+ GenerateDescriptors(printer.get());
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n"
+ "}\n");
+
+ printer.reset();
+ output.reset();
+ }
+}
+
+
+void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) {
+ // Embed the descriptor. We simply serialize the entire FileDescriptorProto
+ // and embed it as a string literal, which is parsed and built into real
+ // descriptors at initialization time. We unfortunately have to put it in
+ // a string literal, not a byte array, because apparently using a literal
+ // byte array causes the Java compiler to generate *instructions* to
+ // initialize each and every byte of the array, e.g. as if you typed:
+ // b[0] = 123; b[1] = 456; b[2] = 789;
+ // This makes huge bytecode files and can easily hit the compiler's internal
+ // code size limits (error "code to large"). String literals are apparently
+ // embedded raw, which is what we want.
+ FileDescriptorProto file_proto;
+ file_->CopyTo(&file_proto);
+
+
+ string file_data;
+ file_proto.SerializeToString(&file_data);
+
+ printer->Print(
+ "java.lang.String[] descriptorData = {\n");
+ printer->Indent();
+
+ // Only write 40 bytes per line.
+ static const int kBytesPerLine = 40;
+ for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
+ if (i > 0) {
+ // Every 400 lines, start a new string literal, in order to avoid the
+ // 64k length limit.
+ if (i % 400 == 0) {
+ printer->Print(",\n");
+ } else {
+ printer->Print(" +\n");
+ }
+ }
+ printer->Print("\"$data$\"",
+ "data", CEscape(file_data.substr(i, kBytesPerLine)));
+ }
+
+ printer->Outdent();
+ printer->Print("\n};\n");
+
+ // -----------------------------------------------------------------
+ // Create the InternalDescriptorAssigner.
+
+ printer->Print(
+ "com.google.protobuf.Descriptors.FileDescriptor."
+ "InternalDescriptorAssigner assigner =\n"
+ " new com.google.protobuf.Descriptors.FileDescriptor."
+ " InternalDescriptorAssigner() {\n"
+ " public com.google.protobuf.ExtensionRegistry assignDescriptors(\n"
+ " com.google.protobuf.Descriptors.FileDescriptor root) {\n"
+ " descriptor = root;\n"
+ // Custom options will be handled when immutable messages' outer class is
+ // loaded. Here we just return null and let custom options be unknown
+ // fields.
+ " return null;\n"
+ " }\n"
+ " };\n");
+
+ // -----------------------------------------------------------------
+ // Find out all dependencies.
+ vector<pair<string, string> > dependencies;
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ if (ShouldIncludeDependency(file_->dependency(i))) {
+ string filename = file_->dependency(i)->name();
+ string classname = FileJavaPackage(file_->dependency(i)) + "." +
+ name_resolver_->GetDescriptorClassName(
+ file_->dependency(i));
+ dependencies.push_back(std::make_pair(filename, classname));
+ }
+ }
+
+ // -----------------------------------------------------------------
+ // Invoke internalBuildGeneratedFileFrom() to build the file.
+ printer->Print(
+ "com.google.protobuf.Descriptors.FileDescriptor\n"
+ " .internalBuildGeneratedFileFrom(descriptorData,\n");
+ printer->Print(
+ " new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
+
+ for (int i = 0; i < dependencies.size(); i++) {
+ const string& dependency = dependencies[i].second;
+ printer->Print(
+ " $dependency$.getDescriptor(),\n",
+ "dependency", dependency);
+ }
+
+ printer->Print(
+ " }, assigner);\n");
+}
+
+bool SharedCodeGenerator::ShouldIncludeDependency(
+ const FileDescriptor* descriptor) {
+ return true;
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h
new file mode 100644
index 00000000..38a32fc2
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h
@@ -0,0 +1,94 @@
+// 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: xiaofeng@google.com (Feng Xiao)
+//
+// Generators that generate shared code between immutable API and mutable API.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+ class FileDescriptor; // descriptor.h
+ namespace compiler {
+ class GeneratorContext; // code_generator.h
+ namespace java {
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// A generator that generates code that are shared between immutable API
+// and mutable API. Currently only descriptors are shared.
+class SharedCodeGenerator {
+ public:
+ explicit SharedCodeGenerator(const FileDescriptor* file);
+ ~SharedCodeGenerator();
+
+ void Generate(GeneratorContext* generator_context,
+ vector<string>* file_list);
+
+ void GenerateDescriptors(io::Printer* printer);
+
+ private:
+ // Returns whether the dependency should be included in the output file.
+ // Always returns true for opensource, but used internally at Google to help
+ // improve compatibility with version 1 of protocol buffers.
+ bool ShouldIncludeDependency(const FileDescriptor* descriptor);
+
+ google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
+ const FileDescriptor* file_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator);
+};
+
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 4f1fb14c..8aa5699c 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -36,9 +36,12 @@
#include <map>
#include <string>
-#include <google/protobuf/compiler/java/java_string_field.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_string_field.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
@@ -56,17 +59,16 @@ namespace {
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex,
+ const FieldGeneratorInfo* info,
+ ClassNameResolver* name_resolver,
map<string, string>* variables) {
- (*variables)["name"] =
- UnderscoresToCamelCase(descriptor);
- (*variables)["capitalized_name"] =
- UnderscoresToCapitalizedCamelCase(descriptor);
- (*variables)["constant_name"] = FieldConstantName(descriptor);
- (*variables)["number"] = SimpleItoa(descriptor->number());
+ SetCommonFieldVariables(descriptor, info, variables);
+
(*variables)["empty_list"] = "com.google.protobuf.LazyStringArrayList.EMPTY";
- (*variables)["default"] = DefaultValue(descriptor);
- (*variables)["default_init"] = ("= " + DefaultValue(descriptor));
+ (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+ (*variables)["default_init"] =
+ "= " + ImmutableDefaultValue(descriptor, name_resolver);
(*variables)["capitalized_type"] = "String";
(*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
(*variables)["tag_size"] = SimpleItoa(
@@ -83,46 +85,75 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["on_changed"] =
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
- // For singular messages and builders, one bit is used for the hasField bit.
- (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ if (SupportFieldPresence(descriptor->file())) {
+ // For singular messages and builders, one bit is used for the hasField bit.
+ (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+ (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+
+ // Note that these have a trailing ";".
+ (*variables)["set_has_field_bit_message"] =
+ GenerateSetBit(messageBitIndex) + ";";
+ (*variables)["set_has_field_bit_builder"] =
+ GenerateSetBit(builderBitIndex) + ";";
+ (*variables)["clear_has_field_bit_builder"] =
+ GenerateClearBit(builderBitIndex) + ";";
- (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
- (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
- (*variables)["clear_has_field_bit_builder"] =
- GenerateClearBit(builderBitIndex);
+ (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+ } else {
+ (*variables)["set_has_field_bit_message"] = "";
+ (*variables)["set_has_field_bit_builder"] = "";
+ (*variables)["clear_has_field_bit_builder"] = "";
+
+ (*variables)["is_field_present_message"] =
+ "!get" + (*variables)["capitalized_name"] + "Bytes().isEmpty()";
+ }
- // For repated builders, one bit is used for whether the array is immutable.
+ // For repeated builders, one bit is used for whether the array is immutable.
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+ // 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);
+
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
(*variables)["set_has_field_bit_to_local"] =
GenerateSetBitToLocal(messageBitIndex);
}
+bool CheckUtf8(const FieldDescriptor* descriptor) {
+ return descriptor->file()->options().java_string_check_utf8();
+}
+
} // namespace
// ===================================================================
-StringFieldGenerator::
-StringFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex,
- int builderBitIndex)
+ImmutableStringFieldGenerator::
+ImmutableStringFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
- builderBitIndex_(builderBitIndex) {
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
- &variables_);
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
}
-StringFieldGenerator::~StringFieldGenerator() {}
+ImmutableStringFieldGenerator::~ImmutableStringFieldGenerator() {}
-int StringFieldGenerator::GetNumBitsForMessage() const {
+int ImmutableStringFieldGenerator::GetNumBitsForMessage() const {
return 1;
}
-int StringFieldGenerator::GetNumBitsForBuilder() const {
+int ImmutableStringFieldGenerator::GetNumBitsForBuilder() const {
return 1;
}
@@ -158,41 +189,68 @@ int StringFieldGenerator::GetNumBitsForBuilder() const {
// For single fields, the logic for this is done inside the generated code. For
// repeated fields, the logic is done in LazyStringArrayList and
// UnmodifiableLazyStringList.
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$boolean has$capitalized_name$();\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$boolean has$capitalized_name$();\n"
- "$deprecation$String get$capitalized_name$();\n");
+ "$deprecation$java.lang.String get$capitalized_name$();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes();\n");
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private java.lang.Object $name$_;\n"
- "$deprecation$public boolean has$capitalized_name$() {\n"
- " return $get_has_field_bit_message$;\n"
- "}\n");
+ "private java.lang.Object $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_message$;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$public String get$capitalized_name$() {\n"
+ "$deprecation$public java.lang.String get$capitalized_name$() {\n"
" java.lang.Object ref = $name$_;\n"
- " if (ref instanceof String) {\n"
- " return (String) ref;\n"
+ " if (ref instanceof java.lang.String) {\n"
+ " return (java.lang.String) ref;\n"
" } else {\n"
" com.google.protobuf.ByteString bs = \n"
" (com.google.protobuf.ByteString) ref;\n"
- " String s = bs.toStringUtf8();\n"
- " if (com.google.protobuf.Internal.isValidUtf8(bs)) {\n"
- " $name$_ = s;\n"
- " }\n"
+ " java.lang.String s = bs.toStringUtf8();\n");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " $name$_ = s;\n");
+ } else {
+ printer->Print(variables_,
+ " if (bs.isValidUtf8()) {\n"
+ " $name$_ = s;\n"
+ " }\n");
+ }
+ printer->Print(variables_,
" return s;\n"
" }\n"
- "}\n"
- "private com.google.protobuf.ByteString get$capitalized_name$Bytes() {\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes() {\n"
" java.lang.Object ref = $name$_;\n"
- " if (ref instanceof String) {\n"
+ " if (ref instanceof java.lang.String) {\n"
" com.google.protobuf.ByteString b = \n"
- " com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n"
+ " com.google.protobuf.ByteString.copyFromUtf8(\n"
+ " (java.lang.String) ref);\n"
" $name$_ = b;\n"
" return b;\n"
" } else {\n"
@@ -201,36 +259,72 @@ GenerateMembers(io::Printer* printer) const {
"}\n");
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private java.lang.Object $name$_ $default_init$;\n"
- "$deprecation$public boolean has$capitalized_name$() {\n"
- " return $get_has_field_bit_builder$;\n"
- "}\n");
+ "private java.lang.Object $name$_ $default_init$;\n");
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_builder$;\n"
+ "}\n");
+ }
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$public String get$capitalized_name$() {\n"
+ "$deprecation$public java.lang.String get$capitalized_name$() {\n"
" java.lang.Object ref = $name$_;\n"
- " if (!(ref instanceof String)) {\n"
- " String s = ((com.google.protobuf.ByteString) ref).toStringUtf8();\n"
- " $name$_ = s;\n"
+ " if (!(ref instanceof java.lang.String)) {\n"
+ " com.google.protobuf.ByteString bs =\n"
+ " (com.google.protobuf.ByteString) ref;\n"
+ " java.lang.String s = bs.toStringUtf8();\n");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " $name$_ = s;\n");
+ } else {
+ printer->Print(variables_,
+ " if (bs.isValidUtf8()) {\n"
+ " $name$_ = s;\n"
+ " }\n");
+ }
+ printer->Print(variables_,
" return s;\n"
" } else {\n"
- " return (String) ref;\n"
+ " return (java.lang.String) ref;\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes() {\n"
+ " java.lang.Object ref = $name$_;\n"
+ " if (ref instanceof String) {\n"
+ " com.google.protobuf.ByteString b = \n"
+ " com.google.protobuf.ByteString.copyFromUtf8(\n"
+ " (java.lang.String) ref);\n"
+ " $name$_ = b;\n"
+ " return b;\n"
+ " } else {\n"
+ " return (com.google.protobuf.ByteString) ref;\n"
" }\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$public Builder set$capitalized_name$(String value) {\n"
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " java.lang.String value) {\n"
"$null_check$"
- " $set_has_field_bit_builder$;\n"
+ " $set_has_field_bit_builder$\n"
" $name$_ = value;\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
- " $clear_has_field_bit_builder$;\n");
+ " $clear_has_field_bit_builder$\n");
// The default value is not a simple literal so we want to avoid executing
// it multiple times. Instead, get the default out of the default instance.
printer->Print(variables_,
@@ -240,80 +334,126 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return this;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "void set$capitalized_name$(com.google.protobuf.ByteString value) {\n"
- " $set_has_field_bit_builder$;\n"
+ "$deprecation$public Builder set$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ "$null_check$");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " checkByteStringIsUtf8(value);\n");
+ }
+ printer->Print(variables_,
+ " $set_has_field_bit_builder$\n"
" $name$_ = value;\n"
" $on_changed$\n"
+ " return this;\n"
"}\n");
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateInitializationCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = $default$;\n");
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateBuilderClearCode(io::Printer* printer) const {
printer->Print(variables_,
"$name$_ = $default$;\n"
- "$clear_has_field_bit_builder$;\n");
+ "$clear_has_field_bit_builder$\n");
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
- printer->Print(variables_,
- "if (other.has$capitalized_name$()) {\n"
- " set$capitalized_name$(other.get$capitalized_name$());\n"
- "}\n");
+ if (SupportFieldPresence(descriptor_->file())) {
+ // Allow a slight breach of abstraction here in order to avoid forcing
+ // all string fields to Strings when copying fields from a Message.
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " $set_has_field_bit_builder$\n"
+ " $name$_ = other.$name$_;\n"
+ " $on_changed$\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "if (!other.get$capitalized_name$().isEmpty()) {\n"
+ " $name$_ = other.$name$_;\n"
+ " $on_changed$\n"
+ "}\n");
+ }
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "if ($get_has_field_bit_from_local$) {\n"
+ " $set_has_field_bit_to_local$;\n"
+ "}\n");
+ }
printer->Print(variables_,
- "if ($get_has_field_bit_from_local$) {\n"
- " $set_has_field_bit_to_local$;\n"
- "}\n"
"result.$name$_ = $name$_;\n");
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
- printer->Print(variables_,
- "$set_has_field_bit_builder$;\n"
- "$name$_ = input.readBytes();\n");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ "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"
+ "$set_has_field_bit_message$\n"
+ "$name$_ = bs;\n");
+ }
+}
+
+void ImmutableStringFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ // noop for strings.
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
+ "if ($is_field_present_message$) {\n"
" output.writeBytes($number$, get$capitalized_name$Bytes());\n"
"}\n");
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
+ "if ($is_field_present_message$) {\n"
" size += com.google.protobuf.CodedOutputStream\n"
" .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
"}\n");
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"result = result && get$capitalized_name$()\n"
" .equals(other.get$capitalized_name$());\n");
}
-void StringFieldGenerator::
+void ImmutableStringFieldGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(variables_,
"hash = (37 * hash) + $constant_name$;\n");
@@ -321,56 +461,319 @@ GenerateHashCode(io::Printer* printer) const {
"hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
}
-string StringFieldGenerator::GetBoxedType() const {
- return "String";
+string ImmutableStringFieldGenerator::GetBoxedType() const {
+ return "java.lang.String";
+}
+
+// ===================================================================
+
+ImmutableStringOneofFieldGenerator::
+ImmutableStringOneofFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
+ : ImmutableStringFieldGenerator(
+ descriptor, messageBitIndex, builderBitIndex, context) {
+ const OneofGeneratorInfo* info =
+ context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+ SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableStringOneofFieldGenerator::
+~ImmutableStringOneofFieldGenerator() {}
+
+void ImmutableStringOneofFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ PrintExtraFieldInfo(variables_, printer);
+
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+ " java.lang.Object ref $default_init$;\n"
+ " if ($has_oneof_case_message$) {\n"
+ " ref = $oneof_name$_;\n"
+ " }\n"
+ " if (ref instanceof java.lang.String) {\n"
+ " return (java.lang.String) ref;\n"
+ " } else {\n"
+ " com.google.protobuf.ByteString bs = \n"
+ " (com.google.protobuf.ByteString) ref;\n"
+ " java.lang.String s = bs.toStringUtf8();\n");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " if ($has_oneof_case_message$) {\n"
+ " $oneof_name$_ = s;\n"
+ " }\n");
+ } else {
+ printer->Print(variables_,
+ " if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n"
+ " $oneof_name$_ = s;\n"
+ " }\n");
+ }
+ printer->Print(variables_,
+ " return s;\n"
+ " }\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes() {\n"
+ " java.lang.Object ref $default_init$;\n"
+ " if ($has_oneof_case_message$) {\n"
+ " ref = $oneof_name$_;\n"
+ " }\n"
+ " if (ref instanceof java.lang.String) {\n"
+ " com.google.protobuf.ByteString b = \n"
+ " com.google.protobuf.ByteString.copyFromUtf8(\n"
+ " (java.lang.String) ref);\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $oneof_name$_ = b;\n"
+ " }\n"
+ " return b;\n"
+ " } else {\n"
+ " return (com.google.protobuf.ByteString) ref;\n"
+ " }\n"
+ "}\n");
}
+void ImmutableStringOneofFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ if (SupportFieldPresence(descriptor_->file())) {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case_message$;\n"
+ "}\n");
+ }
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+ " java.lang.Object ref $default_init$;\n"
+ " if ($has_oneof_case_message$) {\n"
+ " ref = $oneof_name$_;\n"
+ " }\n"
+ " if (!(ref instanceof java.lang.String)) {\n"
+ " com.google.protobuf.ByteString bs =\n"
+ " (com.google.protobuf.ByteString) ref;\n"
+ " java.lang.String s = bs.toStringUtf8();\n"
+ " if ($has_oneof_case_message$) {\n");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " $oneof_name$_ = s;\n");
+ } else {
+ printer->Print(variables_,
+ " if (bs.isValidUtf8()) {\n"
+ " $oneof_name$_ = s;\n"
+ " }\n");
+ }
+ printer->Print(variables_,
+ " }\n"
+ " return s;\n"
+ " } else {\n"
+ " return (java.lang.String) ref;\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes() {\n"
+ " java.lang.Object ref $default_init$;\n"
+ " if ($has_oneof_case_message$) {\n"
+ " ref = $oneof_name$_;\n"
+ " }\n"
+ " if (ref instanceof String) {\n"
+ " com.google.protobuf.ByteString b = \n"
+ " com.google.protobuf.ByteString.copyFromUtf8(\n"
+ " (java.lang.String) ref);\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $oneof_name$_ = b;\n"
+ " }\n"
+ " return b;\n"
+ " } else {\n"
+ " return (com.google.protobuf.ByteString) ref;\n"
+ " }\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$(\n"
+ " java.lang.String value) {\n"
+ "$null_check$"
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = value;\n"
+ " $on_changed$\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder clear$capitalized_name$() {\n"
+ " if ($has_oneof_case_message$) {\n"
+ " $clear_oneof_case_message$;\n"
+ " $oneof_name$_ = null;\n"
+ " $on_changed$\n"
+ " }\n"
+ " return this;\n"
+ "}\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder set$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ "$null_check$");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " checkByteStringIsUtf8(value);\n");
+ }
+ printer->Print(variables_,
+ " $set_oneof_case_message$;\n"
+ " $oneof_name$_ = value;\n"
+ " $on_changed$\n"
+ " return this;\n"
+ "}\n");
+}
+
+void ImmutableStringOneofFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // Allow a slight breach of abstraction here in order to avoid forcing
+ // all string fields to Strings when copying fields from a Message.
+ printer->Print(variables_,
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = other.$oneof_name$_;\n"
+ "$on_changed$\n");
+}
+
+void ImmutableStringOneofFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " result.$oneof_name$_ = $oneof_name$_;\n"
+ "}\n");
+}
+
+void ImmutableStringOneofFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ "String s = input.readStringRequireUtf8();\n"
+ "$set_oneof_case_message$;\n"
+ "$oneof_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_oneof_case_message$;\n"
+ "$oneof_name$_ = s;\n");
+ } else {
+ printer->Print(variables_,
+ "com.google.protobuf.ByteString bs = input.readBytes();\n"
+ "$set_oneof_case_message$;\n"
+ "$oneof_name$_ = bs;\n");
+ }
+}
+
+void ImmutableStringOneofFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " output.writeBytes($number$, get$capitalized_name$Bytes());\n"
+ "}\n");
+}
+
+void ImmutableStringOneofFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case_message$) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
+ "}\n");
+}
// ===================================================================
-RepeatedStringFieldGenerator::
-RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex,
- int builderBitIndex)
+RepeatedImmutableStringFieldGenerator::
+RepeatedImmutableStringFieldGenerator(const FieldDescriptor* descriptor,
+ int messageBitIndex,
+ int builderBitIndex,
+ Context* context)
: descriptor_(descriptor), messageBitIndex_(messageBitIndex),
- builderBitIndex_(builderBitIndex) {
+ builderBitIndex_(builderBitIndex), context_(context),
+ name_resolver_(context->GetNameResolver()) {
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
- &variables_);
+ context->GetFieldGeneratorInfo(descriptor),
+ name_resolver_, &variables_);
}
-RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
+RepeatedImmutableStringFieldGenerator::
+~RepeatedImmutableStringFieldGenerator() {}
-int RepeatedStringFieldGenerator::GetNumBitsForMessage() const {
+int RepeatedImmutableStringFieldGenerator::GetNumBitsForMessage() const {
return 0;
}
-int RepeatedStringFieldGenerator::GetNumBitsForBuilder() const {
+int RepeatedImmutableStringFieldGenerator::GetNumBitsForBuilder() const {
return 1;
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$com.google.protobuf.ProtocolStringList\n"
+ " get$capitalized_name$List();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$int get$capitalized_name$Count();\n");
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$java.util.List<String> get$capitalized_name$List();\n"
- "$deprecation$int get$capitalized_name$Count();\n"
- "$deprecation$String get$capitalized_name$(int index);\n");
+ "$deprecation$java.lang.String get$capitalized_name$(int index);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes(int index);\n");
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private com.google.protobuf.LazyStringList $name$_;\n"
- "$deprecation$public java.util.List<String>\n"
+ "private com.google.protobuf.LazyStringList $name$_;\n");
+ PrintExtraFieldInfo(variables_, printer);
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ProtocolStringList\n"
" get$capitalized_name$List() {\n"
" return $name$_;\n" // note: unmodifiable list
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
- "$deprecation$public String get$capitalized_name$(int index) {\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes(int index) {\n"
+ " return $name$_.getByteString(index);\n"
+ "}\n");
if (descriptor_->options().packed() &&
HasGeneratedMethods(descriptor_->containing_type())) {
@@ -379,7 +782,7 @@ GenerateMembers(io::Printer* printer) const {
}
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
// One field is the list and the bit field keeps track of whether the
// list is immutable. If it's immutable, the invariant is that it must
@@ -405,39 +808,60 @@ GenerateBuilderMembers(io::Printer* printer) const {
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable.
+ WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$public java.util.List<String>\n"
+ "$deprecation$public com.google.protobuf.ProtocolStringList\n"
" get$capitalized_name$List() {\n"
- " return java.util.Collections.unmodifiableList($name$_);\n"
- "}\n"
+ " return $name$_.getUnmodifiableView();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Count() {\n"
" return $name$_.size();\n"
- "}\n"
- "$deprecation$public String get$capitalized_name$(int index) {\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public com.google.protobuf.ByteString\n"
+ " get$capitalized_name$Bytes(int index) {\n"
+ " return $name$_.getByteString(index);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder set$capitalized_name$(\n"
- " int index, String value) {\n"
+ " int index, java.lang.String value) {\n"
"$null_check$"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.set(index, value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
- "$deprecation$public Builder add$capitalized_name$(String value) {\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$(\n"
+ " java.lang.String value) {\n"
"$null_check$"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(value);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder addAll$capitalized_name$(\n"
- " java.lang.Iterable<String> values) {\n"
+ " java.lang.Iterable<java.lang.String> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
- " super.addAll(values, $name$_);\n"
+ " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
+ " values, $name$_);\n"
" $on_changed$\n"
" return this;\n"
- "}\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
"$deprecation$public Builder clear$capitalized_name$() {\n"
" $name$_ = $empty_list$;\n"
" $clear_mutable_bit_builder$;\n"
@@ -445,32 +869,41 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return this;\n"
"}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$deprecation$public Builder add$capitalized_name$Bytes(\n"
+ " com.google.protobuf.ByteString value) {\n"
+ "$null_check$");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " checkByteStringIsUtf8(value);\n");
+ }
printer->Print(variables_,
- "void add$capitalized_name$(com.google.protobuf.ByteString value) {\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(value);\n"
" $on_changed$\n"
+ " return this;\n"
"}\n");
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateInitializationCode(io::Printer* printer) const {
printer->Print(variables_, "$name$_ = $empty_list$;\n");
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateBuilderClearCode(io::Printer* printer) const {
printer->Print(variables_,
"$name$_ = $empty_list$;\n"
"$clear_mutable_bit_builder$;\n");
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
// The code below does two optimizations:
// 1. If the other list is empty, there's nothing to do. This ensures we
@@ -490,39 +923,82 @@ GenerateMergingCode(io::Printer* printer) const {
"}\n");
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
// The code below ensures that the result has an immutable list. If our
// list is immutable, we can just reuse it. If not, we make it immutable.
printer->Print(variables_,
"if ($get_mutable_bit_builder$) {\n"
- " $name$_ = new com.google.protobuf.UnmodifiableLazyStringList(\n"
- " $name$_);\n"
+ " $name$_ = $name$_.getUnmodifiableView();\n"
" $clear_mutable_bit_builder$;\n"
"}\n"
"result.$name$_ = $name$_;\n");
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
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");
+ }
printer->Print(variables_,
- "ensure$capitalized_name$IsMutable();\n"
- "$name$_.add(input.readBytes());\n");
+ "if (!$get_mutable_bit_parser$) {\n"
+ " $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n");
+ if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) {
+ printer->Print(variables_,
+ "$name$_.add(s);\n");
+ } else {
+ printer->Print(variables_,
+ "$name$_.add(bs);\n");
+ }
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateParsingCodeFromPacked(io::Printer* printer) const {
printer->Print(variables_,
"int length = input.readRawVarint32();\n"
"int limit = input.pushLimit(length);\n"
- "while (input.getBytesUntilLimit() > 0) {\n"
- " add$capitalized_name$(input.read$capitalized_type$());\n"
+ "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n"
+ " $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
+ " $set_mutable_bit_parser$;\n"
+ "}\n"
+ "while (input.getBytesUntilLimit() > 0) {\n");
+ if (CheckUtf8(descriptor_)) {
+ printer->Print(variables_,
+ " String s = input.readStringRequireUtf8();\n");
+ } else {
+ printer->Print(variables_,
+ " String s = input.readString();\n");
+ }
+ printer->Print(variables_,
+ " $name$.add(s);\n");
+ printer->Print(variables_,
"}\n"
"input.popLimit(limit);\n");
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_mutable_bit_parser$) {\n"
+ " $name$_ = $name$_.getUnmodifiableView();\n"
+ "}\n");
+}
+
+void RepeatedImmutableStringFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
if (descriptor_->options().packed()) {
printer->Print(variables_,
@@ -541,7 +1017,7 @@ GenerateSerializationCode(io::Printer* printer) const {
}
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
"{\n"
@@ -579,14 +1055,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print("}\n");
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"result = result && get$capitalized_name$List()\n"
" .equals(other.get$capitalized_name$List());\n");
}
-void RepeatedStringFieldGenerator::
+void RepeatedImmutableStringFieldGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(variables_,
"if (get$capitalized_name$Count() > 0) {\n"
@@ -595,7 +1071,7 @@ GenerateHashCode(io::Printer* printer) const {
"}\n");
}
-string RepeatedStringFieldGenerator::GetBoxedType() const {
+string RepeatedImmutableStringFieldGenerator::GetBoxedType() const {
return "String";
}
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
index 8cb41469..1ea44dec 100644
--- a/src/google/protobuf/compiler/java/java_string_field.h
+++ b/src/google/protobuf/compiler/java/java_string_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -42,16 +42,26 @@
namespace google {
namespace protobuf {
+ namespace compiler {
+ namespace java {
+ class Context; // context.h
+ class ClassNameResolver; // name_resolver.h
+ }
+ }
+}
+
+namespace protobuf {
namespace compiler {
namespace java {
-class StringFieldGenerator : public FieldGenerator {
+class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
public:
- explicit StringFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex, int builderBitIndex);
- ~StringFieldGenerator();
+ explicit ImmutableStringFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableStringFieldGenerator();
- // implements FieldGenerator ---------------------------------------
+ // implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const;
int GetNumBitsForBuilder() const;
void GenerateInterfaceMembers(io::Printer* printer) const;
@@ -62,29 +72,55 @@ class StringFieldGenerator : public FieldGenerator {
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:
+ protected:
const FieldDescriptor* descriptor_;
map<string, string> variables_;
const int messageBitIndex_;
const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldGenerator);
};
-class RepeatedStringFieldGenerator : public FieldGenerator {
+class ImmutableStringOneofFieldGenerator
+ : public ImmutableStringFieldGenerator {
public:
- explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
- int messageBitIndex, int builderBitIndex);
- ~RepeatedStringFieldGenerator();
+ ImmutableStringOneofFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~ImmutableStringOneofFieldGenerator();
- // implements FieldGenerator ---------------------------------------
+ private:
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldGenerator);
+};
+
+class RepeatedImmutableStringFieldGenerator : public ImmutableFieldGenerator {
+ public:
+ explicit RepeatedImmutableStringFieldGenerator(
+ const FieldDescriptor* descriptor, int messageBitIndex,
+ int builderBitIndex, Context* context);
+ ~RepeatedImmutableStringFieldGenerator();
+
+ // implements ImmutableFieldGenerator ---------------------------------------
int GetNumBitsForMessage() const;
int GetNumBitsForBuilder() const;
void GenerateInterfaceMembers(io::Printer* printer) const;
@@ -96,11 +132,13 @@ class RepeatedStringFieldGenerator : public FieldGenerator {
void GenerateBuildingCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
void GenerateParsingCodeFromPacked(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:
@@ -108,8 +146,10 @@ class RepeatedStringFieldGenerator : public FieldGenerator {
map<string, string> variables_;
const int messageBitIndex_;
const int builderBitIndex_;
+ Context* context_;
+ ClassNameResolver* name_resolver_;
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator);
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableStringFieldGenerator);
};
} // namespace java
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.cc b/src/google/protobuf/compiler/javanano/javanano_enum.cc
new file mode 100644
index 00000000..f934b05f
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_enum.cc
@@ -0,0 +1,111 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/compiler/javanano/javanano_enum.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Params& params)
+ : params_(params), descriptor_(descriptor) {
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ const EnumValueDescriptor* value = descriptor_->value(i);
+ const EnumValueDescriptor* canonical_value =
+ descriptor_->FindValueByNumber(value->number());
+
+ if (value == canonical_value) {
+ canonical_values_.push_back(value);
+ } else {
+ Alias alias;
+ alias.value = value;
+ alias.canonical_value = canonical_value;
+ aliases_.push_back(alias);
+ }
+ }
+}
+
+EnumGenerator::~EnumGenerator() {}
+
+void EnumGenerator::Generate(io::Printer* printer) {
+ printer->Print(
+ "\n"
+ "// enum $classname$\n",
+ "classname", descriptor_->name());
+
+ // Start of container interface
+ bool use_shell_class = params_.java_enum_style();
+ if (use_shell_class) {
+ printer->Print(
+ "public interface $classname$ {\n",
+ "classname", RenameJavaKeywords(descriptor_->name()));
+ printer->Indent();
+ }
+
+ // Canonical values
+ for (int i = 0; i < canonical_values_.size(); i++) {
+ printer->Print(
+ "public static final int $name$ = $canonical_value$;\n",
+ "name", RenameJavaKeywords(canonical_values_[i]->name()),
+ "canonical_value", SimpleItoa(canonical_values_[i]->number()));
+ }
+
+ // Aliases
+ for (int i = 0; i < aliases_.size(); i++) {
+ printer->Print(
+ "public static final int $name$ = $canonical_name$;\n",
+ "name", RenameJavaKeywords(aliases_[i].value->name()),
+ "canonical_name", RenameJavaKeywords(aliases_[i].canonical_value->name()));
+ }
+
+ // End of container interface
+ if (use_shell_class) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.h b/src/google/protobuf/compiler/javanano/javanano_enum.h
new file mode 100644
index 00000000..10dd3648
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_enum.h
@@ -0,0 +1,87 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class EnumGenerator {
+ public:
+ explicit EnumGenerator(const EnumDescriptor* descriptor, const Params& params);
+ ~EnumGenerator();
+
+ void Generate(io::Printer* printer);
+
+ private:
+ const Params& params_;
+ const EnumDescriptor* descriptor_;
+
+ // The proto language allows multiple enum constants to have the same numeric
+ // value. Java, however, does not allow multiple enum constants to be
+ // considered equivalent. We treat the first defined constant for any
+ // given numeric value as "canonical" and the rest as aliases of that
+ // canonical value.
+ vector<const EnumValueDescriptor*> canonical_values_;
+
+ struct Alias {
+ const EnumValueDescriptor* value;
+ const EnumValueDescriptor* canonical_value;
+ };
+ vector<Alias> aliases_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
new file mode 100644
index 00000000..8a59d323
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
@@ -0,0 +1,520 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javanano/javanano_enum_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+namespace {
+
+// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
+// repeat code between this and the other field types.
+void SetEnumVariables(const Params& params,
+ const FieldDescriptor* descriptor, map<string, string>* variables) {
+ (*variables)["name"] =
+ RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ (*variables)["capitalized_name"] =
+ RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ if (params.use_reference_types_for_primitives()
+ && !params.reftypes_primitive_enums()
+ && !descriptor->is_repeated()) {
+ (*variables)["type"] = "java.lang.Integer";
+ (*variables)["default"] = "null";
+ } else {
+ (*variables)["type"] = "int";
+ (*variables)["default"] = DefaultValue(params, descriptor);
+ }
+ (*variables)["repeated_default"] =
+ "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
+ (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+ (*variables)["tag_size"] = SimpleItoa(
+ internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
+ (*variables)["non_packed_tag"] = SimpleItoa(
+ internal::WireFormatLite::MakeTag(descriptor->number(),
+ internal::WireFormat::WireTypeForFieldType(descriptor->type())));
+ (*variables)["message_name"] = descriptor->containing_type()->name();
+}
+
+void LoadEnumValues(const Params& params,
+ const EnumDescriptor* enum_descriptor, vector<string>* canonical_values) {
+ string enum_class_name = ClassName(params, enum_descriptor);
+ for (int i = 0; i < enum_descriptor->value_count(); i++) {
+ const EnumValueDescriptor* value = enum_descriptor->value(i);
+ const EnumValueDescriptor* canonical_value =
+ enum_descriptor->FindValueByNumber(value->number());
+ if (value == canonical_value) {
+ canonical_values->push_back(
+ enum_class_name + "." + RenameJavaKeywords(value->name()));
+ }
+ }
+}
+
+void PrintCaseLabels(
+ io::Printer* printer, const vector<string>& canonical_values) {
+ for (int i = 0; i < canonical_values.size(); i++) {
+ printer->Print(
+ " case $value$:\n",
+ "value", canonical_values[i]);
+ }
+}
+
+} // namespace
+
+// ===================================================================
+
+EnumFieldGenerator::
+EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetEnumVariables(params, descriptor, &variables_);
+ LoadEnumValues(params, descriptor->enum_type(), &canonical_values_);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public $type$ $name$;\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$;\n");
+ }
+}
+
+void EnumFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $default$;\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "has$capitalized_name$ = false;\n");
+ }
+}
+
+void EnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int value = input.readInt32();\n"
+ "switch (value) {\n");
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Print(variables_,
+ " this.$name$ = value;\n");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ " has$capitalized_name$ = true;\n");
+ }
+ printer->Print(
+ " break;\n"
+ "}\n");
+ // No default case: in case of invalid value from the wire, preserve old
+ // field value. Also we are not storing the invalid value into the unknown
+ // fields, because there is no way to get the value out.
+}
+
+void EnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ if (descriptor_->is_required() && !params_.generate_has()) {
+ // Always serialize a required field if we don't have the 'has' signal.
+ printer->Print(variables_,
+ "output.writeInt32($number$, this.$name$);\n");
+ } else {
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "if (this.$name$ != $default$ || has$capitalized_name$) {\n");
+ } else {
+ printer->Print(variables_,
+ "if (this.$name$ != $default$) {\n");
+ }
+ printer->Print(variables_,
+ " output.writeInt32($number$, this.$name$);\n"
+ "}\n");
+ }
+}
+
+void EnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ if (descriptor_->is_required() && !params_.generate_has()) {
+ printer->Print(variables_,
+ "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeInt32Size($number$, this.$name$);\n");
+ } else {
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "if (this.$name$ != $default$ || has$capitalized_name$) {\n");
+ } else {
+ printer->Print(variables_,
+ "if (this.$name$ != $default$) {\n");
+ }
+ printer->Print(variables_,
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeInt32Size($number$, this.$name$);\n"
+ "}\n");
+ }
+}
+
+void EnumFieldGenerator::GenerateEqualsCode(io::Printer* printer) const {
+ if (params_.use_reference_types_for_primitives()
+ && !params_.reftypes_primitive_enums()) {
+ printer->Print(variables_,
+ "if (this.$name$ == null) {\n"
+ " if (other.$name$ != null) {\n"
+ " return false;\n"
+ " }\n"
+ "} else if (!this.$name$.equals(other.$name$)) {\n"
+ " return false;"
+ "}\n");
+ } else {
+ // We define equality as serialized form equality. If generate_has(),
+ // then if the field value equals the default value in both messages,
+ // but one's 'has' field is set and the other's is not, the serialized
+ // forms are different and we should return false.
+ printer->Print(variables_,
+ "if (this.$name$ != other.$name$");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (this.$name$ == $default$\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ "}\n");
+ }
+}
+
+void EnumFieldGenerator::GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(
+ "result = 31 * result + ");
+ if (params_.use_reference_types_for_primitives()
+ && !params_.reftypes_primitive_enums()) {
+ printer->Print(variables_,
+ "(this.$name$ == null ? 0 : this.$name$)");
+ } else {
+ printer->Print(variables_,
+ "this.$name$");
+ }
+ printer->Print(";\n");
+}
+
+// ===================================================================
+
+AccessorEnumFieldGenerator::
+AccessorEnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params, int has_bit_index)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetEnumVariables(params, descriptor, &variables_);
+ LoadEnumValues(params, descriptor->enum_type(), &canonical_values_);
+ SetBitOperationVariables("has", has_bit_index, &variables_);
+}
+
+AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {}
+
+void AccessorEnumFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "private int $name$_;\n"
+ "public int get$capitalized_name$() {\n"
+ " return $name$_;\n"
+ "}\n"
+ "public $message_name$ set$capitalized_name$(int value) {\n"
+ " $name$_ = value;\n"
+ " $set_has$;\n"
+ " return this;\n"
+ "}\n"
+ "public boolean has$capitalized_name$() {\n"
+ " return $get_has$;\n"
+ "}\n"
+ "public $message_name$ clear$capitalized_name$() {\n"
+ " $name$_ = $default$;\n"
+ " $clear_has$;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_ = $default$;\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int value = input.readInt32();\n"
+ "switch (value) {\n");
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Print(variables_,
+ " $name$_ = value;\n"
+ " $set_has$;\n"
+ " break;\n"
+ "}\n");
+ // No default case: in case of invalid value from the wire, preserve old
+ // field value. Also we are not storing the invalid value into the unknown
+ // fields, because there is no way to get the value out.
+}
+
+void AccessorEnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has$) {\n"
+ " output.writeInt32($number$, $name$_);\n"
+ "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has$) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeInt32Size($number$, $name$_);\n"
+ "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || $name$_ != other.$name$_) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result + $name$_;\n");
+}
+
+// ===================================================================
+
+RepeatedEnumFieldGenerator::
+RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetEnumVariables(params, descriptor, &variables_);
+ LoadEnumValues(params, descriptor->enum_type(), &canonical_values_);
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+
+void RepeatedEnumFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public $type$[] $name$;\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $repeated_default$;\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // First, figure out the maximum length of the array, then parse,
+ // and finally copy the valid values to the field.
+ printer->Print(variables_,
+ "int length = com.google.protobuf.nano.WireFormatNano\n"
+ " .getRepeatedFieldArrayLength(input, $non_packed_tag$);\n"
+ "int[] validValues = new int[length];\n"
+ "int validCount = 0;\n"
+ "for (int i = 0; i < length; i++) {\n"
+ " if (i != 0) { // tag for first value already consumed.\n"
+ " input.readTag();\n"
+ " }\n"
+ " int value = input.readInt32();\n"
+ " switch (value) {\n");
+ printer->Indent();
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Outdent();
+ printer->Print(variables_,
+ " validValues[validCount++] = value;\n"
+ " break;\n"
+ " }\n"
+ "}\n"
+ "if (validCount != 0) {\n"
+ " int i = this.$name$ == null ? 0 : this.$name$.length;\n"
+ " if (i == 0 && validCount == validValues.length) {\n"
+ " this.$name$ = validValues;\n"
+ " } else {\n"
+ " int[] newArray = new int[i + validCount];\n"
+ " if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ " }\n"
+ " java.lang.System.arraycopy(validValues, 0, newArray, i, validCount);\n"
+ " this.$name$ = newArray;\n"
+ " }\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateMergingCodeFromPacked(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int bytes = input.readRawVarint32();\n"
+ "int limit = input.pushLimit(bytes);\n"
+ "// First pass to compute array length.\n"
+ "int arrayLength = 0;\n"
+ "int startPos = input.getPosition();\n"
+ "while (input.getBytesUntilLimit() > 0) {\n"
+ " switch (input.readInt32()) {\n");
+ printer->Indent();
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Outdent();
+ printer->Print(variables_,
+ " arrayLength++;\n"
+ " break;\n"
+ " }\n"
+ "}\n"
+ "if (arrayLength != 0) {\n"
+ " input.rewindToPosition(startPos);\n"
+ " int i = this.$name$ == null ? 0 : this.$name$.length;\n"
+ " int[] newArray = new int[i + arrayLength];\n"
+ " if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ " }\n"
+ " while (input.getBytesUntilLimit() > 0) {\n"
+ " int value = input.readInt32();\n"
+ " switch (value) {\n");
+ printer->Indent();
+ printer->Indent();
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(variables_,
+ " newArray[i++] = value;\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " this.$name$ = newArray;\n"
+ "}\n"
+ "input.popLimit(limit);\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateRepeatedDataSizeCode(io::Printer* printer) const {
+ // Creates a variable dataSize and puts the serialized size in there.
+ printer->Print(variables_,
+ "int dataSize = 0;\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " int element = this.$name$[i];\n"
+ " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeInt32SizeNoTag(element);\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n");
+ printer->Indent();
+
+ if (descriptor_->options().packed()) {
+ GenerateRepeatedDataSizeCode(printer);
+ printer->Print(variables_,
+ "output.writeRawVarint32($tag$);\n"
+ "output.writeRawVarint32(dataSize);\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " output.writeRawVarint32(this.$name$[i]);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " output.writeInt32($number$, this.$name$[i]);\n"
+ "}\n");
+ }
+
+ printer->Outdent();
+ printer->Print(variables_,
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n");
+ printer->Indent();
+
+ GenerateRepeatedDataSizeCode(printer);
+
+ printer->Print(
+ "size += dataSize;\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "size += $tag_size$;\n"
+ "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeRawVarint32Size(dataSize);\n");
+ } else {
+ printer->Print(variables_,
+ "size += $tag_size$ * this.$name$.length;\n");
+ }
+
+ printer->Outdent();
+
+ printer->Print(
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!com.google.protobuf.nano.InternalNano.equals(\n"
+ " this.$name$, other.$name$)) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
new file mode 100644
index 00000000..00adc61f
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
@@ -0,0 +1,125 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__
+
+#include <map>
+#include <string>
+#include <vector>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class EnumFieldGenerator : public FieldGenerator {
+ public:
+ explicit EnumFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params);
+ ~EnumFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ vector<string> canonical_values_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class AccessorEnumFieldGenerator : public FieldGenerator {
+ public:
+ explicit AccessorEnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params, int has_bit_index);
+ ~AccessorEnumFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ vector<string> canonical_values_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorEnumFieldGenerator);
+};
+
+class RepeatedEnumFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedEnumFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params);
+ ~RepeatedEnumFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateMergingCodeFromPacked(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
+
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ vector<string> canonical_values_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.cc b/src/google/protobuf/compiler/javanano/javanano_extension.cc
new file mode 100644
index 00000000..754ed550
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.cc
@@ -0,0 +1,150 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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: bduff@google.com (Brian Duff)
+
+#include <google/protobuf/compiler/javanano/javanano_extension.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+const char* GetTypeConstantName(const FieldDescriptor::Type type) {
+ switch (type) {
+ case FieldDescriptor::TYPE_INT32 : return "TYPE_INT32" ;
+ case FieldDescriptor::TYPE_UINT32 : return "TYPE_UINT32" ;
+ case FieldDescriptor::TYPE_SINT32 : return "TYPE_SINT32" ;
+ case FieldDescriptor::TYPE_FIXED32 : return "TYPE_FIXED32" ;
+ case FieldDescriptor::TYPE_SFIXED32: return "TYPE_SFIXED32";
+ case FieldDescriptor::TYPE_INT64 : return "TYPE_INT64" ;
+ case FieldDescriptor::TYPE_UINT64 : return "TYPE_UINT64" ;
+ case FieldDescriptor::TYPE_SINT64 : return "TYPE_SINT64" ;
+ case FieldDescriptor::TYPE_FIXED64 : return "TYPE_FIXED64" ;
+ case FieldDescriptor::TYPE_SFIXED64: return "TYPE_SFIXED64";
+ case FieldDescriptor::TYPE_FLOAT : return "TYPE_FLOAT" ;
+ case FieldDescriptor::TYPE_DOUBLE : return "TYPE_DOUBLE" ;
+ case FieldDescriptor::TYPE_BOOL : return "TYPE_BOOL" ;
+ case FieldDescriptor::TYPE_STRING : return "TYPE_STRING" ;
+ case FieldDescriptor::TYPE_BYTES : return "TYPE_BYTES" ;
+ case FieldDescriptor::TYPE_ENUM : return "TYPE_ENUM" ;
+ case FieldDescriptor::TYPE_GROUP : return "TYPE_GROUP" ;
+ case FieldDescriptor::TYPE_MESSAGE : return "TYPE_MESSAGE" ;
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+} // namespace
+
+void SetVariables(const FieldDescriptor* descriptor, const Params params,
+ map<string, string>* variables) {
+ (*variables)["extends"] = ClassName(params, descriptor->containing_type());
+ (*variables)["name"] = RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ bool repeated = descriptor->is_repeated();
+ (*variables)["repeated"] = repeated ? "Repeated" : "";
+ (*variables)["type"] = GetTypeConstantName(descriptor->type());
+ JavaType java_type = GetJavaType(descriptor->type());
+ string tag = SimpleItoa(WireFormat::MakeTag(descriptor));
+ if (java_type == JAVATYPE_MESSAGE) {
+ (*variables)["ext_type"] = "MessageTyped";
+ string message_type = ClassName(params, descriptor->message_type());
+ if (repeated) {
+ message_type += "[]";
+ }
+ (*variables)["class"] = message_type;
+ // For message typed extensions, tags_params contains a single tag
+ // for both singular and repeated cases.
+ (*variables)["tag_params"] = tag;
+ } else {
+ (*variables)["ext_type"] = "PrimitiveTyped";
+ if (!repeated) {
+ (*variables)["class"] = BoxedPrimitiveTypeName(java_type);
+ (*variables)["tag_params"] = tag;
+ } else {
+ (*variables)["class"] = PrimitiveTypeName(java_type) + "[]";
+ if (!descriptor->is_packable()) {
+ // Non-packable: nonPackedTag == tag, packedTag == 0
+ (*variables)["tag_params"] = tag + ", " + tag + ", 0";
+ } else if (descriptor->options().packed()) {
+ // Packable and packed: tag == packedTag
+ string non_packed_tag = SimpleItoa(WireFormatLite::MakeTag(
+ descriptor->number(),
+ WireFormat::WireTypeForFieldType(descriptor->type())));
+ (*variables)["tag_params"] = tag + ", " + non_packed_tag + ", " + tag;
+ } else {
+ // Packable and not packed: tag == nonPackedTag
+ string packed_tag = SimpleItoa(WireFormatLite::MakeTag(
+ descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+ (*variables)["tag_params"] = tag + ", " + tag + ", " + packed_tag;
+ }
+ }
+ }
+}
+
+ExtensionGenerator::
+ExtensionGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : params_(params), descriptor_(descriptor) {
+ SetVariables(descriptor, params, &variables_);
+}
+
+ExtensionGenerator::~ExtensionGenerator() {}
+
+void ExtensionGenerator::Generate(io::Printer* printer) const {
+ printer->Print("\n");
+ PrintFieldComment(printer, descriptor_);
+ printer->Print(variables_,
+ "public static final com.google.protobuf.nano.Extension<\n"
+ " $extends$,\n"
+ " $class$> $name$ =\n"
+ " com.google.protobuf.nano.Extension.create$repeated$$ext_type$(\n"
+ " com.google.protobuf.nano.Extension.$type$,\n"
+ " $class$.class,\n"
+ " $tag_params$);\n");
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.h b/src/google/protobuf/compiler/javanano/javanano_extension.h
new file mode 100644
index 00000000..4843e296
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.h
@@ -0,0 +1,74 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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: bduff@google.com (Brian Duff)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/descriptor.pb.h>
+
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class ExtensionGenerator {
+ public:
+ explicit ExtensionGenerator(const FieldDescriptor* descriptor, const Params& params);
+ ~ExtensionGenerator();
+
+ void Generate(io::Printer* printer) const;
+
+ private:
+ const Params& params_;
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.cc b/src/google/protobuf/compiler/javanano/javanano_field.cc
new file mode 100644
index 00000000..85257f3f
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_field.cc
@@ -0,0 +1,209 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/compiler/javanano/javanano_primitive_field.h>
+#include <google/protobuf/compiler/javanano/javanano_enum_field.h>
+#include <google/protobuf/compiler/javanano/javanano_map_field.h>
+#include <google/protobuf/compiler/javanano/javanano_message_field.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+FieldGenerator::~FieldGenerator() {}
+
+bool FieldGenerator::SavedDefaultNeeded() const {
+ // No saved default for this field by default.
+ // Subclasses whose instances may need saved defaults will override this
+ // and return the appropriate value.
+ return false;
+}
+
+void FieldGenerator::GenerateInitSavedDefaultCode(io::Printer* printer) const {
+ // No saved default for this field by default.
+ // Subclasses whose instances may need saved defaults will override this
+ // and generate the appropriate init code to the printer.
+}
+
+void FieldGenerator::GenerateMergingCodeFromPacked(io::Printer* printer) const {
+ // Reaching here indicates a bug. Cases are:
+ // - This FieldGenerator should support packing, but this method should be
+ // overridden.
+ // - This FieldGenerator doesn't support packing, and this method should
+ // never have been called.
+ GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() "
+ << "called on field generator that does not support packing.";
+}
+
+// =============================================
+
+FieldGeneratorMap::FieldGeneratorMap(
+ const Descriptor* descriptor, const Params &params)
+ : descriptor_(descriptor),
+ field_generators_(
+ new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
+
+ int next_has_bit_index = 0;
+ bool saved_defaults_needed = false;
+ // Construct all the FieldGenerators.
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ FieldGenerator* field_generator = MakeGenerator(
+ descriptor->field(i), params, &next_has_bit_index);
+ saved_defaults_needed = saved_defaults_needed
+ || field_generator->SavedDefaultNeeded();
+ field_generators_[i].reset(field_generator);
+ }
+ total_bits_ = next_has_bit_index;
+ saved_defaults_needed_ = saved_defaults_needed;
+}
+
+FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
+ const Params &params, int* next_has_bit_index) {
+ JavaType java_type = GetJavaType(field);
+ if (field->is_repeated()) {
+ switch (java_type) {
+ case JAVATYPE_MESSAGE:
+ if (IsMapEntry(field->message_type())) {
+ return new MapFieldGenerator(field, params);
+ } else {
+ return new RepeatedMessageFieldGenerator(field, params);
+ }
+ case JAVATYPE_ENUM:
+ return new RepeatedEnumFieldGenerator(field, params);
+ default:
+ return new RepeatedPrimitiveFieldGenerator(field, params);
+ }
+ } else if (field->containing_oneof()) {
+ switch (java_type) {
+ case JAVATYPE_MESSAGE:
+ return new MessageOneofFieldGenerator(field, params);
+ case JAVATYPE_ENUM:
+ default:
+ return new PrimitiveOneofFieldGenerator(field, params);
+ }
+ } else if (params.optional_field_accessors() && field->is_optional()
+ && java_type != JAVATYPE_MESSAGE) {
+ // We need a has-bit for each primitive/enum field because their default
+ // values could be same as explicitly set values. But we don't need it
+ // for a message field because they have no defaults and Nano uses 'null'
+ // for unset messages, which cannot be set explicitly.
+ switch (java_type) {
+ case JAVATYPE_ENUM:
+ return new AccessorEnumFieldGenerator(
+ field, params, (*next_has_bit_index)++);
+ default:
+ return new AccessorPrimitiveFieldGenerator(
+ field, params, (*next_has_bit_index)++);
+ }
+ } else {
+ switch (java_type) {
+ case JAVATYPE_MESSAGE:
+ return new MessageFieldGenerator(field, params);
+ case JAVATYPE_ENUM:
+ return new EnumFieldGenerator(field, params);
+ default:
+ return new PrimitiveFieldGenerator(field, params);
+ }
+ }
+}
+
+FieldGeneratorMap::~FieldGeneratorMap() {}
+
+const FieldGenerator& FieldGeneratorMap::get(
+ const FieldDescriptor* field) const {
+ GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
+ return *field_generators_[field->index()];
+}
+
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ (*variables)["oneof_name"] =
+ UnderscoresToCamelCase(descriptor->containing_oneof());
+ (*variables)["oneof_capitalized_name"] =
+ UnderscoresToCapitalizedCamelCase(descriptor->containing_oneof());
+ (*variables)["oneof_index"] =
+ SimpleItoa(descriptor->containing_oneof()->index());
+ (*variables)["set_oneof_case"] =
+ "this." + (*variables)["oneof_name"] +
+ "Case_ = " + SimpleItoa(descriptor->number());
+ (*variables)["clear_oneof_case"] =
+ "this." + (*variables)["oneof_name"] + "Case_ = 0";
+ (*variables)["has_oneof_case"] =
+ "this." + (*variables)["oneof_name"] + "Case_ == " +
+ SimpleItoa(descriptor->number());
+}
+
+void GenerateOneofFieldEquals(const FieldDescriptor* descriptor,
+ const map<string, string>& variables,
+ io::Printer* printer) {
+ if (GetJavaType(descriptor) == JAVATYPE_BYTES) {
+ printer->Print(variables,
+ "if (this.has$capitalized_name$()) {\n"
+ " if (!java.util.Arrays.equals((byte[]) this.$oneof_name$_,\n"
+ " (byte[]) other.$oneof_name$_)) {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+ } else {
+ printer->Print(variables,
+ "if (this.has$capitalized_name$()) {\n"
+ " if (!this.$oneof_name$_.equals(other.$oneof_name$_)) {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+ }
+}
+
+void GenerateOneofFieldHashCode(const FieldDescriptor* descriptor,
+ const map<string, string>& variables,
+ io::Printer* printer) {
+ if (GetJavaType(descriptor) == JAVATYPE_BYTES) {
+ printer->Print(variables,
+ "result = 31 * result + ($has_oneof_case$\n"
+ " ? java.util.Arrays.hashCode((byte[]) this.$oneof_name$_) : 0);\n");
+ } else {
+ printer->Print(variables,
+ "result = 31 * result +\n"
+ " ($has_oneof_case$ ? this.$oneof_name$_.hashCode() : 0);\n");
+ }
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h
new file mode 100644
index 00000000..c2cf091c
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_field.h
@@ -0,0 +1,129 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class FieldGenerator {
+ public:
+ FieldGenerator(const Params& params) : params_(params) {}
+ virtual ~FieldGenerator();
+
+ virtual bool SavedDefaultNeeded() const;
+ virtual void GenerateInitSavedDefaultCode(io::Printer* printer) const;
+
+ // Generates code for Java fields and methods supporting this field.
+ // If this field needs a saved default (SavedDefaultNeeded() is true),
+ // then @lazy_init controls how the static field for that default value
+ // and its initialization code should be generated. If @lazy_init is
+ // true, the static field is not declared final and the initialization
+ // code is generated only when GenerateInitSavedDefaultCode is called;
+ // otherwise, the static field is declared final and initialized inline.
+ // GenerateInitSavedDefaultCode will not be called in the latter case.
+ virtual void GenerateMembers(
+ io::Printer* printer, bool lazy_init) const = 0;
+
+ virtual void GenerateClearCode(io::Printer* printer) const = 0;
+ virtual void GenerateMergingCode(io::Printer* printer) const = 0;
+
+ // Generates code to merge from packed serialized form. The default
+ // implementation will fail; subclasses which can handle packed serialized
+ // forms will override this and print appropriate code to the printer.
+ virtual void GenerateMergingCodeFromPacked(io::Printer* printer) const;
+
+ virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
+ virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
+ virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
+ virtual void GenerateHashCodeCode(io::Printer* printer) const = 0;
+
+ protected:
+ const Params& params_;
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
+};
+
+// Convenience class which constructs FieldGenerators for a Descriptor.
+class FieldGeneratorMap {
+ public:
+ explicit FieldGeneratorMap(const Descriptor* descriptor, const Params &params);
+ ~FieldGeneratorMap();
+
+ const FieldGenerator& get(const FieldDescriptor* field) const;
+ int total_bits() const { return total_bits_; }
+ bool saved_defaults_needed() const { return saved_defaults_needed_; }
+
+ private:
+ const Descriptor* descriptor_;
+ scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+ int total_bits_;
+ bool saved_defaults_needed_;
+
+ static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
+ const Params &params, int* next_has_bit_index);
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
+};
+
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables);
+void GenerateOneofFieldEquals(const FieldDescriptor* descriptor,
+ const map<string, string>& variables,
+ io::Printer* printer);
+void GenerateOneofFieldHashCode(const FieldDescriptor* descriptor,
+ const map<string, string>& variables,
+ io::Printer* printer);
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_file.cc b/src/google/protobuf/compiler/javanano/javanano_file.cc
new file mode 100644
index 00000000..3676ab9d
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_file.cc
@@ -0,0 +1,263 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <iostream>
+
+#include <google/protobuf/compiler/javanano/javanano_file.h>
+#include <google/protobuf/compiler/javanano/javanano_enum.h>
+#include <google/protobuf/compiler/javanano/javanano_extension.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/compiler/javanano/javanano_message.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+namespace {
+
+// Recursively searches the given message to see if it contains any extensions.
+bool UsesExtensions(const Message& message) {
+ const Reflection* reflection = message.GetReflection();
+
+ // We conservatively assume that unknown fields are extensions.
+ if (reflection->GetUnknownFields(message).field_count() > 0) return true;
+
+ vector<const FieldDescriptor*> fields;
+ reflection->ListFields(message, &fields);
+
+ for (int i = 0; i < fields.size(); i++) {
+ if (fields[i]->is_extension()) return true;
+
+ if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (fields[i]->is_repeated()) {
+ int size = reflection->FieldSize(message, fields[i]);
+ for (int j = 0; j < size; j++) {
+ const Message& sub_message =
+ reflection->GetRepeatedMessage(message, fields[i], j);
+ if (UsesExtensions(sub_message)) return true;
+ }
+ } else {
+ const Message& sub_message = reflection->GetMessage(message, fields[i]);
+ if (UsesExtensions(sub_message)) return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+} // namespace
+
+FileGenerator::FileGenerator(const FileDescriptor* file, const Params& params)
+ : file_(file),
+ params_(params),
+ java_package_(FileJavaPackage(params, file)),
+ classname_(FileClassName(params, file)) {}
+
+FileGenerator::~FileGenerator() {}
+
+bool FileGenerator::Validate(string* error) {
+ // Check for extensions
+ FileDescriptorProto file_proto;
+ file_->CopyTo(&file_proto);
+ if (UsesExtensions(file_proto) && !params_.store_unknown_fields()) {
+ error->assign(file_->name());
+ error->append(
+ ": Java NANO_RUNTIME only supports extensions when the "
+ "'store_unknown_fields' generator option is 'true'.");
+ return false;
+ }
+
+ if (file_->service_count() != 0 && !params_.ignore_services()) {
+ error->assign(file_->name());
+ error->append(
+ ": Java NANO_RUNTIME does not support services\"");
+ return false;
+ }
+
+ if (!IsOuterClassNeeded(params_, file_)) {
+ return true;
+ }
+
+ // Check whether legacy javanano generator would omit the outer class.
+ if (!params_.has_java_outer_classname(file_->name())
+ && file_->message_type_count() == 1
+ && file_->enum_type_count() == 0 && file_->extension_count() == 0) {
+ cout << "INFO: " << file_->name() << ":" << endl;
+ cout << "Javanano generator has changed to align with java generator. "
+ "An outer class will be created for this file and the single message "
+ "in the file will become a nested class. Use java_multiple_files to "
+ "skip generating the outer class, or set an explicit "
+ "java_outer_classname to suppress this message." << endl;
+ }
+
+ // Check that no class name matches the file's class name. This is a common
+ // problem that leads to Java compile errors that can be hard to understand.
+ // It's especially bad when using the java_multiple_files, since we would
+ // end up overwriting the outer class with one of the inner ones.
+ bool found_conflict = false;
+ for (int i = 0; !found_conflict && i < file_->message_type_count(); i++) {
+ if (file_->message_type(i)->name() == classname_) {
+ found_conflict = true;
+ }
+ }
+ if (params_.java_enum_style()) {
+ for (int i = 0; !found_conflict && i < file_->enum_type_count(); i++) {
+ if (file_->enum_type(i)->name() == classname_) {
+ found_conflict = true;
+ }
+ }
+ }
+ if (found_conflict) {
+ error->assign(file_->name());
+ error->append(
+ ": Cannot generate Java output because the file's outer class name, \"");
+ error->append(classname_);
+ error->append(
+ "\", matches the name of one of the types declared inside it. "
+ "Please either rename the type or use the java_outer_classname "
+ "option to specify a different outer class name for the .proto file.");
+ return false;
+ }
+ return true;
+}
+
+void FileGenerator::Generate(io::Printer* printer) {
+ // We don't import anything because we refer to all classes by their
+ // fully-qualified names in the generated source.
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
+ if (!java_package_.empty()) {
+ printer->Print(
+ "\n"
+ "package $package$;\n",
+ "package", java_package_);
+ }
+
+ // Note: constants (from enums, emitted in the loop below) may have the same names as constants
+ // in the nested classes. This causes Java warnings, but is not fatal, so we suppress those
+ // warnings here in the top-most class declaration.
+ printer->Print(
+ "\n"
+ "@SuppressWarnings(\"hiding\")\n"
+ "public interface $classname$ {\n",
+ "classname", classname_);
+ printer->Indent();
+
+ // -----------------------------------------------------------------
+
+ // Extensions.
+ for (int i = 0; i < file_->extension_count(); i++) {
+ ExtensionGenerator(file_->extension(i), params_).Generate(printer);
+ }
+
+ // Enums.
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ EnumGenerator(file_->enum_type(i), params_).Generate(printer);
+ }
+
+ // Messages.
+ if (!params_.java_multiple_files(file_->name())) {
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ MessageGenerator(file_->message_type(i), params_).Generate(printer);
+ }
+ }
+
+ // Static variables.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ // TODO(kenton): Reuse MessageGenerator objects?
+ MessageGenerator(file_->message_type(i), params_).GenerateStaticVariables(printer);
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+}
+
+template<typename GeneratorClass, typename DescriptorClass>
+static void GenerateSibling(const string& package_dir,
+ const string& java_package,
+ const DescriptorClass* descriptor,
+ GeneratorContext* output_directory,
+ vector<string>* file_list,
+ const Params& params) {
+ string filename = package_dir + descriptor->name() + ".java";
+ file_list->push_back(filename);
+
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(filename));
+ io::Printer printer(output.get(), '$');
+
+ printer.Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
+ if (!java_package.empty()) {
+ printer.Print(
+ "\n"
+ "package $package$;\n",
+ "package", java_package);
+ }
+
+ GeneratorClass(descriptor, params).Generate(&printer);
+}
+
+void FileGenerator::GenerateSiblings(const string& package_dir,
+ GeneratorContext* output_directory,
+ vector<string>* file_list) {
+ if (params_.java_multiple_files(file_->name())) {
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ GenerateSibling<MessageGenerator>(package_dir, java_package_,
+ file_->message_type(i),
+ output_directory, file_list, params_);
+ }
+
+ if (params_.java_enum_style()) {
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ GenerateSibling<EnumGenerator>(package_dir, java_package_,
+ file_->enum_type(i),
+ output_directory, file_list, params_);
+ }
+ }
+ }
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_file.h b/src/google/protobuf/compiler/javanano/javanano_file.h
new file mode 100644
index 00000000..217eafe2
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_file.h
@@ -0,0 +1,94 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__
+
+#include <string>
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+
+namespace google {
+namespace protobuf {
+ class FileDescriptor; // descriptor.h
+ namespace io {
+ class Printer; // printer.h
+ }
+ namespace compiler {
+ class GeneratorContext; // code_generator.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class FileGenerator {
+ public:
+ explicit FileGenerator(const FileDescriptor* file, const Params& params);
+ ~FileGenerator();
+
+ // Checks for problems that would otherwise lead to cryptic compile errors.
+ // Returns true if there are no problems, or writes an error description to
+ // the given string and returns false otherwise.
+ bool Validate(string* error);
+
+ void Generate(io::Printer* printer);
+
+ // If we aren't putting everything into one file, this will write all the
+ // files other than the outer file (i.e. one for each message, enum, and
+ // service type).
+ void GenerateSiblings(const string& package_dir,
+ GeneratorContext* output_directory,
+ vector<string>* file_list);
+
+ const string& java_package() { return java_package_; }
+ const string& classname() { return classname_; }
+
+ private:
+ const FileDescriptor* file_;
+ const Params& params_;
+ string java_package_;
+ string classname_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
new file mode 100644
index 00000000..b5fbcd5f
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -0,0 +1,219 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/compiler/javanano/javanano_generator.h>
+#include <google/protobuf/compiler/javanano/javanano_file.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+namespace {
+
+string TrimString(const string& s) {
+ string::size_type start = s.find_first_not_of(" \n\r\t");
+ if (start == string::npos) {
+ return "";
+ }
+ string::size_type end = s.find_last_not_of(" \n\r\t") + 1;
+ return s.substr(start, end - start);
+}
+
+} // namespace
+
+void UpdateParamsRecursively(Params& params,
+ const FileDescriptor* file) {
+ // Add any parameters for this file
+ if (file->options().has_java_outer_classname()) {
+ params.set_java_outer_classname(
+ file->name(), file->options().java_outer_classname());
+ }
+ if (file->options().has_java_package()) {
+ params.set_java_package(
+ file->name(), file->options().java_package());
+ }
+ if (file->options().has_java_multiple_files()) {
+ params.set_java_multiple_files(
+ file->name(), file->options().java_multiple_files());
+ }
+
+ // Loop through all dependent files recursively
+ // adding dep
+ for (int i = 0; i < file->dependency_count(); i++) {
+ UpdateParamsRecursively(params, file->dependency(i));
+ }
+}
+
+JavaNanoGenerator::JavaNanoGenerator() {}
+JavaNanoGenerator::~JavaNanoGenerator() {}
+
+bool JavaNanoGenerator::Generate(const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* output_directory,
+ string* error) const {
+ vector<pair<string, string> > options;
+
+ ParseGeneratorParameter(parameter, &options);
+
+ // -----------------------------------------------------------------
+ // parse generator options
+
+ // Name a file where we will write a list of generated file names, one
+ // per line.
+ string output_list_file;
+ Params params(file->name());
+
+ // Update per file params
+ UpdateParamsRecursively(params, file);
+
+ // Replace any existing options with ones from command line
+ for (int i = 0; i < options.size(); i++) {
+ string option_name = TrimString(options[i].first);
+ string option_value = TrimString(options[i].second);
+ if (option_name == "output_list_file") {
+ output_list_file = option_value;
+ } else if (option_name == "java_package") {
+ vector<string> parts;
+ SplitStringUsing(option_value, "|", &parts);
+ if (parts.size() != 2) {
+ *error = "Bad java_package, expecting filename|PackageName found '"
+ + option_value + "'";
+ return false;
+ }
+ params.set_java_package(parts[0], parts[1]);
+ } else if (option_name == "java_outer_classname") {
+ vector<string> parts;
+ SplitStringUsing(option_value, "|", &parts);
+ if (parts.size() != 2) {
+ *error = "Bad java_outer_classname, "
+ "expecting filename|ClassName found '"
+ + option_value + "'";
+ return false;
+ }
+ params.set_java_outer_classname(parts[0], parts[1]);
+ } else if (option_name == "store_unknown_fields") {
+ params.set_store_unknown_fields(option_value == "true");
+ } else if (option_name == "java_multiple_files") {
+ params.set_override_java_multiple_files(option_value == "true");
+ } else if (option_name == "java_nano_generate_has") {
+ params.set_generate_has(option_value == "true");
+ } else if (option_name == "enum_style") {
+ params.set_java_enum_style(option_value == "java");
+ } else if (option_name == "optional_field_style") {
+ params.set_optional_field_accessors(option_value == "accessors");
+ params.set_use_reference_types_for_primitives(option_value == "reftypes"
+ || option_value == "reftypes_compat_mode");
+ params.set_reftypes_primitive_enums(
+ option_value == "reftypes_compat_mode");
+ if (option_value == "reftypes_compat_mode") {
+ params.set_generate_clear(false);
+ }
+ } else if (option_name == "generate_equals") {
+ params.set_generate_equals(option_value == "true");
+ } else if (option_name == "ignore_services") {
+ params.set_ignore_services(option_value == "true");
+ } else if (option_name == "parcelable_messages") {
+ params.set_parcelable_messages(option_value == "true");
+ } else {
+ *error = "Ignore unknown javanano generator option: " + option_name;
+ }
+ }
+
+ // Check illegal parameter combinations
+ // Note: the enum-like optional_field_style generator param ensures
+ // that we can never have illegal combinations of field styles
+ // (e.g. reftypes and accessors can't be on at the same time).
+ if (params.generate_has()
+ && (params.optional_field_accessors()
+ || params.use_reference_types_for_primitives())) {
+ error->assign("java_nano_generate_has=true cannot be used in conjunction"
+ " with optional_field_style=accessors or optional_field_style=reftypes");
+ return false;
+ }
+
+ // -----------------------------------------------------------------
+
+ FileGenerator file_generator(file, params);
+ if (!file_generator.Validate(error)) {
+ return false;
+ }
+
+ string package_dir =
+ StringReplace(file_generator.java_package(), ".", "/", true);
+ if (!package_dir.empty()) package_dir += "/";
+
+ vector<string> all_files;
+
+ if (IsOuterClassNeeded(params, file)) {
+ string java_filename = package_dir;
+ java_filename += file_generator.classname();
+ java_filename += ".java";
+ all_files.push_back(java_filename);
+
+ // Generate main java file.
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(java_filename));
+ io::Printer printer(output.get(), '$');
+ file_generator.Generate(&printer);
+ }
+
+ // Generate sibling files.
+ file_generator.GenerateSiblings(package_dir, output_directory, &all_files);
+
+ // Generate output list if requested.
+ if (!output_list_file.empty()) {
+ // Generate output list. This is just a simple text file placed in a
+ // deterministic location which lists the .java files being generated.
+ scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
+ output_directory->Open(output_list_file));
+ io::Printer srclist_printer(srclist_raw_output.get(), '$');
+ for (int i = 0; i < all_files.size(); i++) {
+ srclist_printer.Print("$filename$\n", "filename", all_files[i]);
+ }
+ }
+
+ return true;
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.h b/src/google/protobuf/compiler/javanano/javanano_generator.h
new file mode 100644
index 00000000..6f9f7f2a
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.h
@@ -0,0 +1,72 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+//
+// Generates Java nano code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__
+
+#include <string>
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+// CodeGenerator implementation which generates Java nano code. If you create your
+// own protocol compiler binary and you want it to support Java output for the
+// nano runtime, you can do so by registering an instance of this CodeGenerator with
+// the CommandLineInterface in your main() function.
+class LIBPROTOC_EXPORT JavaNanoGenerator : public CodeGenerator {
+ public:
+ JavaNanoGenerator();
+ ~JavaNanoGenerator();
+
+ // implements CodeGenerator ----------------------------------------
+ bool Generate(const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* output_directory,
+ string* error) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaNanoGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
new file mode 100644
index 00000000..0d2ae9db
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
@@ -0,0 +1,585 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <limits>
+#include <vector>
+
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+const char kThickSeparator[] =
+ "// ===================================================================\n";
+const char kThinSeparator[] =
+ "// -------------------------------------------------------------------\n";
+
+class RenameKeywords {
+ private:
+ hash_set<string> java_keywords_set_;
+
+ public:
+ RenameKeywords() {
+ static const char* kJavaKeywordsList[] = {
+ // Reserved Java Keywords
+ "abstract", "assert", "boolean", "break", "byte", "case", "catch",
+ "char", "class", "const", "continue", "default", "do", "double", "else",
+ "enum", "extends", "final", "finally", "float", "for", "goto", "if",
+ "implements", "import", "instanceof", "int", "interface", "long",
+ "native", "new", "package", "private", "protected", "public", "return",
+ "short", "static", "strictfp", "super", "switch", "synchronized",
+ "this", "throw", "throws", "transient", "try", "void", "volatile", "while",
+
+ // Reserved Keywords for Literals
+ "false", "null", "true"
+ };
+
+ for (int i = 0; i < GOOGLE_ARRAYSIZE(kJavaKeywordsList); i++) {
+ java_keywords_set_.insert(kJavaKeywordsList[i]);
+ }
+ }
+
+ // Used to rename the a field name if it's a java keyword. Specifically
+ // this is used to rename the ["name"] or ["capitalized_name"] field params.
+ // (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html)
+ string RenameJavaKeywordsImpl(const string& input) {
+ string result = input;
+
+ if (java_keywords_set_.find(result) != java_keywords_set_.end()) {
+ result += "_";
+ }
+
+ return result;
+ }
+
+};
+
+static RenameKeywords sRenameKeywords;
+
+namespace {
+
+const char* kDefaultPackage = "";
+
+const string& FieldName(const FieldDescriptor* field) {
+ // Groups are hacky: The name of the field is just the lower-cased name
+ // of the group type. In Java, though, we would like to retain the original
+ // capitalization of the type name.
+ if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ return field->message_type()->name();
+ } else {
+ return field->name();
+ }
+}
+
+string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) {
+ string result;
+ // Note: I distrust ctype.h due to locales.
+ for (int i = 0; i < input.size(); i++) {
+ if ('a' <= input[i] && input[i] <= 'z') {
+ if (cap_next_letter) {
+ result += input[i] + ('A' - 'a');
+ } else {
+ result += input[i];
+ }
+ cap_next_letter = false;
+ } else if ('A' <= input[i] && input[i] <= 'Z') {
+ if (i == 0 && !cap_next_letter) {
+ // Force first letter to lower-case unless explicitly told to
+ // capitalize it.
+ result += input[i] + ('a' - 'A');
+ } else {
+ // Capital letters after the first are left as-is.
+ result += input[i];
+ }
+ cap_next_letter = false;
+ } else if ('0' <= input[i] && input[i] <= '9') {
+ result += input[i];
+ cap_next_letter = true;
+ } else {
+ cap_next_letter = true;
+ }
+ }
+ return result;
+}
+
+} // namespace
+
+string UnderscoresToCamelCase(const FieldDescriptor* field) {
+ return UnderscoresToCamelCaseImpl(FieldName(field), false);
+}
+
+string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
+ return UnderscoresToCamelCaseImpl(FieldName(field), true);
+}
+
+string UnderscoresToCamelCase(const MethodDescriptor* method) {
+ return UnderscoresToCamelCaseImpl(method->name(), false);
+}
+
+string UnderscoresToCamelCase(const OneofDescriptor* oneof) {
+ return UnderscoresToCamelCaseImpl(oneof->name(), false);
+}
+
+string UnderscoresToCapitalizedCamelCase(const OneofDescriptor* oneof) {
+ return UnderscoresToCamelCaseImpl(oneof->name(), true);
+}
+
+string RenameJavaKeywords(const string& input) {
+ return sRenameKeywords.RenameJavaKeywordsImpl(input);
+}
+
+string StripProto(const string& filename) {
+ if (HasSuffixString(filename, ".protodevel")) {
+ return StripSuffixString(filename, ".protodevel");
+ } else {
+ return StripSuffixString(filename, ".proto");
+ }
+}
+
+string FileClassName(const Params& params, const FileDescriptor* file) {
+ if (params.has_java_outer_classname(file->name())) {
+ return params.java_outer_classname(file->name());
+ } else {
+ // Use the filename itself with underscores removed
+ // and a CamelCase style name.
+ string basename;
+ string::size_type last_slash = file->name().find_last_of('/');
+ if (last_slash == string::npos) {
+ basename = file->name();
+ } else {
+ basename = file->name().substr(last_slash + 1);
+ }
+ return UnderscoresToCamelCaseImpl(StripProto(basename), true);
+ }
+}
+
+string FileJavaPackage(const Params& params, const FileDescriptor* file) {
+ if (params.has_java_package(file->name())) {
+ return params.java_package(file->name());
+ } else {
+ string result = kDefaultPackage;
+ if (!file->package().empty()) {
+ if (!result.empty()) result += '.';
+ result += file->package();
+ }
+ return result;
+ }
+}
+
+bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) {
+ // If java_multiple_files is false, the outer class is always needed.
+ if (!params.java_multiple_files(file->name())) {
+ return true;
+ }
+
+ // File-scope extensions need the outer class as the scope.
+ if (file->extension_count() != 0) {
+ return true;
+ }
+
+ // If container interfaces are not generated, file-scope enums need the
+ // outer class as the scope.
+ if (file->enum_type_count() != 0 && !params.java_enum_style()) {
+ return true;
+ }
+
+ return false;
+}
+
+string ToJavaName(const Params& params, const string& name, bool is_class,
+ const Descriptor* parent, const FileDescriptor* file) {
+ string result;
+ if (parent != NULL) {
+ result.append(ClassName(params, parent));
+ } else if (is_class && params.java_multiple_files(file->name())) {
+ result.append(FileJavaPackage(params, file));
+ } else {
+ result.append(ClassName(params, file));
+ }
+ if (!result.empty()) result.append(1, '.');
+ result.append(RenameJavaKeywords(name));
+ return result;
+}
+
+string ClassName(const Params& params, const FileDescriptor* descriptor) {
+ string result = FileJavaPackage(params, descriptor);
+ if (!result.empty()) result += '.';
+ result += FileClassName(params, descriptor);
+ return result;
+}
+
+string ClassName(const Params& params, const EnumDescriptor* descriptor) {
+ const Descriptor* parent = descriptor->containing_type();
+ // When using Java enum style, an enum's class name contains the enum name.
+ // Use the standard ToJavaName translation.
+ if (params.java_enum_style()) {
+ return ToJavaName(params, descriptor->name(), true, parent,
+ descriptor->file());
+ }
+ // Otherwise the enum members are accessed from the enclosing class.
+ if (parent != NULL) {
+ return ClassName(params, parent);
+ } else {
+ return ClassName(params, descriptor->file());
+ }
+}
+
+string FieldConstantName(const FieldDescriptor *field) {
+ string name = field->name() + "_FIELD_NUMBER";
+ UpperString(&name);
+ return name;
+}
+
+string FieldDefaultConstantName(const FieldDescriptor *field) {
+ return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default";
+}
+
+void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
+ // We don't want to print group bodies so we cut off after the first line
+ // (the second line for extensions).
+ string def = field->DebugString();
+ string::size_type first_line_end = def.find_first_of('\n');
+ printer->Print("// $def$\n",
+ "def", def.substr(0, first_line_end));
+ if (field->is_extension()) {
+ string::size_type second_line_start = first_line_end + 1;
+ string::size_type second_line_length =
+ def.find('\n', second_line_start) - second_line_start;
+ printer->Print("// $def$\n",
+ "def", def.substr(second_line_start, second_line_length));
+ }
+}
+
+JavaType GetJavaType(FieldDescriptor::Type field_type) {
+ switch (field_type) {
+ case FieldDescriptor::TYPE_INT32:
+ case FieldDescriptor::TYPE_UINT32:
+ case FieldDescriptor::TYPE_SINT32:
+ case FieldDescriptor::TYPE_FIXED32:
+ case FieldDescriptor::TYPE_SFIXED32:
+ return JAVATYPE_INT;
+
+ case FieldDescriptor::TYPE_INT64:
+ case FieldDescriptor::TYPE_UINT64:
+ case FieldDescriptor::TYPE_SINT64:
+ case FieldDescriptor::TYPE_FIXED64:
+ case FieldDescriptor::TYPE_SFIXED64:
+ return JAVATYPE_LONG;
+
+ case FieldDescriptor::TYPE_FLOAT:
+ return JAVATYPE_FLOAT;
+
+ case FieldDescriptor::TYPE_DOUBLE:
+ return JAVATYPE_DOUBLE;
+
+ case FieldDescriptor::TYPE_BOOL:
+ return JAVATYPE_BOOLEAN;
+
+ case FieldDescriptor::TYPE_STRING:
+ return JAVATYPE_STRING;
+
+ case FieldDescriptor::TYPE_BYTES:
+ return JAVATYPE_BYTES;
+
+ case FieldDescriptor::TYPE_ENUM:
+ return JAVATYPE_ENUM;
+
+ case FieldDescriptor::TYPE_GROUP:
+ case FieldDescriptor::TYPE_MESSAGE:
+ return JAVATYPE_MESSAGE;
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return JAVATYPE_INT;
+}
+
+string 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 "byte[]";
+ case JAVATYPE_ENUM : return "int";
+ case JAVATYPE_MESSAGE: return "";
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return "";
+}
+
+string BoxedPrimitiveTypeName(JavaType type) {
+ switch (type) {
+ case JAVATYPE_INT : return "java.lang.Integer";
+ case JAVATYPE_LONG : return "java.lang.Long";
+ case JAVATYPE_FLOAT : return "java.lang.Float";
+ case JAVATYPE_DOUBLE : return "java.lang.Double";
+ case JAVATYPE_BOOLEAN: return "java.lang.Boolean";
+ case JAVATYPE_STRING : return "java.lang.String";
+ case JAVATYPE_BYTES : return "byte[]";
+ case JAVATYPE_ENUM : return "java.lang.Integer";
+ case JAVATYPE_MESSAGE: return "";
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return "";
+}
+
+string EmptyArrayName(const Params& params, const FieldDescriptor* field) {
+ switch (GetJavaType(field)) {
+ case JAVATYPE_INT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
+ case JAVATYPE_LONG : return "com.google.protobuf.nano.WireFormatNano.EMPTY_LONG_ARRAY";
+ case JAVATYPE_FLOAT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_FLOAT_ARRAY";
+ case JAVATYPE_DOUBLE : return "com.google.protobuf.nano.WireFormatNano.EMPTY_DOUBLE_ARRAY";
+ case JAVATYPE_BOOLEAN: return "com.google.protobuf.nano.WireFormatNano.EMPTY_BOOLEAN_ARRAY";
+ case JAVATYPE_STRING : return "com.google.protobuf.nano.WireFormatNano.EMPTY_STRING_ARRAY";
+ case JAVATYPE_BYTES : return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES_ARRAY";
+ case JAVATYPE_ENUM : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
+ case JAVATYPE_MESSAGE: return ClassName(params, field->message_type()) + ".EMPTY_ARRAY";
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return "";
+}
+
+string DefaultValue(const Params& params, const FieldDescriptor* field) {
+ if (field->label() == FieldDescriptor::LABEL_REPEATED) {
+ return EmptyArrayName(params, field);
+ }
+
+ if (params.use_reference_types_for_primitives()) {
+ if (params.reftypes_primitive_enums()
+ && field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+ return "Integer.MIN_VALUE";
+ }
+ return "null";
+ }
+
+ // Switch on cpp_type since we need to know which default_value_* method
+ // of FieldDescriptor to call.
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return SimpleItoa(field->default_value_int32());
+ case FieldDescriptor::CPPTYPE_UINT32:
+ // Need to print as a signed int since Java has no unsigned.
+ return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
+ case FieldDescriptor::CPPTYPE_INT64:
+ return SimpleItoa(field->default_value_int64()) + "L";
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
+ "L";
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ double value = field->default_value_double();
+ if (value == numeric_limits<double>::infinity()) {
+ return "Double.POSITIVE_INFINITY";
+ } else if (value == -numeric_limits<double>::infinity()) {
+ return "Double.NEGATIVE_INFINITY";
+ } else if (value != value) {
+ return "Double.NaN";
+ } else {
+ return SimpleDtoa(value) + "D";
+ }
+ }
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ float value = field->default_value_float();
+ if (value == numeric_limits<float>::infinity()) {
+ return "Float.POSITIVE_INFINITY";
+ } else if (value == -numeric_limits<float>::infinity()) {
+ return "Float.NEGATIVE_INFINITY";
+ } else if (value != value) {
+ return "Float.NaN";
+ } else {
+ return SimpleFtoa(value) + "F";
+ }
+ }
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return field->default_value_bool() ? "true" : "false";
+ case FieldDescriptor::CPPTYPE_STRING:
+ if (!field->default_value_string().empty()) {
+ // Point it to the static final in the generated code.
+ return FieldDefaultConstantName(field);
+ } else {
+ if (field->type() == FieldDescriptor::TYPE_BYTES) {
+ return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES";
+ } else {
+ return "\"\"";
+ }
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return ClassName(params, field->enum_type()) + "." +
+ RenameJavaKeywords(field->default_value_enum()->name());
+
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return "null";
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return "";
+}
+
+
+static const char* kBitMasks[] = {
+ "0x00000001",
+ "0x00000002",
+ "0x00000004",
+ "0x00000008",
+ "0x00000010",
+ "0x00000020",
+ "0x00000040",
+ "0x00000080",
+
+ "0x00000100",
+ "0x00000200",
+ "0x00000400",
+ "0x00000800",
+ "0x00001000",
+ "0x00002000",
+ "0x00004000",
+ "0x00008000",
+
+ "0x00010000",
+ "0x00020000",
+ "0x00040000",
+ "0x00080000",
+ "0x00100000",
+ "0x00200000",
+ "0x00400000",
+ "0x00800000",
+
+ "0x01000000",
+ "0x02000000",
+ "0x04000000",
+ "0x08000000",
+ "0x10000000",
+ "0x20000000",
+ "0x40000000",
+ "0x80000000",
+};
+
+string GetBitFieldName(int index) {
+ string var_name = "bitField";
+ var_name += SimpleItoa(index);
+ var_name += "_";
+ return var_name;
+}
+
+string GetBitFieldNameForBit(int bit_index) {
+ return GetBitFieldName(bit_index / 32);
+}
+
+string GenerateGetBit(int bit_index) {
+ string var_name = GetBitFieldNameForBit(bit_index);
+ int bit_in_var_index = bit_index % 32;
+
+ string mask = kBitMasks[bit_in_var_index];
+ string result = "((" + var_name + " & " + mask + ") != 0)";
+ return result;
+}
+
+string GenerateSetBit(int bit_index) {
+ string var_name = GetBitFieldNameForBit(bit_index);
+ int bit_in_var_index = bit_index % 32;
+
+ string mask = kBitMasks[bit_in_var_index];
+ string result = var_name + " |= " + mask;
+ return result;
+}
+
+string GenerateClearBit(int bit_index) {
+ string var_name = GetBitFieldNameForBit(bit_index);
+ int bit_in_var_index = bit_index % 32;
+
+ string mask = kBitMasks[bit_in_var_index];
+ string result = var_name + " = (" + var_name + " & ~" + mask + ")";
+ return result;
+}
+
+string GenerateDifferentBit(int bit_index) {
+ string var_name = GetBitFieldNameForBit(bit_index);
+ int bit_in_var_index = bit_index % 32;
+
+ string mask = kBitMasks[bit_in_var_index];
+ string result = "((" + var_name + " & " + mask
+ + ") != (other." + var_name + " & " + mask + "))";
+ return result;
+}
+
+void SetBitOperationVariables(const string name,
+ int bitIndex, map<string, string>* variables) {
+ (*variables)["get_" + name] = GenerateGetBit(bitIndex);
+ (*variables)["set_" + name] = GenerateSetBit(bitIndex);
+ (*variables)["clear_" + name] = GenerateClearBit(bitIndex);
+ (*variables)["different_" + name] = GenerateDifferentBit(bitIndex);
+}
+
+bool HasMapField(const Descriptor* descriptor) {
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ const FieldDescriptor* field = descriptor->field(i);
+ if (field->type() == FieldDescriptor::TYPE_MESSAGE &&
+ IsMapEntry(field->message_type())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.h b/src/google/protobuf/compiler/javanano/javanano_helpers.h
new file mode 100644
index 00000000..014c85ae
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.h
@@ -0,0 +1,199 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__
+
+#include <string>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+// Commonly-used separator comments. Thick is a line of '=', thin is a line
+// of '-'.
+extern const char kThickSeparator[];
+extern const char kThinSeparator[];
+
+// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
+// "fooBarBaz" or "FooBarBaz", respectively.
+string UnderscoresToCamelCase(const FieldDescriptor* field);
+string UnderscoresToCamelCase(const OneofDescriptor* oneof);
+string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field);
+string UnderscoresToCapitalizedCamelCase(const OneofDescriptor* oneof);
+
+// Appends an "_" to the end of a field where the name is a reserved java
+// keyword. For example int32 public = 1 will generate int public_.
+string RenameJavaKeywords(const string& input);
+
+// Similar, but for method names. (Typically, this merely has the effect
+// of lower-casing the first letter of the name.)
+string UnderscoresToCamelCase(const MethodDescriptor* method);
+
+// Strips ".proto" or ".protodevel" from the end of a filename.
+string StripProto(const string& filename);
+
+// Gets the unqualified class name for the file. Each .proto file becomes a
+// single Java class, with all its contents nested in that class.
+string FileClassName(const Params& params, const FileDescriptor* file);
+
+// Returns the file's Java package name.
+string FileJavaPackage(const Params& params, const FileDescriptor* file);
+
+// Returns whether the Java outer class is needed, i.e. whether the option
+// java_multiple_files is false, or the proto file contains any file-scope
+// enums/extensions.
+bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file);
+
+// Converts the given simple name of a proto entity to its fully-qualified name
+// in the Java namespace, given that it is in the given file enclosed in the
+// given parent message (or NULL for file-scope entities). Whether the file's
+// outer class name should be included in the return value depends on factors
+// inferrable from the given arguments, including is_class which indicates
+// whether the entity translates to a Java class.
+string ToJavaName(const Params& params, const string& name, bool is_class,
+ const Descriptor* parent, const FileDescriptor* file);
+
+// These return the fully-qualified class name corresponding to the given
+// descriptor.
+inline string ClassName(const Params& params, const Descriptor* descriptor) {
+ return ToJavaName(params, descriptor->name(), true,
+ descriptor->containing_type(), descriptor->file());
+}
+string ClassName(const Params& params, const EnumDescriptor* descriptor);
+inline string ClassName(const Params& params,
+ const ServiceDescriptor* descriptor) {
+ return ToJavaName(params, descriptor->name(), true, NULL, descriptor->file());
+}
+inline string ExtensionIdentifierName(const Params& params,
+ const FieldDescriptor* descriptor) {
+ return ToJavaName(params, descriptor->name(), false,
+ descriptor->extension_scope(), descriptor->file());
+}
+string ClassName(const Params& params, const FileDescriptor* descriptor);
+
+// Get the unqualified name that should be used for a field's field
+// number constant.
+string FieldConstantName(const FieldDescriptor *field);
+
+string FieldDefaultConstantName(const FieldDescriptor *field);
+
+// Print the field's proto-syntax definition as a comment.
+void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field);
+
+enum JavaType {
+ JAVATYPE_INT,
+ JAVATYPE_LONG,
+ JAVATYPE_FLOAT,
+ JAVATYPE_DOUBLE,
+ JAVATYPE_BOOLEAN,
+ JAVATYPE_STRING,
+ JAVATYPE_BYTES,
+ JAVATYPE_ENUM,
+ JAVATYPE_MESSAGE
+};
+
+JavaType GetJavaType(FieldDescriptor::Type field_type);
+
+inline JavaType GetJavaType(const FieldDescriptor* field) {
+ return GetJavaType(field->type());
+}
+
+string 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.
+string BoxedPrimitiveTypeName(JavaType type);
+
+string EmptyArrayName(const Params& params, const FieldDescriptor* field);
+
+string DefaultValue(const Params& params, const FieldDescriptor* field);
+
+
+// Methods for shared bitfields.
+
+// Gets the name of the shared bitfield for the given field index.
+string GetBitFieldName(int index);
+
+// Gets the name of the shared bitfield for the given bit index.
+// Effectively, GetBitFieldName(bit_index / 32)
+string GetBitFieldNameForBit(int bit_index);
+
+// Generates the java code for the expression that returns whether the bit at
+// the given bit index is set.
+// Example: "((bitField1_ & 0x04000000) != 0)"
+string GenerateGetBit(int bit_index);
+
+// Generates the java code for the expression that sets the bit at the given
+// bit index.
+// Example: "bitField1_ |= 0x04000000"
+string GenerateSetBit(int bit_index);
+
+// Generates the java code for the expression that clears the bit at the given
+// bit index.
+// Example: "bitField1_ = (bitField1_ & ~0x04000000)"
+string GenerateClearBit(int bit_index);
+
+// Generates the java code for the expression that returns whether the bit at
+// the given bit index contains different values in the current object and
+// another object accessible via the variable 'other'.
+// Example: "((bitField1_ & 0x04000000) != (other.bitField1_ & 0x04000000))"
+string GenerateDifferentBit(int bit_index);
+
+// Sets the 'get_*', 'set_*', 'clear_*' and 'different_*' variables, where * is
+// the given name of the bit, to the appropriate Java expressions for the given
+// bit index.
+void SetBitOperationVariables(const string name,
+ int bitIndex, map<string, string>* variables);
+
+inline bool IsMapEntry(const Descriptor* descriptor) {
+ // TODO(liujisi): Add an option to turn on maps for proto2 syntax as well.
+ return descriptor->options().map_entry() &&
+ descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+bool HasMapField(const Descriptor* descriptor);
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_map_field.cc b/src/google/protobuf/compiler/javanano/javanano_map_field.cc
new file mode 100644
index 00000000..83b2b0ce
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_map_field.cc
@@ -0,0 +1,186 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/javanano/javanano_map_field.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+namespace {
+
+string TypeName(const Params& params, const FieldDescriptor* field,
+ bool boxed) {
+ JavaType java_type = GetJavaType(field);
+ switch (java_type) {
+ case JAVATYPE_MESSAGE:
+ return ClassName(params, field->message_type());
+ case JAVATYPE_INT:
+ case JAVATYPE_LONG:
+ case JAVATYPE_FLOAT:
+ case JAVATYPE_DOUBLE:
+ case JAVATYPE_BOOLEAN:
+ case JAVATYPE_STRING:
+ case JAVATYPE_BYTES:
+ case JAVATYPE_ENUM:
+ if (boxed) {
+ return BoxedPrimitiveTypeName(java_type);
+ } else {
+ return PrimitiveTypeName(java_type);
+ }
+ // No default because we want the compiler to complain if any new JavaTypes
+ // are added..
+ }
+
+ GOOGLE_LOG(FATAL) << "should not reach here.";
+ return "";
+}
+
+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");
+}
+
+void SetMapVariables(const Params& params,
+ const FieldDescriptor* descriptor, map<string, string>* variables) {
+ const FieldDescriptor* key = KeyField(descriptor);
+ const FieldDescriptor* value = ValueField(descriptor);
+ (*variables)["name"] =
+ RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["key_type"] = TypeName(params, key, false);
+ (*variables)["boxed_key_type"] = TypeName(params,key, true);
+ (*variables)["key_desc_type"] =
+ "TYPE_" + ToUpper(FieldDescriptor::TypeName(key->type()));
+ (*variables)["key_tag"] = SimpleItoa(internal::WireFormat::MakeTag(key));
+ (*variables)["value_type"] = TypeName(params, value, false);
+ (*variables)["boxed_value_type"] = TypeName(params, value, true);
+ (*variables)["value_desc_type"] =
+ "TYPE_" + ToUpper(FieldDescriptor::TypeName(value->type()));
+ (*variables)["value_tag"] = SimpleItoa(internal::WireFormat::MakeTag(value));
+ (*variables)["type_parameters"] =
+ (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
+ (*variables)["value_default"] =
+ value->type() == FieldDescriptor::TYPE_MESSAGE
+ ? "new " + (*variables)["value_type"] + "()"
+ : "null";
+}
+} // namespace
+
+// ===================================================================
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetMapVariables(params, descriptor, &variables_);
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public java.util.Map<$type_parameters$> $name$;\n");
+}
+
+void MapFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = null;\n");
+}
+
+void MapFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "this.$name$ = com.google.protobuf.nano.InternalNano.mergeMapEntry(\n"
+ " input, this.$name$, mapFactory,\n"
+ " com.google.protobuf.nano.InternalNano.$key_desc_type$,\n"
+ " com.google.protobuf.nano.InternalNano.$value_desc_type$,\n"
+ " $value_default$,\n"
+ " $key_tag$, $value_tag$);\n"
+ "\n");
+}
+
+void MapFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " com.google.protobuf.nano.InternalNano.serializeMapField(\n"
+ " output, this.$name$, $number$,\n"
+ " com.google.protobuf.nano.InternalNano.$key_desc_type$,\n"
+ " com.google.protobuf.nano.InternalNano.$value_desc_type$);\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " size += com.google.protobuf.nano.InternalNano.computeMapFieldSize(\n"
+ " this.$name$, $number$,\n"
+ " com.google.protobuf.nano.InternalNano.$key_desc_type$,\n"
+ " com.google.protobuf.nano.InternalNano.$value_desc_type$);\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!com.google.protobuf.nano.InternalNano.equals(\n"
+ " this.$name$, other.$name$)) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result +\n"
+ " com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_map_field.h b/src/google/protobuf/compiler/javanano/javanano_map_field.h
new file mode 100644
index 00000000..c01bde38
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_map_field.h
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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_JAVANANO_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
+
+#include <map>
+#include <string>
+#include <vector>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class MapFieldGenerator : public FieldGenerator {
+ public:
+ explicit MapFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params);
+ ~MapFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc
new file mode 100644
index 00000000..707f6b84
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -0,0 +1,615 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/compiler/javanano/javanano_message.h>
+#include <google/protobuf/compiler/javanano/javanano_enum.h>
+#include <google/protobuf/compiler/javanano/javanano_extension.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+struct FieldOrderingByNumber {
+ inline bool operator()(const FieldDescriptor* a,
+ const FieldDescriptor* b) const {
+ return a->number() < b->number();
+ }
+};
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
+ const FieldDescriptor** fields =
+ new const FieldDescriptor*[descriptor->field_count()];
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ fields[i] = descriptor->field(i);
+ }
+ sort(fields, fields + descriptor->field_count(),
+ FieldOrderingByNumber());
+ return fields;
+}
+
+} // namespace
+
+// ===================================================================
+
+MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params)
+ : params_(params),
+ descriptor_(descriptor),
+ field_generators_(descriptor, params) {
+}
+
+MessageGenerator::~MessageGenerator() {}
+
+void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
+ // Generate static members for all nested types.
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // TODO(kenton): Reuse MessageGenerator objects?
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ MessageGenerator(descriptor_->nested_type(i), params_)
+ .GenerateStaticVariables(printer);
+ }
+}
+
+void MessageGenerator::GenerateStaticVariableInitializers(
+ io::Printer* printer) {
+ // Generate static member initializers for all nested types.
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // TODO(kenton): Reuse MessageGenerator objects?
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ MessageGenerator(descriptor_->nested_type(i), params_)
+ .GenerateStaticVariableInitializers(printer);
+ }
+}
+
+void MessageGenerator::Generate(io::Printer* printer) {
+ if (!params_.store_unknown_fields() &&
+ (descriptor_->extension_count() != 0 || descriptor_->extension_range_count() != 0)) {
+ GOOGLE_LOG(FATAL) << "Extensions are only supported in NANO_RUNTIME if the "
+ "'store_unknown_fields' generator option is 'true'\n";
+ }
+
+ const string& file_name = descriptor_->file()->name();
+ bool is_own_file =
+ params_.java_multiple_files(file_name)
+ && descriptor_->containing_type() == NULL;
+
+ if (is_own_file) {
+ // Note: constants (from enums and fields requiring stored defaults, emitted in the loop below)
+ // may have the same names as constants in the nested classes. This causes Java warnings, but
+ // is not fatal, so we suppress those warnings here in the top-most class declaration.
+ printer->Print(
+ "\n"
+ "@SuppressWarnings(\"hiding\")\n"
+ "public final class $classname$ extends\n",
+ "classname", descriptor_->name());
+ } else {
+ printer->Print(
+ "\n"
+ "public static final class $classname$ extends\n",
+ "classname", descriptor_->name());
+ }
+ if (params_.store_unknown_fields() && params_.parcelable_messages()) {
+ printer->Print(
+ " com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$> {\n",
+ "classname", descriptor_->name());
+ } else if (params_.store_unknown_fields()) {
+ printer->Print(
+ " com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n",
+ "classname", descriptor_->name());
+ } else if (params_.parcelable_messages()) {
+ printer->Print(
+ " com.google.protobuf.nano.android.ParcelableMessageNano {\n");
+ } else {
+ printer->Print(
+ " com.google.protobuf.nano.MessageNano {\n");
+ }
+ printer->Indent();
+
+ // Nested types and extensions
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
+ }
+
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
+ }
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
+ }
+
+ // oneof
+ map<string, string> vars;
+ vars["message_name"] = descriptor_->name();
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof_desc = descriptor_->oneof_decl(i);
+ vars["oneof_name"] = UnderscoresToCamelCase(oneof_desc);
+ vars["oneof_capitalized_name"] =
+ UnderscoresToCapitalizedCamelCase(oneof_desc);
+ vars["oneof_index"] = SimpleItoa(oneof_desc->index());
+ // Oneof Constants
+ for (int j = 0; j < oneof_desc->field_count(); j++) {
+ const FieldDescriptor* field = oneof_desc->field(j);
+ vars["number"] = SimpleItoa(field->number());
+ vars["cap_field_name"] = ToUpper(field->name());
+ printer->Print(vars,
+ "public static final int $cap_field_name$_FIELD_NUMBER = $number$;\n");
+ }
+ // oneofCase_ and oneof_
+ printer->Print(vars,
+ "private int $oneof_name$Case_ = 0;\n"
+ "private java.lang.Object $oneof_name$_;\n");
+ printer->Print(vars,
+ "public int get$oneof_capitalized_name$Case() {\n"
+ " return this.$oneof_name$Case_;\n"
+ "}\n");
+ // Oneof clear
+ printer->Print(vars,
+ "public $message_name$ clear$oneof_capitalized_name$() {\n"
+ " this.$oneof_name$Case_ = 0;\n"
+ " this.$oneof_name$_ = null;\n"
+ " return this;\n"
+ "}\n");
+ }
+
+ // Lazy initialization of otherwise static final fields can help prevent the
+ // class initializer from being generated. We want to prevent it because it
+ // stops ProGuard from inlining any methods in this class into call sites and
+ // therefore reducing the method count. However, extensions are best kept as
+ // public static final fields with initializers, so with their existence we
+ // won't bother with lazy initialization.
+ bool lazy_init = descriptor_->extension_count() == 0;
+
+ // Empty array
+ if (lazy_init) {
+ printer->Print(
+ "\n"
+ "private static volatile $classname$[] _emptyArray;\n"
+ "public static $classname$[] emptyArray() {\n"
+ " // Lazily initializes the empty array\n"
+ " if (_emptyArray == null) {\n"
+ " synchronized (\n"
+ " com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n"
+ " if (_emptyArray == null) {\n"
+ " _emptyArray = new $classname$[0];\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " return _emptyArray;\n"
+ "}\n",
+ "classname", descriptor_->name());
+ } else {
+ printer->Print(
+ "\n"
+ "private static final $classname$[] EMPTY_ARRAY = {};\n"
+ "public static $classname$[] emptyArray() {\n"
+ " return EMPTY_ARRAY;\n"
+ "}\n",
+ "classname", descriptor_->name());
+ }
+
+ // Integers for bit fields
+ int totalInts = (field_generators_.total_bits() + 31) / 32;
+ if (totalInts > 0) {
+ printer->Print("\n");
+ for (int i = 0; i < totalInts; i++) {
+ printer->Print("private int $bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ }
+
+ // Fields and maybe their default values
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ PrintFieldComment(printer, descriptor_->field(i));
+ field_generators_.get(descriptor_->field(i)).GenerateMembers(
+ printer, lazy_init);
+ }
+
+ // Constructor, with lazy init code if needed
+ if (lazy_init && field_generators_.saved_defaults_needed()) {
+ printer->Print(
+ "\n"
+ "private static volatile boolean _classInitialized;\n"
+ "\n"
+ "public $classname$() {\n"
+ " // Lazily initializes the field defaults\n"
+ " if (!_classInitialized) {\n"
+ " synchronized (\n"
+ " com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n"
+ " if (!_classInitialized) {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateInitSavedDefaultCode(printer);
+ }
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " _classInitialized = true;\n"
+ " }\n"
+ " }\n"
+ " }\n");
+ if (params_.generate_clear()) {
+ printer->Print(" clear();\n");
+ }
+ printer->Print("}\n");
+ } else {
+ if (params_.generate_clear()) {
+ printer->Print(
+ "\n"
+ "public $classname$() {\n"
+ " clear();\n"
+ "}\n",
+ "classname", descriptor_->name());
+ }
+ }
+
+ // Other methods in this class
+
+ GenerateClear(printer);
+
+ if (params_.generate_equals()) {
+ GenerateEquals(printer);
+ GenerateHashCode(printer);
+ }
+
+ GenerateMessageSerializationMethods(printer);
+ GenerateMergeFromMethods(printer);
+ GenerateParseFromMethods(printer);
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+// ===================================================================
+
+void MessageGenerator::
+GenerateMessageSerializationMethods(io::Printer* printer) {
+ // Rely on the parent implementations of writeTo() and getSerializedSize()
+ // if there are no fields to serialize in this message.
+ if (descriptor_->field_count() == 0) {
+ return;
+ }
+
+ scoped_array<const FieldDescriptor*> sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n"
+ " throws java.io.IOException {\n");
+ printer->Indent();
+
+ // Output the fields in sorted order
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ GenerateSerializeOneField(printer, sorted_fields[i]);
+ }
+
+ // The parent implementation will write any unknown fields if necessary.
+ printer->Print(
+ "super.writeTo(output);\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+
+ // The parent implementation will get the serialized size for unknown
+ // fields if necessary.
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "protected int computeSerializedSize() {\n"
+ " int size = super.computeSerializedSize();\n");
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
+ }
+
+ printer->Outdent();
+ printer->Print(
+ " return size;\n"
+ "}\n");
+}
+
+void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
+ scoped_array<const FieldDescriptor*> sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "public $classname$ mergeFrom(\n"
+ " com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
+ " throws java.io.IOException {\n",
+ "classname", descriptor_->name());
+
+ printer->Indent();
+ if (HasMapField(descriptor_)) {
+ printer->Print(
+ "com.google.protobuf.nano.MapFactories.MapFactory mapFactory =\n"
+ " com.google.protobuf.nano.MapFactories.getMapFactory();\n");
+ }
+
+ printer->Print(
+ "while (true) {\n");
+ printer->Indent();
+
+ printer->Print(
+ "int tag = input.readTag();\n"
+ "switch (tag) {\n");
+ printer->Indent();
+
+ printer->Print(
+ "case 0:\n" // zero signals EOF / limit reached
+ " return this;\n"
+ "default: {\n");
+
+ printer->Indent();
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "if (!storeUnknownField(input, tag)) {\n"
+ " return this;\n"
+ "}\n");
+ } else {
+ printer->Print(
+ "if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {\n"
+ " return this;\n" // it's an endgroup tag
+ "}\n");
+ }
+ printer->Print("break;\n");
+ printer->Outdent();
+ printer->Print("}\n");
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = sorted_fields[i];
+ uint32 tag = WireFormatLite::MakeTag(field->number(),
+ WireFormat::WireTypeForFieldType(field->type()));
+
+ printer->Print(
+ "case $tag$: {\n",
+ "tag", SimpleItoa(tag));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateMergingCode(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " break;\n"
+ "}\n");
+
+ if (field->is_packable()) {
+ // To make packed = true wire compatible, we generate parsing code from a
+ // packed version of this field regardless of field->options().packed().
+ uint32 packed_tag = WireFormatLite::MakeTag(field->number(),
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+ printer->Print(
+ "case $tag$: {\n",
+ "tag", SimpleItoa(packed_tag));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateMergingCodeFromPacked(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " break;\n"
+ "}\n");
+ }
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n" // switch (tag)
+ " }\n" // while (true)
+ "}\n");
+}
+
+void MessageGenerator::
+GenerateParseFromMethods(io::Printer* printer) {
+ // Note: These are separate from GenerateMessageSerializationMethods()
+ // because they need to be generated even for messages that are optimized
+ // for code size.
+ printer->Print(
+ "\n"
+ "public static $classname$ parseFrom(byte[] data)\n"
+ " throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {\n"
+ " return com.google.protobuf.nano.MessageNano.mergeFrom(new $classname$(), data);\n"
+ "}\n"
+ "\n"
+ "public static $classname$ parseFrom(\n"
+ " com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
+ " throws java.io.IOException {\n"
+ " return new $classname$().mergeFrom(input);\n"
+ "}\n",
+ "classname", descriptor_->name());
+}
+
+void MessageGenerator::GenerateSerializeOneField(
+ io::Printer* printer, const FieldDescriptor* field) {
+ field_generators_.get(field).GenerateSerializationCode(printer);
+}
+
+void MessageGenerator::GenerateClear(io::Printer* printer) {
+ if (!params_.generate_clear()) {
+ return;
+ }
+ printer->Print(
+ "\n"
+ "public $classname$ clear() {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+
+ // Clear bit fields.
+ int totalInts = (field_generators_.total_bits() + 31) / 32;
+ for (int i = 0; i < totalInts; i++) {
+ printer->Print("$bit_field_name$ = 0;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+
+ // Call clear for all of the fields.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ field_generators_.get(field).GenerateClearCode(printer);
+ }
+
+ // Clear oneofs.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print(
+ "clear$oneof_capitalized_name$();\n",
+ "oneof_capitalized_name", UnderscoresToCapitalizedCamelCase(
+ descriptor_->oneof_decl(i)));
+ }
+
+ // Clear unknown fields.
+ if (params_.store_unknown_fields()) {
+ printer->Print("unknownFieldData = null;\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ " cachedSize = -1;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void MessageGenerator::GenerateEquals(io::Printer* printer) {
+ // Don't override if there are no fields. We could generate an
+ // equals method that compares types, but often empty messages
+ // are used as namespaces.
+ if (descriptor_->field_count() == 0 && !params_.store_unknown_fields()) {
+ return;
+ }
+
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "public boolean equals(Object o) {\n");
+ printer->Indent();
+ printer->Print(
+ "if (o == this) {\n"
+ " return true;\n"
+ "}\n"
+ "if (!(o instanceof $classname$)) {\n"
+ " return false;\n"
+ "}\n"
+ "$classname$ other = ($classname$) o;\n",
+ "classname", descriptor_->name());
+
+ // Checking oneof case before checking each oneof field.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof_desc = descriptor_->oneof_decl(i);
+ printer->Print(
+ "if (this.$oneof_name$Case_ != other.$oneof_name$Case_) {\n"
+ " return false;\n"
+ "}\n",
+ "oneof_name", UnderscoresToCamelCase(oneof_desc));
+ }
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ field_generators_.get(field).GenerateEqualsCode(printer);
+ }
+
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "return unknownFieldDataEquals(other);\n");
+ } else {
+ printer->Print(
+ "return true;\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void MessageGenerator::GenerateHashCode(io::Printer* printer) {
+ if (descriptor_->field_count() == 0 && !params_.store_unknown_fields()) {
+ return;
+ }
+
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "public int hashCode() {\n");
+ printer->Indent();
+
+ printer->Print("int result = 17;\n");
+ printer->Print("result = 31 * result + getClass().getName().hashCode();\n");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ field_generators_.get(field).GenerateHashCodeCode(printer);
+ }
+
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "result = 31 * result + unknownFieldDataHashCode();\n");
+ }
+
+ printer->Print("return result;\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+// ===================================================================
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h
new file mode 100644
index 00000000..6f25a3a0
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_message.h
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__
+
+#include <string>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class MessageGenerator {
+ public:
+ explicit MessageGenerator(const Descriptor* descriptor, const Params& params);
+ ~MessageGenerator();
+
+ // All static variables have to be declared at the top-level of the file
+ // so that we can control initialization order, which is important for
+ // DescriptorProto bootstrapping to work.
+ void GenerateStaticVariables(io::Printer* printer);
+
+ // Output code which initializes the static variables generated by
+ // GenerateStaticVariables().
+ void GenerateStaticVariableInitializers(io::Printer* printer);
+
+ // Generate the class itself.
+ void Generate(io::Printer* printer);
+
+ private:
+ void GenerateMessageSerializationMethods(io::Printer* printer);
+ void GenerateMergeFromMethods(io::Printer* printer);
+ void GenerateParseFromMethods(io::Printer* printer);
+ void GenerateSerializeOneField(io::Printer* printer,
+ const FieldDescriptor* field);
+
+ void GenerateClear(io::Printer* printer);
+ void GenerateEquals(io::Printer* printer);
+ void GenerateHashCode(io::Printer* printer);
+
+ const Params& params_;
+ const Descriptor* descriptor_;
+ FieldGeneratorMap field_generators_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
new file mode 100644
index 00000000..181c4060
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
@@ -0,0 +1,334 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javanano/javanano_message_field.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
+// repeat code between this and the other field types.
+void SetMessageVariables(const Params& params,
+ const FieldDescriptor* descriptor, map<string, string>* variables) {
+ (*variables)["name"] =
+ RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ (*variables)["capitalized_name"] =
+ RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["type"] = ClassName(params, descriptor->message_type());
+ (*variables)["group_or_message"] =
+ (descriptor->type() == FieldDescriptor::TYPE_GROUP) ?
+ "Group" : "Message";
+ (*variables)["message_name"] = descriptor->containing_type()->name();
+ //(*variables)["message_type"] = descriptor->message_type()->name();
+ (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+}
+
+} // namespace
+
+// ===================================================================
+
+MessageFieldGenerator::
+MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetMessageVariables(params, descriptor, &variables_);
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {}
+
+void MessageFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public $type$ $name$;\n");
+}
+
+void MessageFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = null;\n");
+}
+
+void MessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ == null) {\n"
+ " this.$name$ = new $type$();\n"
+ "}\n");
+
+ if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "input.readGroup(this.$name$, $number$);\n");
+ } else {
+ printer->Print(variables_,
+ "input.readMessage(this.$name$);\n");
+ }
+}
+
+void MessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " output.write$group_or_message$($number$, this.$name$);\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$group_or_message$Size($number$, this.$name$);\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ == null) { \n"
+ " if (other.$name$ != null) {\n"
+ " return false;\n"
+ " }\n"
+ "} else {\n"
+ " if (!this.$name$.equals(other.$name$)) {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result +\n"
+ " (this.$name$ == null ? 0 : this.$name$.hashCode());\n");
+}
+// ===================================================================
+
+MessageOneofFieldGenerator::MessageOneofFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetMessageVariables(params, descriptor, &variables_);
+ SetCommonOneofVariables(descriptor, &variables_);
+}
+
+MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
+
+void MessageOneofFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case$;\n"
+ "}\n"
+ "public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case$) {\n"
+ " return ($type$) this.$oneof_name$_;\n"
+ " }\n"
+ " return null;\n"
+ "}\n"
+ "public $message_name$ set$capitalized_name$($type$ value) {\n"
+ " if (value == null) { throw new java.lang.NullPointerException(); }\n"
+ " $set_oneof_case$;\n"
+ " this.$oneof_name$_ = value;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ // No clear method for oneof fields.
+}
+
+void MessageOneofFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!($has_oneof_case$)) {\n"
+ " this.$oneof_name$_ = new $type$();\n"
+ "}\n"
+ "input.readMessage(\n"
+ " (com.google.protobuf.nano.MessageNano) this.$oneof_name$_);\n"
+ "$set_oneof_case$;\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case$) {\n"
+ " output.writeMessage($number$,\n"
+ " (com.google.protobuf.nano.MessageNano) this.$oneof_name$_);\n"
+ "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case$) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeMessageSize($number$,\n"
+ " (com.google.protobuf.nano.MessageNano) this.$oneof_name$_);\n"
+ "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ GenerateOneofFieldEquals(descriptor_, variables_, printer);
+}
+
+void MessageOneofFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ GenerateOneofFieldHashCode(descriptor_, variables_, printer);
+}
+
+// ===================================================================
+
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetMessageVariables(params, descriptor, &variables_);
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+void RepeatedMessageFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public $type$[] $name$;\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $type$.emptyArray();\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // First, figure out the length of the array, then parse.
+ printer->Print(variables_,
+ "int arrayLength = com.google.protobuf.nano.WireFormatNano\n"
+ " .getRepeatedFieldArrayLength(input, $tag$);\n"
+ "int i = this.$name$ == null ? 0 : this.$name$.length;\n"
+ "$type$[] newArray =\n"
+ " new $type$[i + arrayLength];\n"
+ "if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ "}\n"
+ "for (; i < newArray.length - 1; i++) {\n"
+ " newArray[i] = new $type$();\n");
+
+ if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ " input.readGroup(newArray[i], $number$);\n");
+ } else {
+ printer->Print(variables_,
+ " input.readMessage(newArray[i]);\n");
+ }
+
+ printer->Print(variables_,
+ " input.readTag();\n"
+ "}\n"
+ "// Last one without readTag.\n"
+ "newArray[i] = new $type$();\n");
+
+ if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "input.readGroup(newArray[i], $number$);\n");
+ } else {
+ printer->Print(variables_,
+ "input.readMessage(newArray[i]);\n");
+ }
+
+ printer->Print(variables_,
+ "this.$name$ = newArray;\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " if (element != null) {\n"
+ " output.write$group_or_message$($number$, element);\n"
+ " }\n"
+ " }\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " if (element != null) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$group_or_message$Size($number$, element);\n"
+ " }\n"
+ " }\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!com.google.protobuf.nano.InternalNano.equals(\n"
+ " this.$name$, other.$name$)) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h
new file mode 100644
index 00000000..6c615f5e
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class MessageFieldGenerator : public FieldGenerator {
+ public:
+ explicit MessageFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params);
+ ~MessageFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class MessageOneofFieldGenerator : public FieldGenerator {
+ public:
+ explicit MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params);
+ ~MessageOneofFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
+};
+
+class RepeatedMessageFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params);
+ ~RepeatedMessageFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h
new file mode 100644
index 00000000..4691f360
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_params.h
@@ -0,0 +1,240 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2010 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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: wink@google.com (Wink Saville)
+
+#ifndef PROTOBUF_COMPILER_JAVANANO_JAVANANO_PARAMS_H_
+#define PROTOBUF_COMPILER_JAVANANO_JAVANANO_PARAMS_H_
+
+#include <map>
+#include <set>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+enum eMultipleFiles { JAVANANO_MUL_UNSET, JAVANANO_MUL_FALSE, JAVANANO_MUL_TRUE };
+
+// Parameters for used by the generators
+class Params {
+ public:
+ typedef map<string, string> NameMap;
+ typedef set<string> NameSet;
+ private:
+ string empty_;
+ string base_name_;
+ eMultipleFiles override_java_multiple_files_;
+ bool store_unknown_fields_;
+ NameMap java_packages_;
+ NameMap java_outer_classnames_;
+ NameSet java_multiple_files_;
+ bool generate_has_;
+ bool java_enum_style_;
+ bool optional_field_accessors_;
+ bool use_reference_types_for_primitives_;
+ bool generate_equals_;
+ bool ignore_services_;
+ bool parcelable_messages_;
+ bool reftypes_primitive_enums_;
+ bool generate_clear_;
+
+ public:
+ Params(const string & base_name) :
+ empty_(""),
+ base_name_(base_name),
+ override_java_multiple_files_(JAVANANO_MUL_UNSET),
+ store_unknown_fields_(false),
+ generate_has_(false),
+ java_enum_style_(false),
+ optional_field_accessors_(false),
+ use_reference_types_for_primitives_(false),
+ generate_equals_(false),
+ ignore_services_(false),
+ parcelable_messages_(false),
+ reftypes_primitive_enums_(false),
+ generate_clear_(true) {
+ }
+
+ const string& base_name() const {
+ return base_name_;
+ }
+
+ bool has_java_package(const string& file_name) const {
+ return java_packages_.find(file_name)
+ != java_packages_.end();
+ }
+ void set_java_package(const string& file_name,
+ const string& java_package) {
+ java_packages_[file_name] = java_package;
+ }
+ const string& java_package(const string& file_name) const {
+ NameMap::const_iterator itr;
+
+ itr = java_packages_.find(file_name);
+ if (itr == java_packages_.end()) {
+ return empty_;
+ } else {
+ return itr->second;
+ }
+ }
+ const NameMap& java_packages() {
+ return java_packages_;
+ }
+
+ bool has_java_outer_classname(const string& file_name) const {
+ return java_outer_classnames_.find(file_name)
+ != java_outer_classnames_.end();
+ }
+ void set_java_outer_classname(const string& file_name,
+ const string& java_outer_classname) {
+ java_outer_classnames_[file_name] = java_outer_classname;
+ }
+ const string& java_outer_classname(const string& file_name) const {
+ NameMap::const_iterator itr;
+
+ itr = java_outer_classnames_.find(file_name);
+ if (itr == java_outer_classnames_.end()) {
+ return empty_;
+ } else {
+ return itr->second;
+ }
+ }
+ const NameMap& java_outer_classnames() {
+ return java_outer_classnames_;
+ }
+
+ void set_override_java_multiple_files(bool java_multiple_files) {
+ if (java_multiple_files) {
+ override_java_multiple_files_ = JAVANANO_MUL_TRUE;
+ } else {
+ override_java_multiple_files_ = JAVANANO_MUL_FALSE;
+ }
+ }
+ void clear_override_java_multiple_files() {
+ override_java_multiple_files_ = JAVANANO_MUL_UNSET;
+ }
+
+ void set_java_multiple_files(const string& file_name, bool value) {
+ if (value) {
+ java_multiple_files_.insert(file_name);
+ } else {
+ java_multiple_files_.erase(file_name);
+ }
+ }
+ bool java_multiple_files(const string& file_name) const {
+ switch (override_java_multiple_files_) {
+ case JAVANANO_MUL_FALSE:
+ return false;
+ case JAVANANO_MUL_TRUE:
+ return true;
+ default:
+ return java_multiple_files_.find(file_name)
+ != java_multiple_files_.end();
+ }
+ }
+
+ void set_store_unknown_fields(bool value) {
+ store_unknown_fields_ = value;
+ }
+ bool store_unknown_fields() const {
+ return store_unknown_fields_;
+ }
+
+ void set_generate_has(bool value) {
+ generate_has_ = value;
+ }
+ bool generate_has() const {
+ return generate_has_;
+ }
+
+ void set_java_enum_style(bool value) {
+ java_enum_style_ = value;
+ }
+ bool java_enum_style() const {
+ return java_enum_style_;
+ }
+
+ void set_optional_field_accessors(bool value) {
+ optional_field_accessors_ = value;
+ }
+ bool optional_field_accessors() const {
+ return optional_field_accessors_;
+ }
+
+ void set_use_reference_types_for_primitives(bool value) {
+ use_reference_types_for_primitives_ = value;
+ }
+ bool use_reference_types_for_primitives() const {
+ return use_reference_types_for_primitives_;
+ }
+
+ void set_generate_equals(bool value) {
+ generate_equals_ = value;
+ }
+ bool generate_equals() const {
+ return generate_equals_;
+ }
+
+ void set_ignore_services(bool value) {
+ ignore_services_ = value;
+ }
+ bool ignore_services() const {
+ return ignore_services_;
+ }
+
+ void set_parcelable_messages(bool value) {
+ parcelable_messages_ = value;
+ }
+ bool parcelable_messages() const {
+ return parcelable_messages_;
+ }
+
+ void set_reftypes_primitive_enums(bool value) {
+ reftypes_primitive_enums_ = value;
+ }
+ bool reftypes_primitive_enums() const {
+ return reftypes_primitive_enums_;
+ }
+
+ void set_generate_clear(bool value) {
+ generate_clear_ = value;
+ }
+ bool generate_clear() const {
+ return generate_clear_;
+ }
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // PROTOBUF_COMPILER_JAVANANO_JAVANANO_PARAMS_H_
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
new file mode 100644
index 00000000..41bad0a6
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
@@ -0,0 +1,960 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <math.h>
+#include <string>
+
+#include <google/protobuf/compiler/javanano/javanano_primitive_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+bool IsReferenceType(JavaType type) {
+ switch (type) {
+ case JAVATYPE_INT : return false;
+ case JAVATYPE_LONG : return false;
+ case JAVATYPE_FLOAT : return false;
+ case JAVATYPE_DOUBLE : return false;
+ case JAVATYPE_BOOLEAN: return false;
+ case JAVATYPE_STRING : return true;
+ case JAVATYPE_BYTES : return true;
+ case JAVATYPE_ENUM : return false;
+ case JAVATYPE_MESSAGE: return true;
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return false;
+}
+
+bool IsArrayType(JavaType type) {
+ switch (type) {
+ case JAVATYPE_INT : return false;
+ case JAVATYPE_LONG : return false;
+ case JAVATYPE_FLOAT : return false;
+ case JAVATYPE_DOUBLE : return false;
+ case JAVATYPE_BOOLEAN: return false;
+ case JAVATYPE_STRING : return false;
+ case JAVATYPE_BYTES : return true;
+ case JAVATYPE_ENUM : return false;
+ case JAVATYPE_MESSAGE: return false;
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return false;
+}
+
+const char* GetCapitalizedType(const FieldDescriptor* field) {
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_INT32 : return "Int32" ;
+ case FieldDescriptor::TYPE_UINT32 : return "UInt32" ;
+ case FieldDescriptor::TYPE_SINT32 : return "SInt32" ;
+ case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ;
+ case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
+ case FieldDescriptor::TYPE_INT64 : return "Int64" ;
+ case FieldDescriptor::TYPE_UINT64 : return "UInt64" ;
+ case FieldDescriptor::TYPE_SINT64 : return "SInt64" ;
+ case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ;
+ case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
+ case FieldDescriptor::TYPE_FLOAT : return "Float" ;
+ case FieldDescriptor::TYPE_DOUBLE : return "Double" ;
+ case FieldDescriptor::TYPE_BOOL : return "Bool" ;
+ case FieldDescriptor::TYPE_STRING : return "String" ;
+ case FieldDescriptor::TYPE_BYTES : return "Bytes" ;
+ case FieldDescriptor::TYPE_ENUM : return "Enum" ;
+ case FieldDescriptor::TYPE_GROUP : return "Group" ;
+ case FieldDescriptor::TYPE_MESSAGE : return "Message" ;
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+// For encodings with fixed sizes, returns that size in bytes. Otherwise
+// returns -1.
+int FixedSize(FieldDescriptor::Type type) {
+ switch (type) {
+ case FieldDescriptor::TYPE_INT32 : return -1;
+ case FieldDescriptor::TYPE_INT64 : return -1;
+ case FieldDescriptor::TYPE_UINT32 : return -1;
+ case FieldDescriptor::TYPE_UINT64 : return -1;
+ case FieldDescriptor::TYPE_SINT32 : return -1;
+ case FieldDescriptor::TYPE_SINT64 : return -1;
+ case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
+ case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
+ case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
+ case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
+ case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize;
+ case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize;
+
+ case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
+ case FieldDescriptor::TYPE_ENUM : return -1;
+
+ case FieldDescriptor::TYPE_STRING : return -1;
+ case FieldDescriptor::TYPE_BYTES : return -1;
+ case FieldDescriptor::TYPE_GROUP : return -1;
+ case FieldDescriptor::TYPE_MESSAGE : return -1;
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return -1;
+}
+
+bool AllAscii(const string& text) {
+ for (int i = 0; i < text.size(); i++) {
+ if ((text[i] & 0x80) != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params,
+ map<string, string>* variables) {
+ (*variables)["name"] =
+ RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ (*variables)["capitalized_name"] =
+ RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ if (params.use_reference_types_for_primitives()
+ && !descriptor->is_repeated()) {
+ (*variables)["type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+ } else {
+ (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
+ }
+ // Deals with defaults. For C++-string types (string and bytes),
+ // we might need to have the generated code do the unicode decoding
+ // (see comments in InternalNano.java for gory details.). We would
+ // like to do this once into a static field and re-use that from
+ // then on.
+ if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+ !descriptor->default_value_string().empty() &&
+ !params.use_reference_types_for_primitives()) {
+ if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+ (*variables)["default"] = DefaultValue(params, descriptor);
+ (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
+ (*variables)["default_constant_value"] = strings::Substitute(
+ "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")",
+ CEscape(descriptor->default_value_string()));
+ (*variables)["default_copy_if_needed"] =
+ (*variables)["default"] + ".clone()";
+ } else if (AllAscii(descriptor->default_value_string())) {
+ // All chars are ASCII. In this case directly referencing a
+ // CEscape()'d string literal works fine.
+ (*variables)["default"] =
+ "\"" + CEscape(descriptor->default_value_string()) + "\"";
+ (*variables)["default_copy_if_needed"] = (*variables)["default"];
+ } else {
+ // Strings where some chars are non-ASCII. We need to save the
+ // default value.
+ (*variables)["default"] = DefaultValue(params, descriptor);
+ (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
+ (*variables)["default_constant_value"] = strings::Substitute(
+ "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")",
+ CEscape(descriptor->default_value_string()));
+ (*variables)["default_copy_if_needed"] = (*variables)["default"];
+ }
+ } else {
+ // Non-string, non-bytes field. Defaults are literals.
+ (*variables)["default"] = DefaultValue(params, descriptor);
+ (*variables)["default_copy_if_needed"] = (*variables)["default"];
+ }
+ (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+ (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
+ (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+ (*variables)["tag_size"] = SimpleItoa(
+ WireFormat::TagSize(descriptor->number(), descriptor->type()));
+ (*variables)["non_packed_tag"] = SimpleItoa(
+ internal::WireFormatLite::MakeTag(descriptor->number(),
+ internal::WireFormat::WireTypeForFieldType(descriptor->type())));
+ int fixed_size = FixedSize(descriptor->type());
+ if (fixed_size != -1) {
+ (*variables)["fixed_size"] = SimpleItoa(fixed_size);
+ }
+ (*variables)["message_name"] = descriptor->containing_type()->name();
+ (*variables)["empty_array_name"] = EmptyArrayName(params, descriptor);
+}
+} // namespace
+
+// ===================================================================
+
+PrimitiveFieldGenerator::
+PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, params, &variables_);
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
+
+bool PrimitiveFieldGenerator::SavedDefaultNeeded() const {
+ return variables_.find("default_constant") != variables_.end();
+}
+
+void PrimitiveFieldGenerator::GenerateInitSavedDefaultCode(io::Printer* printer) const {
+ if (variables_.find("default_constant") != variables_.end()) {
+ printer->Print(variables_,
+ "$default_constant$ = $default_constant_value$;\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer, bool lazy_init) const {
+ if (variables_.find("default_constant") != variables_.end()) {
+ // Those primitive types that need a saved default.
+ if (lazy_init) {
+ printer->Print(variables_,
+ "private static $type$ $default_constant$;\n");
+ } else {
+ printer->Print(variables_,
+ "private static final $type$ $default_constant$ =\n"
+ " $default_constant_value$;\n");
+ }
+ }
+
+ printer->Print(variables_,
+ "public $type$ $name$;\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$;\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $default_copy_if_needed$;\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "has$capitalized_name$ = false;\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "this.$name$ = input.read$capitalized_type$();\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "has$capitalized_name$ = true;\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializationConditional(io::Printer* printer) const {
+ if (params_.use_reference_types_for_primitives()) {
+ // For reference type mode, serialize based on equality
+ // to null.
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n");
+ return;
+ }
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "if (has$capitalized_name$ || ");
+ } else {
+ printer->Print(variables_,
+ "if (");
+ }
+ JavaType java_type = GetJavaType(descriptor_);
+ if (IsArrayType(java_type)) {
+ printer->Print(variables_,
+ "!java.util.Arrays.equals(this.$name$, $default$)) {\n");
+ } else if (IsReferenceType(java_type)) {
+ printer->Print(variables_,
+ "!this.$name$.equals($default$)) {\n");
+ } else if (java_type == JAVATYPE_FLOAT) {
+ printer->Print(variables_,
+ "java.lang.Float.floatToIntBits(this.$name$)\n"
+ " != java.lang.Float.floatToIntBits($default$)) {\n");
+ } else if (java_type == JAVATYPE_DOUBLE) {
+ printer->Print(variables_,
+ "java.lang.Double.doubleToLongBits(this.$name$)\n"
+ " != java.lang.Double.doubleToLongBits($default$)) {\n");
+ } else {
+ printer->Print(variables_,
+ "this.$name$ != $default$) {\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ if (descriptor_->is_required() && !params_.generate_has()) {
+ // Always serialize a required field if we don't have the 'has' signal.
+ printer->Print(variables_,
+ "output.write$capitalized_type$($number$, this.$name$);\n");
+ } else {
+ GenerateSerializationConditional(printer);
+ printer->Print(variables_,
+ " output.write$capitalized_type$($number$, this.$name$);\n"
+ "}\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ if (descriptor_->is_required() && !params_.generate_has()) {
+ printer->Print(variables_,
+ "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$Size($number$, this.$name$);\n");
+ } else {
+ GenerateSerializationConditional(printer);
+ printer->Print(variables_,
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$Size($number$, this.$name$);\n"
+ "}\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ // We define equality as serialized form equality. If generate_has(),
+ // then if the field value equals the default value in both messages,
+ // but one's 'has' field is set and the other's is not, the serialized
+ // forms are different and we should return false.
+ JavaType java_type = GetJavaType(descriptor_);
+ if (java_type == JAVATYPE_BYTES) {
+ printer->Print(variables_,
+ "if (!java.util.Arrays.equals(this.$name$, other.$name$)");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (java.util.Arrays.equals(this.$name$, $default$)\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ "}\n");
+ } else if (java_type == JAVATYPE_STRING
+ || params_.use_reference_types_for_primitives()) {
+ printer->Print(variables_,
+ "if (this.$name$ == null) {\n"
+ " if (other.$name$ != null) {\n"
+ " return false;\n"
+ " }\n"
+ "} else if (!this.$name$.equals(other.$name$)");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (this.$name$.equals($default$)\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ "}\n");
+ } else if (java_type == JAVATYPE_FLOAT) {
+ printer->Print(variables_,
+ "{\n"
+ " int bits = java.lang.Float.floatToIntBits(this.$name$);\n"
+ " if (bits != java.lang.Float.floatToIntBits(other.$name$)");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (bits == java.lang.Float.floatToIntBits($default$)\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+ } else if (java_type == JAVATYPE_DOUBLE) {
+ printer->Print(variables_,
+ "{\n"
+ " long bits = java.lang.Double.doubleToLongBits(this.$name$);\n"
+ " if (bits != java.lang.Double.doubleToLongBits(other.$name$)");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (bits == java.lang.Double.doubleToLongBits($default$)\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "if (this.$name$ != other.$name$");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (this.$name$ == $default$\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ "}\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ JavaType java_type = GetJavaType(descriptor_);
+ if (java_type == JAVATYPE_BYTES) {
+ printer->Print(variables_,
+ "result = 31 * result + java.util.Arrays.hashCode(this.$name$);\n");
+ } else if (java_type == JAVATYPE_STRING
+ || params_.use_reference_types_for_primitives()) {
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + (this.$name$ == null ? 0 : this.$name$.hashCode());\n");
+ } else {
+ switch (java_type) {
+ // For all Java primitive types below, the hash codes match the
+ // results of BoxedType.valueOf(primitiveValue).hashCode().
+ case JAVATYPE_INT:
+ printer->Print(variables_,
+ "result = 31 * result + this.$name$;\n");
+ break;
+ case JAVATYPE_LONG:
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + (int) (this.$name$ ^ (this.$name$ >>> 32));\n");
+ break;
+ case JAVATYPE_FLOAT:
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + java.lang.Float.floatToIntBits(this.$name$);\n");
+ break;
+ case JAVATYPE_DOUBLE:
+ printer->Print(variables_,
+ "{\n"
+ " long v = java.lang.Double.doubleToLongBits(this.$name$);\n"
+ " result = 31 * result + (int) (v ^ (v >>> 32));\n"
+ "}\n");
+ break;
+ case JAVATYPE_BOOLEAN:
+ printer->Print(variables_,
+ "result = 31 * result + (this.$name$ ? 1231 : 1237);\n");
+ break;
+ default:
+ GOOGLE_LOG(ERROR) << "unknown java type for primitive field";
+ break;
+ }
+ }
+}
+
+// ===================================================================
+
+AccessorPrimitiveFieldGenerator::
+AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params, int has_bit_index)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, params, &variables_);
+ SetBitOperationVariables("has", has_bit_index, &variables_);
+}
+
+AccessorPrimitiveFieldGenerator::~AccessorPrimitiveFieldGenerator() {}
+
+bool AccessorPrimitiveFieldGenerator::SavedDefaultNeeded() const {
+ return variables_.find("default_constant") != variables_.end();
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateInitSavedDefaultCode(io::Printer* printer) const {
+ if (variables_.find("default_constant") != variables_.end()) {
+ printer->Print(variables_,
+ "$default_constant$ = $default_constant_value$;\n");
+ }
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer, bool lazy_init) const {
+ if (variables_.find("default_constant") != variables_.end()) {
+ // Those primitive types that need a saved default.
+ if (lazy_init) {
+ printer->Print(variables_,
+ "private static $type$ $default_constant$;\n");
+ } else {
+ printer->Print(variables_,
+ "private static final $type$ $default_constant$ =\n"
+ " $default_constant_value$;\n");
+ }
+ }
+ printer->Print(variables_,
+ "private $type$ $name$_;\n"
+ "public $type$ get$capitalized_name$() {\n"
+ " return $name$_;\n"
+ "}\n"
+ "public $message_name$ set$capitalized_name$($type$ value) {\n");
+ if (IsReferenceType(GetJavaType(descriptor_))) {
+ printer->Print(variables_,
+ " if (value == null) {\n"
+ " throw new java.lang.NullPointerException();\n"
+ " }\n");
+ }
+ printer->Print(variables_,
+ " $name$_ = value;\n"
+ " $set_has$;\n"
+ " return this;\n"
+ "}\n"
+ "public boolean has$capitalized_name$() {\n"
+ " return $get_has$;\n"
+ "}\n"
+ "public $message_name$ clear$capitalized_name$() {\n"
+ " $name$_ = $default_copy_if_needed$;\n"
+ " $clear_has$;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_ = $default_copy_if_needed$;\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_ = input.read$capitalized_type$();\n"
+ "$set_has$;\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has$) {\n"
+ " output.write$capitalized_type$($number$, $name$_);\n"
+ "}\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has$) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$Size($number$, $name$_);\n"
+ "}\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ switch (GetJavaType(descriptor_)) {
+ // For all Java primitive types below, the equality checks match the
+ // results of BoxedType.valueOf(primitiveValue).equals(otherValue).
+ case JAVATYPE_FLOAT:
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || java.lang.Float.floatToIntBits($name$_)\n"
+ " != java.lang.Float.floatToIntBits(other.$name$_)) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ case JAVATYPE_DOUBLE:
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || java.lang.Double.doubleToLongBits($name$_)\n"
+ " != java.lang.Double.doubleToLongBits(other.$name$_)) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ case JAVATYPE_INT:
+ case JAVATYPE_LONG:
+ case JAVATYPE_BOOLEAN:
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || $name$_ != other.$name$_) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ case JAVATYPE_STRING:
+ // Accessor style would guarantee $name$_ non-null
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || !$name$_.equals(other.$name$_)) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ case JAVATYPE_BYTES:
+ // Accessor style would guarantee $name$_ non-null
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || !java.util.Arrays.equals($name$_, other.$name$_)) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ default:
+ GOOGLE_LOG(ERROR) << "unknown java type for primitive field";
+ break;
+ }
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ switch (GetJavaType(descriptor_)) {
+ // For all Java primitive types below, the hash codes match the
+ // results of BoxedType.valueOf(primitiveValue).hashCode().
+ case JAVATYPE_INT:
+ printer->Print(variables_,
+ "result = 31 * result + $name$_;\n");
+ break;
+ case JAVATYPE_LONG:
+ printer->Print(variables_,
+ "result = 31 * result + (int) ($name$_ ^ ($name$_ >>> 32));\n");
+ break;
+ case JAVATYPE_FLOAT:
+ printer->Print(variables_,
+ "result = 31 * result +\n"
+ " java.lang.Float.floatToIntBits($name$_);\n");
+ break;
+ case JAVATYPE_DOUBLE:
+ printer->Print(variables_,
+ "{\n"
+ " long v = java.lang.Double.doubleToLongBits($name$_);\n"
+ " result = 31 * result + (int) (v ^ (v >>> 32));\n"
+ "}\n");
+ break;
+ case JAVATYPE_BOOLEAN:
+ printer->Print(variables_,
+ "result = 31 * result + ($name$_ ? 1231 : 1237);\n");
+ break;
+ case JAVATYPE_STRING:
+ // Accessor style would guarantee $name$_ non-null
+ printer->Print(variables_,
+ "result = 31 * result + $name$_.hashCode();\n");
+ break;
+ case JAVATYPE_BYTES:
+ // Accessor style would guarantee $name$_ non-null
+ printer->Print(variables_,
+ "result = 31 * result + java.util.Arrays.hashCode($name$_);\n");
+ break;
+ default:
+ GOOGLE_LOG(ERROR) << "unknown java type for primitive field";
+ break;
+ }
+}
+
+// ===================================================================
+
+PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, params, &variables_);
+ SetCommonOneofVariables(descriptor, &variables_);
+}
+
+PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
+
+void PrimitiveOneofFieldGenerator::GenerateMembers(
+ io::Printer* printer, bool /*unused lazy_init*/) const {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$() {\n"
+ " return $has_oneof_case$;\n"
+ "}\n"
+ "public $type$ get$capitalized_name$() {\n"
+ " if ($has_oneof_case$) {\n"
+ " return ($type$) ($boxed_type$) this.$oneof_name$_;\n"
+ " }\n"
+ " return $default$;\n"
+ "}\n"
+ "public $message_name$ set$capitalized_name$($type$ value) {\n"
+ " $set_oneof_case$;\n"
+ " this.$oneof_name$_ = value;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateClearCode(
+ io::Printer* printer) const {
+ // No clear method for oneof fields.
+}
+
+void PrimitiveOneofFieldGenerator::GenerateMergingCode(
+ io::Printer* printer) const {
+ printer->Print(variables_,
+ "this.$oneof_name$_ = input.read$capitalized_type$();\n"
+ "$set_oneof_case$;\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateSerializationCode(
+ io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case$) {\n"
+ " output.write$capitalized_type$(\n"
+ " $number$, ($boxed_type$) this.$oneof_name$_);\n"
+ "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateSerializedSizeCode(
+ io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($has_oneof_case$) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$Size(\n"
+ " $number$, ($boxed_type$) this.$oneof_name$_);\n"
+ "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateEqualsCode(
+ io::Printer* printer) const {
+ GenerateOneofFieldEquals(descriptor_, variables_, printer);
+}
+
+void PrimitiveOneofFieldGenerator::GenerateHashCodeCode(
+ io::Printer* printer) const {
+ GenerateOneofFieldHashCode(descriptor_, variables_, printer);
+}
+
+// ===================================================================
+
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, params, &variables_);
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /*unused init_defaults*/) const {
+ printer->Print(variables_,
+ "public $type$[] $name$;\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $default$;\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // First, figure out the length of the array, then parse.
+ printer->Print(variables_,
+ "int arrayLength = com.google.protobuf.nano.WireFormatNano\n"
+ " .getRepeatedFieldArrayLength(input, $non_packed_tag$);\n"
+ "int i = this.$name$ == null ? 0 : this.$name$.length;\n");
+
+ if (GetJavaType(descriptor_) == JAVATYPE_BYTES) {
+ printer->Print(variables_,
+ "byte[][] newArray = new byte[i + arrayLength][];\n");
+ } else {
+ printer->Print(variables_,
+ "$type$[] newArray = new $type$[i + arrayLength];\n");
+ }
+ printer->Print(variables_,
+ "if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ "}\n"
+ "for (; i < newArray.length - 1; i++) {\n"
+ " newArray[i] = input.read$capitalized_type$();\n"
+ " input.readTag();\n"
+ "}\n"
+ "// Last one without readTag.\n"
+ "newArray[i] = input.read$capitalized_type$();\n"
+ "this.$name$ = newArray;\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMergingCodeFromPacked(io::Printer* printer) const {
+ printer->Print(
+ "int length = input.readRawVarint32();\n"
+ "int limit = input.pushLimit(length);\n");
+
+ // If we know the elements will all be of the same size, the arrayLength
+ // can be calculated much more easily. However, FixedSize() returns 1 for
+ // repeated bool fields, which are guaranteed to have the fixed size of
+ // 1 byte per value only if we control the output. On the wire they can
+ // legally appear as variable-size integers, so we need to use the slow
+ // way for repeated bool fields.
+ if (descriptor_->type() == FieldDescriptor::TYPE_BOOL
+ || FixedSize(descriptor_->type()) == -1) {
+ printer->Print(variables_,
+ "// First pass to compute array length.\n"
+ "int arrayLength = 0;\n"
+ "int startPos = input.getPosition();\n"
+ "while (input.getBytesUntilLimit() > 0) {\n"
+ " input.read$capitalized_type$();\n"
+ " arrayLength++;\n"
+ "}\n"
+ "input.rewindToPosition(startPos);\n");
+ } else {
+ printer->Print(variables_,
+ "int arrayLength = length / $fixed_size$;\n");
+ }
+
+ printer->Print(variables_,
+ "int i = this.$name$ == null ? 0 : this.$name$.length;\n"
+ "$type$[] newArray = new $type$[i + arrayLength];\n"
+ "if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ "}\n"
+ "for (; i < newArray.length; i++) {\n"
+ " newArray[i] = input.read$capitalized_type$();\n"
+ "}\n"
+ "this.$name$ = newArray;\n"
+ "input.popLimit(limit);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateRepeatedDataSizeCode(io::Printer* printer) const {
+ // Creates a variable dataSize and puts the serialized size in there.
+ // If the element type is a Java reference type, also generates
+ // dataCount which stores the number of non-null elements in the field.
+ if (IsReferenceType(GetJavaType(descriptor_))) {
+ printer->Print(variables_,
+ "int dataCount = 0;\n"
+ "int dataSize = 0;\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " if (element != null) {\n"
+ " dataCount++;\n"
+ " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$SizeNoTag(element);\n"
+ " }\n"
+ "}\n");
+ } else if (FixedSize(descriptor_->type()) == -1) {
+ printer->Print(variables_,
+ "int dataSize = 0;\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$SizeNoTag(element);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "int dataSize = $fixed_size$ * this.$name$.length;\n");
+ }
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n");
+ printer->Indent();
+
+ if (descriptor_->is_packable() && descriptor_->options().packed()) {
+ GenerateRepeatedDataSizeCode(printer);
+ printer->Print(variables_,
+ "output.writeRawVarint32($tag$);\n"
+ "output.writeRawVarint32(dataSize);\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " output.write$capitalized_type$NoTag(this.$name$[i]);\n"
+ "}\n");
+ } else if (IsReferenceType(GetJavaType(descriptor_))) {
+ printer->Print(variables_,
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " if (element != null) {\n"
+ " output.write$capitalized_type$($number$, element);\n"
+ " }\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " output.write$capitalized_type$($number$, this.$name$[i]);\n"
+ "}\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n");
+ printer->Indent();
+
+ GenerateRepeatedDataSizeCode(printer);
+
+ printer->Print(
+ "size += dataSize;\n");
+ if (descriptor_->is_packable() && descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "size += $tag_size$;\n"
+ "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeRawVarint32Size(dataSize);\n");
+ } else if (IsReferenceType(GetJavaType(descriptor_))) {
+ printer->Print(variables_,
+ "size += $tag_size$ * dataCount;\n");
+ } else {
+ printer->Print(variables_,
+ "size += $tag_size$ * this.$name$.length;\n");
+ }
+
+ printer->Outdent();
+
+ printer->Print(
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!com.google.protobuf.nano.InternalNano.equals(\n"
+ " this.$name$, other.$name$)) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
new file mode 100644
index 00000000..ca7116ff
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
@@ -0,0 +1,149 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_PRIMITIVE_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class PrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit PrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params);
+ ~PrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ bool SavedDefaultNeeded() const;
+ void GenerateInitSavedDefaultCode(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ void GenerateSerializationConditional(io::Printer* printer) const;
+
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class AccessorPrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Params &params, int has_bit_index);
+ ~AccessorPrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ bool SavedDefaultNeeded() const;
+ void GenerateInitSavedDefaultCode(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorPrimitiveFieldGenerator);
+};
+
+class PrimitiveOneofFieldGenerator : public FieldGenerator {
+ public:
+ explicit PrimitiveOneofFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params);
+ ~PrimitiveOneofFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator);
+};
+
+class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params);
+ ~RepeatedPrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateMergingCodeFromPacked(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
+
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_PRIMITIVE_FIELD_H__
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index d9b0c3f9..931b8fa3 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,7 +34,8 @@
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <google/protobuf/compiler/python/python_generator.h>
#include <google/protobuf/compiler/java/java_generator.h>
-
+#include <google/protobuf/compiler/javanano/javanano_generator.h>
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
int main(int argc, char* argv[]) {
@@ -43,7 +44,7 @@ int main(int argc, char* argv[]) {
// Proto2 C++
google::protobuf::compiler::cpp::CppGenerator cpp_generator;
- cli.RegisterGenerator("--cpp_out", &cpp_generator,
+ cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator,
"Generate C++ header and source.");
// Proto2 Java
@@ -57,5 +58,15 @@ int main(int argc, char* argv[]) {
cli.RegisterGenerator("--python_out", &py_generator,
"Generate Python source file.");
+ // Java Nano
+ google::protobuf::compiler::javanano::JavaNanoGenerator javanano_generator;
+ cli.RegisterGenerator("--javanano_out", &javanano_generator,
+ "Generate Java Nano source file.");
+
+ // Ruby
+ google::protobuf::compiler::ruby::Generator rb_generator;
+ cli.RegisterGenerator("--ruby_out", &rb_generator,
+ "Generate Ruby source file.");
+
return cli.Run(argc, argv);
}
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index 5b76af25..98261431 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,14 +32,20 @@
#include <google/protobuf/compiler/mock_code_generator.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
#include <google/protobuf/testing/file.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -52,7 +58,7 @@ string CommaSeparatedList(const vector<const FileDescriptor*> all_files) {
for (int i = 0; i < all_files.size(); i++) {
names.push_back(all_files[i]->name());
}
- return JoinStrings(names, ",");
+ return Join(names, ",");
}
static const char* kFirstInsertionPointName = "first_mock_insertion_point";
@@ -76,11 +82,11 @@ void MockCodeGenerator::ExpectGenerated(
const string& first_parsed_file_name,
const string& output_directory) {
string content;
- ASSERT_TRUE(File::ReadFileToString(
- output_directory + "/" + GetOutputFileName(name, file), &content));
+ GOOGLE_CHECK_OK(
+ File::GetContents(output_directory + "/" + GetOutputFileName(name, file),
+ &content, true));
- vector<string> lines;
- SplitStringUsing(content, "\n", &lines);
+ vector<string> lines = Split(content, "\n", true);
while (!lines.empty() && lines.back().empty()) {
lines.pop_back();
@@ -94,7 +100,7 @@ void MockCodeGenerator::ExpectGenerated(
SplitStringUsing(insertions, ",", &insertion_list);
}
- ASSERT_EQ(lines.size(), 3 + insertion_list.size() * 2);
+ EXPECT_EQ(lines.size(), 3 + insertion_list.size() * 2);
EXPECT_EQ(GetOutputFileContent(name, parameter, file,
first_parsed_file_name, first_message_name),
lines[0]);
@@ -127,10 +133,19 @@ bool MockCodeGenerator::Generate(
*error = "Saw message type MockCodeGenerator_Error.";
return false;
} else if (command == "Exit") {
- cerr << "Saw message type MockCodeGenerator_Exit." << endl;
+ std::cerr << "Saw message type MockCodeGenerator_Exit." << std::endl;
exit(123);
} else if (command == "Abort") {
- cerr << "Saw message type MockCodeGenerator_Abort." << endl;
+ std::cerr << "Saw message type MockCodeGenerator_Abort." << std::endl;
+ abort();
+ } else if (command == "HasSourceCodeInfo") {
+ FileDescriptorProto file_descriptor_proto;
+ file->CopySourceCodeInfoTo(&file_descriptor_proto);
+ bool has_source_code_info =
+ file_descriptor_proto.has_source_code_info() &&
+ file_descriptor_proto.source_code_info().location_size() > 0;
+ std::cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
+ << has_source_code_info << "." << std::endl;
abort();
} else {
GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
@@ -145,10 +160,8 @@ bool MockCodeGenerator::Generate(
for (int i = 0; i < insert_into.size(); i++) {
{
- scoped_ptr<io::ZeroCopyOutputStream> output(
- context->OpenForInsert(
- GetOutputFileName(insert_into[i], file),
- kFirstInsertionPointName));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->OpenForInsert(
+ GetOutputFileName(insert_into[i], file), kFirstInsertionPointName));
io::Printer printer(output.get(), '$');
printer.PrintRaw(GetOutputFileContent(name_, "first_insert",
file, context));
@@ -159,10 +172,9 @@ bool MockCodeGenerator::Generate(
}
{
- scoped_ptr<io::ZeroCopyOutputStream> output(
- context->OpenForInsert(
- GetOutputFileName(insert_into[i], file),
- kSecondInsertionPointName));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->OpenForInsert(GetOutputFileName(insert_into[i], file),
+ kSecondInsertionPointName));
io::Printer printer(output.get(), '$');
printer.PrintRaw(GetOutputFileContent(name_, "second_insert",
file, context));
@@ -173,7 +185,7 @@ bool MockCodeGenerator::Generate(
}
}
} else {
- scoped_ptr<io::ZeroCopyOutputStream> output(
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
context->Open(GetOutputFileName(name_, file)));
io::Printer printer(output.get(), '$');
diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h
index 5c7942bd..8c8348d8 100644
--- a/src/google/protobuf/compiler/mock_code_generator.h
+++ b/src/google/protobuf/compiler/mock_code_generator.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -59,6 +59,10 @@ namespace compiler {
// MockCodeGenerator_Exit." to stderr and then calls exit(123).
// MockCodeGenerator_Abort: Generate() prints "Saw message type
// MockCodeGenerator_Abort." to stderr and then calls abort().
+// MockCodeGenerator_HasSourceCodeInfo: Causes Generate() to abort after
+// printing "Saw message type MockCodeGenerator_HasSourceCodeInfo: FOO." to
+// stderr, where FOO is "1" if the supplied FileDescriptorProto has source
+// code info, and "0" otherwise.
class MockCodeGenerator : public CodeGenerator {
public:
MockCodeGenerator(const string& name);
diff --git a/src/google/protobuf/compiler/package_info.h b/src/google/protobuf/compiler/package_info.h
index b8971267..fb6b473e 100644
--- a/src/google/protobuf/compiler/package_info.h
+++ b/src/google/protobuf/compiler/package_info.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 34317b1f..c50cdf54 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,7 +46,7 @@
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/map_util.h>
namespace google {
namespace protobuf {
@@ -84,6 +84,32 @@ TypeNameMap MakeTypeNameTable() {
const TypeNameMap kTypeNames = MakeTypeNameTable();
+// Camel-case the field name and append "Entry" for generated map entry name.
+// e.g. map<KeyType, ValueType> foo_map => FooMapEntry
+string MapEntryName(const string& field_name) {
+ string result;
+ static const char kSuffix[] = "Entry";
+ result.reserve(field_name.size() + sizeof(kSuffix));
+ bool cap_next = true;
+ for (int i = 0; i < field_name.size(); ++i) {
+ if (field_name[i] == '_') {
+ cap_next = true;
+ } else if (cap_next) {
+ // Note: Do not use ctype.h due to locales.
+ if ('a' <= field_name[i] && field_name[i] <= 'z') {
+ result.push_back(field_name[i] - 'a' + 'A');
+ } else {
+ result.push_back(field_name[i]);
+ }
+ cap_next = false;
+ } else {
+ result.push_back(field_name[i]);
+ }
+ }
+ result.append(kSuffix);
+ return result;
+}
+
} // anonymous namespace
// Makes code slightly more readable. The meaning of "DO(foo)" is
@@ -174,6 +200,20 @@ bool Parser::ConsumeInteger(int* output, const char* error) {
}
}
+bool Parser::ConsumeSignedInteger(int* output, const char* error) {
+ bool is_negative = false;
+ uint64 max_value = kint32max;
+ if (TryConsume("-")) {
+ is_negative = true;
+ max_value += 1;
+ }
+ uint64 value = 0;
+ DO(ConsumeInteger64(max_value, &value, error));
+ if (is_negative) value *= -1;
+ *output = value;
+ return true;
+}
+
bool Parser::ConsumeInteger64(uint64 max_value, uint64* output,
const char* error) {
if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
@@ -237,6 +277,47 @@ bool Parser::ConsumeString(string* output, const char* error) {
}
}
+bool Parser::TryConsumeEndOfDeclaration(
+ const char* text, const LocationRecorder* location) {
+ if (LookingAt(text)) {
+ string leading, trailing;
+ vector<string> detached;
+ input_->NextWithComments(&trailing, &detached, &leading);
+
+ // Save the leading comments for next time, and recall the leading comments
+ // from last time.
+ leading.swap(upcoming_doc_comments_);
+
+ if (location != NULL) {
+ upcoming_detached_comments_.swap(detached);
+ location->AttachComments(&leading, &trailing, &detached);
+ } else if (strcmp(text, "}") == 0) {
+ // If the current location is null and we are finishing the current scope,
+ // drop pending upcoming detached comments.
+ upcoming_detached_comments_.swap(detached);
+ } else {
+ // Otherwise, append the new detached comments to the existing upcoming
+ // detached comments.
+ upcoming_detached_comments_.insert(upcoming_detached_comments_.end(),
+ detached.begin(), detached.end());
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Parser::ConsumeEndOfDeclaration(
+ const char* text, const LocationRecorder* location) {
+ if (TryConsumeEndOfDeclaration(text, location)) {
+ return true;
+ } else {
+ AddError("Expected \"" + string(text) + "\".");
+ return false;
+ }
+}
+
// -------------------------------------------------------------------
void Parser::AddError(int line, int column, const string& error) {
@@ -300,6 +381,11 @@ void Parser::LocationRecorder::StartAt(const io::Tokenizer::Token& token) {
location_->set_span(1, token.column);
}
+void Parser::LocationRecorder::StartAt(const LocationRecorder& other) {
+ location_->set_span(0, other.location_->span(0));
+ location_->set_span(1, other.location_->span(1));
+}
+
void Parser::LocationRecorder::EndAt(const io::Tokenizer::Token& token) {
if (token.line != location_->span(0)) {
location_->add_span(token.line);
@@ -315,6 +401,25 @@ void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor,
}
}
+void Parser::LocationRecorder::AttachComments(
+ string* leading, string* trailing,
+ vector<string>* detached_comments) const {
+ GOOGLE_CHECK(!location_->has_leading_comments());
+ GOOGLE_CHECK(!location_->has_trailing_comments());
+
+ if (!leading->empty()) {
+ location_->mutable_leading_comments()->swap(*leading);
+ }
+ if (!trailing->empty()) {
+ location_->mutable_trailing_comments()->swap(*trailing);
+ }
+ for (int i = 0; i < detached_comments->size(); ++i) {
+ location_->add_leading_detached_comments()->swap(
+ (*detached_comments)[i]);
+ }
+ detached_comments->clear();
+}
+
// -------------------------------------------------------------------
void Parser::SkipStatement() {
@@ -322,7 +427,7 @@ void Parser::SkipStatement() {
if (AtEnd()) {
return;
} else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
- if (TryConsume(";")) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
return;
} else if (TryConsume("{")) {
SkipRestOfBlock();
@@ -340,7 +445,7 @@ void Parser::SkipRestOfBlock() {
if (AtEnd()) {
return;
} else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
- if (TryConsume("}")) {
+ if (TryConsumeEndOfDeclaration("}", NULL)) {
return;
} else if (TryConsume("{")) {
SkipRestOfBlock();
@@ -364,21 +469,29 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
SourceCodeInfo source_code_info;
source_code_info_ = &source_code_info;
+ vector<string> top_doc_comments;
if (LookingAtType(io::Tokenizer::TYPE_START)) {
// Advance to first token.
- input_->Next();
+ input_->NextWithComments(NULL, &upcoming_detached_comments_,
+ &upcoming_doc_comments_);
}
{
LocationRecorder root_location(this);
if (require_syntax_identifier_ || LookingAt("syntax")) {
- if (!ParseSyntaxIdentifier()) {
+ if (!ParseSyntaxIdentifier(root_location)) {
// Don't attempt to parse the file if we didn't recognize the syntax
// identifier.
return false;
}
+ // Store the syntax into the file.
+ if (file != NULL) file->set_syntax(syntax_identifier_);
} else if (!stop_after_syntax_identifier_) {
+ GOOGLE_LOG(WARNING) << "No syntax specified for the proto file. "
+ << "Please use 'syntax = \"proto2\";' or "
+ << "'syntax = \"proto3\";' to specify a syntax "
+ << "version. (Defaulted to proto2 syntax.)";
syntax_identifier_ = "proto2";
}
@@ -393,7 +506,8 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
if (LookingAt("}")) {
AddError("Unmatched \"}\".");
- input_->Next();
+ input_->NextWithComments(NULL, &upcoming_detached_comments_,
+ &upcoming_doc_comments_);
}
}
}
@@ -405,20 +519,25 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
return !had_errors_;
}
-bool Parser::ParseSyntaxIdentifier() {
- DO(Consume("syntax", "File must begin with 'syntax = \"proto2\";'."));
+bool Parser::ParseSyntaxIdentifier(const LocationRecorder& parent) {
+ LocationRecorder syntax_location(parent,
+ FileDescriptorProto::kSyntaxFieldNumber);
+ 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;
DO(ConsumeString(&syntax, "Expected syntax identifier."));
- DO(Consume(";"));
+ DO(ConsumeEndOfDeclaration(";", &syntax_location));
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;
}
@@ -427,21 +546,21 @@ bool Parser::ParseSyntaxIdentifier() {
bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
const LocationRecorder& root_location) {
- if (TryConsume(";")) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
// empty statement; ignore
return true;
} else if (LookingAt("message")) {
LocationRecorder location(root_location,
FileDescriptorProto::kMessageTypeFieldNumber, file->message_type_size());
- return ParseMessageDefinition(file->add_message_type(), location);
+ return ParseMessageDefinition(file->add_message_type(), location, file);
} else if (LookingAt("enum")) {
LocationRecorder location(root_location,
FileDescriptorProto::kEnumTypeFieldNumber, file->enum_type_size());
- return ParseEnumDefinition(file->add_enum_type(), location);
+ return ParseEnumDefinition(file->add_enum_type(), location, file);
} else if (LookingAt("service")) {
LocationRecorder location(root_location,
FileDescriptorProto::kServiceFieldNumber, file->service_size());
- return ParseServiceDefinition(file->add_service(), location);
+ return ParseServiceDefinition(file->add_service(), location, file);
} else if (LookingAt("extend")) {
LocationRecorder location(root_location,
FileDescriptorProto::kExtensionFieldNumber);
@@ -449,16 +568,19 @@ bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
file->mutable_message_type(),
root_location,
FileDescriptorProto::kMessageTypeFieldNumber,
- location);
+ location, file);
} else if (LookingAt("import")) {
- int index = file->dependency_size();
- return ParseImport(file->add_dependency(), root_location, index);
+ return ParseImport(file->mutable_dependency(),
+ file->mutable_public_dependency(),
+ file->mutable_weak_dependency(),
+ root_location, file);
} else if (LookingAt("package")) {
- return ParsePackage(file, root_location);
+ return ParsePackage(file, root_location, file);
} else if (LookingAt("option")) {
LocationRecorder location(root_location,
FileDescriptorProto::kOptionsFieldNumber);
- return ParseOption(file->mutable_options(), location);
+ return ParseOption(file->mutable_options(), location, file,
+ OPTION_STATEMENT);
} else {
AddError("Expected top-level statement (e.g. \"message\").");
return false;
@@ -468,8 +590,10 @@ bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
// -------------------------------------------------------------------
// Messages
-bool Parser::ParseMessageDefinition(DescriptorProto* message,
- const LocationRecorder& message_location) {
+bool Parser::ParseMessageDefinition(
+ DescriptorProto* message,
+ const LocationRecorder& message_location,
+ const FileDescriptorProto* containing_file) {
DO(Consume("message"));
{
LocationRecorder location(message_location,
@@ -478,49 +602,90 @@ bool Parser::ParseMessageDefinition(DescriptorProto* message,
message, DescriptorPool::ErrorCollector::NAME);
DO(ConsumeIdentifier(message->mutable_name(), "Expected message name."));
}
- DO(ParseMessageBlock(message, message_location));
+ DO(ParseMessageBlock(message, message_location, containing_file));
return true;
}
+namespace {
+
+const int kMaxExtensionRangeSentinel = -1;
+
+bool IsMessageSetWireFormatMessage(const DescriptorProto& message) {
+ const MessageOptions& options = message.options();
+ for (int i = 0; i < options.uninterpreted_option_size(); ++i) {
+ const UninterpretedOption& uninterpreted = options.uninterpreted_option(i);
+ if (uninterpreted.name_size() == 1 &&
+ uninterpreted.name(0).name_part() == "message_set_wire_format" &&
+ uninterpreted.identifier_value() == "true") {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Modifies any extension ranges that specified 'max' as the end of the
+// extension range, and sets them to the type-specific maximum. The actual max
+// tag number can only be determined after all options have been parsed.
+void AdjustExtensionRangesWithMaxEndNumber(DescriptorProto* message) {
+ const bool is_message_set = IsMessageSetWireFormatMessage(*message);
+ const int max_extension_number = is_message_set ?
+ kint32max :
+ FieldDescriptor::kMaxNumber + 1;
+ for (int i = 0; i < message->extension_range_size(); ++i) {
+ if (message->extension_range(i).end() == kMaxExtensionRangeSentinel) {
+ message->mutable_extension_range(i)->set_end(max_extension_number);
+ }
+ }
+}
+
+} // namespace
+
bool Parser::ParseMessageBlock(DescriptorProto* message,
- const LocationRecorder& message_location) {
- DO(Consume("{"));
+ const LocationRecorder& message_location,
+ const FileDescriptorProto* containing_file) {
+ DO(ConsumeEndOfDeclaration("{", &message_location));
- while (!TryConsume("}")) {
+ while (!TryConsumeEndOfDeclaration("}", NULL)) {
if (AtEnd()) {
AddError("Reached end of input in message definition (missing '}').");
return false;
}
- if (!ParseMessageStatement(message, message_location)) {
+ if (!ParseMessageStatement(message, message_location, containing_file)) {
// This statement failed to parse. Skip it, but keep looping to parse
// other statements.
SkipStatement();
}
}
+ if (message->extension_range_size() > 0) {
+ AdjustExtensionRangesWithMaxEndNumber(message);
+ }
return true;
}
bool Parser::ParseMessageStatement(DescriptorProto* message,
- const LocationRecorder& message_location) {
- if (TryConsume(";")) {
+ const LocationRecorder& message_location,
+ const FileDescriptorProto* containing_file) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
// empty statement; ignore
return true;
} else if (LookingAt("message")) {
LocationRecorder location(message_location,
DescriptorProto::kNestedTypeFieldNumber,
message->nested_type_size());
- return ParseMessageDefinition(message->add_nested_type(), location);
+ return ParseMessageDefinition(message->add_nested_type(), location,
+ containing_file);
} else if (LookingAt("enum")) {
LocationRecorder location(message_location,
DescriptorProto::kEnumTypeFieldNumber,
message->enum_type_size());
- return ParseEnumDefinition(message->add_enum_type(), location);
+ return ParseEnumDefinition(message->add_enum_type(), location,
+ containing_file);
} else if (LookingAt("extensions")) {
LocationRecorder location(message_location,
DescriptorProto::kExtensionRangeFieldNumber);
- return ParseExtensions(message, location);
+ return ParseExtensions(message, location, containing_file);
} else if (LookingAt("extend")) {
LocationRecorder location(message_location,
DescriptorProto::kExtensionFieldNumber);
@@ -528,11 +693,21 @@ bool Parser::ParseMessageStatement(DescriptorProto* message,
message->mutable_nested_type(),
message_location,
DescriptorProto::kNestedTypeFieldNumber,
- location);
+ location, containing_file);
} else if (LookingAt("option")) {
LocationRecorder location(message_location,
DescriptorProto::kOptionsFieldNumber);
- return ParseOption(message->mutable_options(), location);
+ return ParseOption(message->mutable_options(), location,
+ containing_file, OPTION_STATEMENT);
+ } else if (LookingAt("oneof")) {
+ int oneof_index = message->oneof_decl_size();
+ LocationRecorder oneof_location(message_location,
+ DescriptorProto::kOneofDeclFieldNumber,
+ oneof_index);
+
+ return ParseOneof(message->add_oneof_decl(), message,
+ oneof_index, oneof_location, message_location,
+ containing_file);
} else {
LocationRecorder location(message_location,
DescriptorProto::kFieldFieldNumber,
@@ -541,7 +716,8 @@ bool Parser::ParseMessageStatement(DescriptorProto* message,
message->mutable_nested_type(),
message_location,
DescriptorProto::kNestedTypeFieldNumber,
- location);
+ location,
+ containing_file);
}
}
@@ -549,30 +725,99 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field,
RepeatedPtrField<DescriptorProto>* messages,
const LocationRecorder& parent_location,
int location_field_number_for_nested_type,
- const LocationRecorder& field_location) {
- // Parse label and type.
- io::Tokenizer::Token label_token = input_->current();
+ const LocationRecorder& field_location,
+ const FileDescriptorProto* containing_file) {
{
LocationRecorder location(field_location,
FieldDescriptorProto::kLabelFieldNumber);
FieldDescriptorProto::Label label;
- DO(ParseLabel(&label));
- field->set_label(label);
+ if (ParseLabel(&label, containing_file)) {
+ field->set_label(label);
+ }
}
+ return ParseMessageFieldNoLabel(field, messages, parent_location,
+ location_field_number_for_nested_type,
+ field_location,
+ containing_file);
+}
+
+bool Parser::ParseMessageFieldNoLabel(
+ FieldDescriptorProto* field,
+ RepeatedPtrField<DescriptorProto>* messages,
+ const LocationRecorder& parent_location,
+ 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);
+ }
}
}
@@ -598,14 +843,14 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field,
}
// Parse options.
- DO(ParseFieldOptions(field, field_location));
+ DO(ParseFieldOptions(field, field_location, containing_file));
// Deal with groups.
if (field->has_type() && field->type() == FieldDescriptorProto::TYPE_GROUP) {
// Awkward: Since a group declares both a message type and a field, we
// have to create overlapping locations.
LocationRecorder group_location(parent_location);
- group_location.StartAt(label_token);
+ group_location.StartAt(field_location);
group_location.AddPath(location_field_number_for_nested_type);
group_location.AddPath(messages->size());
@@ -641,20 +886,54 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field,
field->set_type_name(group->name());
if (LookingAt("{")) {
- DO(ParseMessageBlock(group, group_location));
+ DO(ParseMessageBlock(group, group_location, containing_file));
} else {
AddError("Missing group body.");
return false;
}
} else {
- DO(Consume(";"));
+ DO(ConsumeEndOfDeclaration(";", &field_location));
+ }
+
+ // Create a map entry type if this is a map field.
+ if (map_field.is_map_field) {
+ GenerateMapEntry(map_field, field, messages);
}
return true;
}
+void Parser::GenerateMapEntry(const MapField& map_field,
+ FieldDescriptorProto* field,
+ RepeatedPtrField<DescriptorProto>* messages) {
+ DescriptorProto* entry = messages->Add();
+ string entry_name = MapEntryName(field->name());
+ field->set_type_name(entry_name);
+ entry->set_name(entry_name);
+ entry->mutable_options()->set_map_entry(true);
+ FieldDescriptorProto* key_field = entry->add_field();
+ key_field->set_name("key");
+ key_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+ key_field->set_number(1);
+ if (map_field.key_type_name.empty()) {
+ key_field->set_type(map_field.key_type);
+ } else {
+ key_field->set_type_name(map_field.key_type_name);
+ }
+ FieldDescriptorProto* value_field = entry->add_field();
+ value_field->set_name("value");
+ value_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+ value_field->set_number(2);
+ if (map_field.value_type_name.empty()) {
+ value_field->set_type(map_field.value_type);
+ } else {
+ value_field->set_type_name(map_field.value_type_name);
+ }
+}
+
bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
- const LocationRecorder& field_location) {
+ const LocationRecorder& field_location,
+ const FileDescriptorProto* containing_file) {
if (!LookingAt("[")) return true;
LocationRecorder location(field_location,
@@ -667,9 +946,10 @@ bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
if (LookingAt("default")) {
// We intentionally pass field_location rather than location here, since
// the default value is not actually an option.
- DO(ParseDefaultAssignment(field, field_location));
+ DO(ParseDefaultAssignment(field, field_location, containing_file));
} else {
- DO(ParseOptionAssignment(field->mutable_options(), location));
+ DO(ParseOption(field->mutable_options(), location,
+ containing_file, OPTION_ASSIGNMENT));
}
} while (TryConsume(","));
@@ -677,8 +957,10 @@ bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
return true;
}
-bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field,
- const LocationRecorder& field_location) {
+bool Parser::ParseDefaultAssignment(
+ FieldDescriptorProto* field,
+ const LocationRecorder& field_location,
+ const FileDescriptorProto* containing_file) {
if (field->has_default_value()) {
AddError("Already set option \"default\".");
field->clear_default_value();
@@ -695,8 +977,16 @@ bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field,
if (!field->has_type()) {
// The field has a type name, but we don't know if it is a message or an
- // enum yet. Assume an enum for now.
- DO(ConsumeIdentifier(default_value, "Expected identifier."));
+ // enum yet. (If it were a primitive type, |field| would have a type set
+ // already.) In this case, simply take the current string as the default
+ // value; we will catch the error later if it is not a valid enum value.
+ // (N.B. that we do not check whether the current token is an identifier:
+ // doing so throws strange errors when the user mistypes a primitive
+ // typename and we assume it's an enum. E.g.: "optional int foo = 1 [default
+ // = 42]". In such a case the fundamental error is really that "int" is not
+ // a type, not that "42" is not an identifier. See b/12533582.)
+ *default_value = input_->current().text;
+ input_->Next();
return true;
}
@@ -722,7 +1012,8 @@ bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field,
}
// Parse the integer to verify that it is not out-of-range.
uint64 value;
- DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+ DO(ConsumeInteger64(max_value, &value,
+ "Expected integer for field default value."));
// And stringify it again.
default_value->append(SimpleItoa(value));
break;
@@ -744,7 +1035,8 @@ bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field,
}
// Parse the integer to verify that it is not out-of-range.
uint64 value;
- DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+ DO(ConsumeInteger64(max_value, &value,
+ "Expected integer for field default value."));
// And stringify it again.
default_value->append(SimpleItoa(value));
break;
@@ -776,7 +1068,11 @@ bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field,
break;
case FieldDescriptorProto::TYPE_STRING:
- DO(ConsumeString(default_value, "Expected string."));
+ // Note: When file opton java_string_check_utf8 is true, if a
+ // non-string representation (eg byte[]) is later supported, it must
+ // be checked for UTF-8-ness.
+ DO(ConsumeString(default_value, "Expected string for field default "
+ "value."));
break;
case FieldDescriptorProto::TYPE_BYTES:
@@ -785,7 +1081,8 @@ bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field,
break;
case FieldDescriptorProto::TYPE_ENUM:
- DO(ConsumeIdentifier(default_value, "Expected identifier."));
+ DO(ConsumeIdentifier(default_value, "Expected enum identifier for field "
+ "default value."));
break;
case FieldDescriptorProto::TYPE_MESSAGE:
@@ -798,7 +1095,8 @@ bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field,
}
bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
- const LocationRecorder& part_location) {
+ const LocationRecorder& part_location,
+ const FileDescriptorProto* containing_file) {
UninterpretedOption::NamePart* name = uninterpreted_option->add_name();
string identifier; // We parse identifiers into this string.
if (LookingAt("(")) { // This is an extension.
@@ -835,6 +1133,8 @@ bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
bool Parser::ParseUninterpretedBlock(string* value) {
// Note that enclosing braces are not added to *value.
+ // We do NOT use ConsumeEndOfStatement for this brace because it's delimiting
+ // an expression, not a block of statements.
DO(Consume("{"));
int brace_depth = 1;
while (!AtEnd()) {
@@ -858,8 +1158,10 @@ bool Parser::ParseUninterpretedBlock(string* value) {
// We don't interpret the option here. Instead we store it in an
// UninterpretedOption, to be interpreted later.
-bool Parser::ParseOptionAssignment(Message* options,
- const LocationRecorder& options_location) {
+bool Parser::ParseOption(Message* options,
+ const LocationRecorder& options_location,
+ const FileDescriptorProto* containing_file,
+ OptionStyle style) {
// Create an entry in the uninterpreted_option field.
const FieldDescriptor* uninterpreted_option_field = options->GetDescriptor()->
FindFieldByName("uninterpreted_option");
@@ -872,6 +1174,10 @@ bool Parser::ParseOptionAssignment(Message* options,
options_location, uninterpreted_option_field->number(),
reflection->FieldSize(*options, uninterpreted_option_field));
+ if (style == OPTION_STATEMENT) {
+ DO(Consume("option"));
+ }
+
UninterpretedOption* uninterpreted_option = down_cast<UninterpretedOption*>(
options->GetReflection()->AddMessage(options,
uninterpreted_option_field));
@@ -886,102 +1192,114 @@ bool Parser::ParseOptionAssignment(Message* options,
{
LocationRecorder part_location(name_location,
uninterpreted_option->name_size());
- DO(ParseOptionNamePart(uninterpreted_option, part_location));
+ DO(ParseOptionNamePart(uninterpreted_option, part_location,
+ containing_file));
}
while (LookingAt(".")) {
DO(Consume("."));
LocationRecorder part_location(name_location,
uninterpreted_option->name_size());
- DO(ParseOptionNamePart(uninterpreted_option, part_location));
+ DO(ParseOptionNamePart(uninterpreted_option, part_location,
+ containing_file));
}
}
DO(Consume("="));
- LocationRecorder value_location(location);
- value_location.RecordLegacyLocation(
- uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE);
-
- // All values are a single token, except for negative numbers, which consist
- // of a single '-' symbol, followed by a positive number.
- bool is_negative = TryConsume("-");
+ {
+ LocationRecorder value_location(location);
+ value_location.RecordLegacyLocation(
+ uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE);
- switch (input_->current().type) {
- case io::Tokenizer::TYPE_START:
- GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read.";
- return false;
+ // All values are a single token, except for negative numbers, which consist
+ // of a single '-' symbol, followed by a positive number.
+ bool is_negative = TryConsume("-");
- case io::Tokenizer::TYPE_END:
- AddError("Unexpected end of stream while parsing option value.");
- return false;
+ switch (input_->current().type) {
+ case io::Tokenizer::TYPE_START:
+ GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read.";
+ return false;
- case io::Tokenizer::TYPE_IDENTIFIER: {
- value_location.AddPath(UninterpretedOption::kIdentifierValueFieldNumber);
- if (is_negative) {
- AddError("Invalid '-' symbol before identifier.");
+ case io::Tokenizer::TYPE_END:
+ AddError("Unexpected end of stream while parsing option value.");
return false;
- }
- string value;
- DO(ConsumeIdentifier(&value, "Expected identifier."));
- uninterpreted_option->set_identifier_value(value);
- break;
- }
- case io::Tokenizer::TYPE_INTEGER: {
- uint64 value;
- uint64 max_value =
- is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max;
- DO(ConsumeInteger64(max_value, &value, "Expected integer."));
- if (is_negative) {
+ case io::Tokenizer::TYPE_IDENTIFIER: {
value_location.AddPath(
- UninterpretedOption::kNegativeIntValueFieldNumber);
- uninterpreted_option->set_negative_int_value(-static_cast<int64>(value));
- } else {
- value_location.AddPath(
- UninterpretedOption::kPositiveIntValueFieldNumber);
- uninterpreted_option->set_positive_int_value(value);
+ UninterpretedOption::kIdentifierValueFieldNumber);
+ if (is_negative) {
+ AddError("Invalid '-' symbol before identifier.");
+ return false;
+ }
+ string value;
+ DO(ConsumeIdentifier(&value, "Expected identifier."));
+ uninterpreted_option->set_identifier_value(value);
+ break;
}
- break;
- }
- case io::Tokenizer::TYPE_FLOAT: {
- value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
- double value;
- DO(ConsumeNumber(&value, "Expected number."));
- uninterpreted_option->set_double_value(is_negative ? -value : value);
- break;
- }
+ case io::Tokenizer::TYPE_INTEGER: {
+ uint64 value;
+ uint64 max_value =
+ is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max;
+ DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+ if (is_negative) {
+ value_location.AddPath(
+ UninterpretedOption::kNegativeIntValueFieldNumber);
+ uninterpreted_option->set_negative_int_value(
+ -static_cast<int64>(value));
+ } else {
+ value_location.AddPath(
+ UninterpretedOption::kPositiveIntValueFieldNumber);
+ uninterpreted_option->set_positive_int_value(value);
+ }
+ break;
+ }
- case io::Tokenizer::TYPE_STRING: {
- value_location.AddPath(UninterpretedOption::kStringValueFieldNumber);
- if (is_negative) {
- AddError("Invalid '-' symbol before string.");
- return false;
+ case io::Tokenizer::TYPE_FLOAT: {
+ value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
+ double value;
+ DO(ConsumeNumber(&value, "Expected number."));
+ uninterpreted_option->set_double_value(is_negative ? -value : value);
+ break;
}
- string value;
- DO(ConsumeString(&value, "Expected string."));
- uninterpreted_option->set_string_value(value);
- break;
- }
- case io::Tokenizer::TYPE_SYMBOL:
- if (LookingAt("{")) {
- value_location.AddPath(UninterpretedOption::kAggregateValueFieldNumber);
- DO(ParseUninterpretedBlock(
- uninterpreted_option->mutable_aggregate_value()));
- } else {
- AddError("Expected option value.");
- return false;
+ case io::Tokenizer::TYPE_STRING: {
+ value_location.AddPath(UninterpretedOption::kStringValueFieldNumber);
+ if (is_negative) {
+ AddError("Invalid '-' symbol before string.");
+ return false;
+ }
+ string value;
+ DO(ConsumeString(&value, "Expected string."));
+ uninterpreted_option->set_string_value(value);
+ break;
}
- break;
+
+ case io::Tokenizer::TYPE_SYMBOL:
+ if (LookingAt("{")) {
+ value_location.AddPath(
+ UninterpretedOption::kAggregateValueFieldNumber);
+ DO(ParseUninterpretedBlock(
+ uninterpreted_option->mutable_aggregate_value()));
+ } else {
+ AddError("Expected option value.");
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (style == OPTION_STATEMENT) {
+ DO(ConsumeEndOfDeclaration(";", &location));
}
return true;
}
bool Parser::ParseExtensions(DescriptorProto* message,
- const LocationRecorder& extensions_location) {
+ const LocationRecorder& extensions_location,
+ const FileDescriptorProto* containing_file) {
// Parse the declaration.
DO(Consume("extensions"));
@@ -1008,7 +1326,10 @@ bool Parser::ParseExtensions(DescriptorProto* message,
LocationRecorder end_location(
location, DescriptorProto::ExtensionRange::kEndFieldNumber);
if (TryConsume("max")) {
- end = FieldDescriptor::kMaxNumber;
+ // Set to the sentinel value - 1 since we increment the value below.
+ // The actual value of the end of the range should be set with
+ // AdjustExtensionRangesWithMaxEndNumber.
+ end = kMaxExtensionRangeSentinel - 1;
} else {
DO(ConsumeInteger(&end, "Expected integer."));
}
@@ -1028,7 +1349,7 @@ bool Parser::ParseExtensions(DescriptorProto* message,
range->set_end(end);
} while (TryConsume(","));
- DO(Consume(";"));
+ DO(ConsumeEndOfDeclaration(";", &extensions_location));
return true;
}
@@ -1036,7 +1357,8 @@ bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
RepeatedPtrField<DescriptorProto>* messages,
const LocationRecorder& parent_location,
int location_field_number_for_nested_type,
- const LocationRecorder& extend_location) {
+ const LocationRecorder& extend_location,
+ const FileDescriptorProto* containing_file) {
DO(Consume("extend"));
// Parse the extendee type.
@@ -1046,7 +1368,7 @@ bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
io::Tokenizer::Token extendee_end = input_->previous();
// Parse the block.
- DO(Consume("{"));
+ DO(ConsumeEndOfDeclaration("{", &extend_location));
bool is_first = true;
@@ -1078,12 +1400,70 @@ bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
if (!ParseMessageField(field, messages, parent_location,
location_field_number_for_nested_type,
- location)) {
+ location,
+ containing_file)) {
// This statement failed to parse. Skip it, but keep looping to parse
// other statements.
SkipStatement();
}
- } while(!TryConsume("}"));
+ } while (!TryConsumeEndOfDeclaration("}", NULL));
+
+ return true;
+}
+
+bool Parser::ParseOneof(OneofDescriptorProto* oneof_decl,
+ DescriptorProto* containing_type,
+ int oneof_index,
+ const LocationRecorder& oneof_location,
+ const LocationRecorder& containing_type_location,
+ const FileDescriptorProto* containing_file) {
+ DO(Consume("oneof"));
+
+ {
+ LocationRecorder name_location(oneof_location,
+ OneofDescriptorProto::kNameFieldNumber);
+ DO(ConsumeIdentifier(oneof_decl->mutable_name(), "Expected oneof name."));
+ }
+
+ DO(ConsumeEndOfDeclaration("{", &oneof_location));
+
+ do {
+ if (AtEnd()) {
+ AddError("Reached end of input in oneof definition (missing '}').");
+ return false;
+ }
+
+ // Print a nice error if the user accidentally tries to place a label
+ // on an individual member of a oneof.
+ if (LookingAt("required") ||
+ LookingAt("optional") ||
+ LookingAt("repeated")) {
+ AddError("Fields in oneofs must not have labels (required / optional "
+ "/ repeated).");
+ // We can continue parsing here because we understand what the user
+ // meant. The error report will still make parsing fail overall.
+ input_->Next();
+ }
+
+ LocationRecorder field_location(containing_type_location,
+ DescriptorProto::kFieldFieldNumber,
+ containing_type->field_size());
+
+ FieldDescriptorProto* field = containing_type->add_field();
+ field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+ field->set_oneof_index(oneof_index);
+
+ if (!ParseMessageFieldNoLabel(field,
+ containing_type->mutable_nested_type(),
+ containing_type_location,
+ DescriptorProto::kNestedTypeFieldNumber,
+ field_location,
+ containing_file)) {
+ // This statement failed to parse. Skip it, but keep looping to parse
+ // other statements.
+ SkipStatement();
+ }
+ } while (!TryConsumeEndOfDeclaration("}", NULL));
return true;
}
@@ -1092,7 +1472,8 @@ bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
// Enums
bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type,
- const LocationRecorder& enum_location) {
+ const LocationRecorder& enum_location,
+ const FileDescriptorProto* containing_file) {
DO(Consume("enum"));
{
@@ -1103,21 +1484,22 @@ bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type,
DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name."));
}
- DO(ParseEnumBlock(enum_type, enum_location));
+ DO(ParseEnumBlock(enum_type, enum_location, containing_file));
return true;
}
bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type,
- const LocationRecorder& enum_location) {
- DO(Consume("{"));
+ const LocationRecorder& enum_location,
+ const FileDescriptorProto* containing_file) {
+ DO(ConsumeEndOfDeclaration("{", &enum_location));
- while (!TryConsume("}")) {
+ while (!TryConsumeEndOfDeclaration("}", NULL)) {
if (AtEnd()) {
AddError("Reached end of input in enum definition (missing '}').");
return false;
}
- if (!ParseEnumStatement(enum_type, enum_location)) {
+ if (!ParseEnumStatement(enum_type, enum_location, containing_file)) {
// This statement failed to parse. Skip it, but keep looping to parse
// other statements.
SkipStatement();
@@ -1128,23 +1510,26 @@ bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type,
}
bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type,
- const LocationRecorder& enum_location) {
- if (TryConsume(";")) {
+ const LocationRecorder& enum_location,
+ const FileDescriptorProto* containing_file) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
// empty statement; ignore
return true;
} else if (LookingAt("option")) {
LocationRecorder location(enum_location,
EnumDescriptorProto::kOptionsFieldNumber);
- return ParseOption(enum_type->mutable_options(), location);
+ return ParseOption(enum_type->mutable_options(), location,
+ containing_file, OPTION_STATEMENT);
} else {
LocationRecorder location(enum_location,
EnumDescriptorProto::kValueFieldNumber, enum_type->value_size());
- return ParseEnumConstant(enum_type->add_value(), location);
+ return ParseEnumConstant(enum_type->add_value(), location, containing_file);
}
}
bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value,
- const LocationRecorder& enum_value_location) {
+ const LocationRecorder& enum_value_location,
+ const FileDescriptorProto* containing_file) {
// Parse name.
{
LocationRecorder location(enum_value_location,
@@ -1164,23 +1549,23 @@ bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value,
location.RecordLegacyLocation(
enum_value, DescriptorPool::ErrorCollector::NUMBER);
- bool is_negative = TryConsume("-");
int number;
- DO(ConsumeInteger(&number, "Expected integer."));
- if (is_negative) number *= -1;
+ DO(ConsumeSignedInteger(&number, "Expected integer."));
enum_value->set_number(number);
}
- DO(ParseEnumConstantOptions(enum_value, enum_value_location));
+ DO(ParseEnumConstantOptions(enum_value, enum_value_location,
+ containing_file));
- DO(Consume(";"));
+ DO(ConsumeEndOfDeclaration(";", &enum_value_location));
return true;
}
bool Parser::ParseEnumConstantOptions(
EnumValueDescriptorProto* value,
- const LocationRecorder& enum_value_location) {
+ const LocationRecorder& enum_value_location,
+ const FileDescriptorProto* containing_file) {
if (!LookingAt("[")) return true;
LocationRecorder location(
@@ -1189,7 +1574,8 @@ bool Parser::ParseEnumConstantOptions(
DO(Consume("["));
do {
- DO(ParseOptionAssignment(value->mutable_options(), location));
+ DO(ParseOption(value->mutable_options(), location,
+ containing_file, OPTION_ASSIGNMENT));
} while (TryConsume(","));
DO(Consume("]"));
@@ -1199,8 +1585,10 @@ bool Parser::ParseEnumConstantOptions(
// -------------------------------------------------------------------
// Services
-bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service,
- const LocationRecorder& service_location) {
+bool Parser::ParseServiceDefinition(
+ ServiceDescriptorProto* service,
+ const LocationRecorder& service_location,
+ const FileDescriptorProto* containing_file) {
DO(Consume("service"));
{
@@ -1211,21 +1599,22 @@ bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service,
DO(ConsumeIdentifier(service->mutable_name(), "Expected service name."));
}
- DO(ParseServiceBlock(service, service_location));
+ DO(ParseServiceBlock(service, service_location, containing_file));
return true;
}
bool Parser::ParseServiceBlock(ServiceDescriptorProto* service,
- const LocationRecorder& service_location) {
- DO(Consume("{"));
+ const LocationRecorder& service_location,
+ const FileDescriptorProto* containing_file) {
+ DO(ConsumeEndOfDeclaration("{", &service_location));
- while (!TryConsume("}")) {
+ while (!TryConsumeEndOfDeclaration("}", NULL)) {
if (AtEnd()) {
AddError("Reached end of input in service definition (missing '}').");
return false;
}
- if (!ParseServiceStatement(service, service_location)) {
+ if (!ParseServiceStatement(service, service_location, containing_file)) {
// This statement failed to parse. Skip it, but keep looping to parse
// other statements.
SkipStatement();
@@ -1236,23 +1625,26 @@ bool Parser::ParseServiceBlock(ServiceDescriptorProto* service,
}
bool Parser::ParseServiceStatement(ServiceDescriptorProto* service,
- const LocationRecorder& service_location) {
- if (TryConsume(";")) {
+ const LocationRecorder& service_location,
+ const FileDescriptorProto* containing_file) {
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
// empty statement; ignore
return true;
} else if (LookingAt("option")) {
LocationRecorder location(
service_location, ServiceDescriptorProto::kOptionsFieldNumber);
- return ParseOption(service->mutable_options(), location);
+ return ParseOption(service->mutable_options(), location,
+ containing_file, OPTION_STATEMENT);
} else {
LocationRecorder location(service_location,
ServiceDescriptorProto::kMethodFieldNumber, service->method_size());
- return ParseServiceMethod(service->add_method(), location);
+ return ParseServiceMethod(service->add_method(), location, containing_file);
}
}
bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
- const LocationRecorder& method_location) {
+ const LocationRecorder& method_location,
+ const FileDescriptorProto* containing_file) {
DO(Consume("rpc"));
{
@@ -1266,6 +1658,15 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
// Parse input type.
DO(Consume("("));
{
+ if (LookingAt("stream")) {
+ LocationRecorder location(
+ method_location, MethodDescriptorProto::kClientStreamingFieldNumber);
+ location.RecordLegacyLocation(
+ method, DescriptorPool::ErrorCollector::OTHER);
+ method->set_client_streaming(true);
+ DO(Consume("stream"));
+
+ }
LocationRecorder location(method_location,
MethodDescriptorProto::kInputTypeFieldNumber);
location.RecordLegacyLocation(
@@ -1278,6 +1679,15 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
DO(Consume("returns"));
DO(Consume("("));
{
+ if (LookingAt("stream")) {
+ LocationRecorder location(
+ method_location, MethodDescriptorProto::kServerStreamingFieldNumber);
+ location.RecordLegacyLocation(
+ method, DescriptorPool::ErrorCollector::OTHER);
+ DO(Consume("stream"));
+ method->set_server_streaming(true);
+
+ }
LocationRecorder location(method_location,
MethodDescriptorProto::kOutputTypeFieldNumber);
location.RecordLegacyLocation(
@@ -1286,28 +1696,43 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
}
DO(Consume(")"));
- if (TryConsume("{")) {
+ if (LookingAt("{")) {
// Options!
- while (!TryConsume("}")) {
- if (AtEnd()) {
- AddError("Reached end of input in method options (missing '}').");
- return false;
- }
+ DO(ParseMethodOptions(method_location, containing_file,
+ MethodDescriptorProto::kOptionsFieldNumber,
+ method->mutable_options()));
+ } else {
+ DO(ConsumeEndOfDeclaration(";", &method_location));
+ }
- if (TryConsume(";")) {
- // empty statement; ignore
- } else {
- LocationRecorder location(method_location,
- MethodDescriptorProto::kOptionsFieldNumber);
- if (!ParseOption(method->mutable_options(), location)) {
- // This statement failed to parse. Skip it, but keep looping to
- // parse other statements.
- SkipStatement();
- }
+ return true;
+}
+
+
+bool Parser::ParseMethodOptions(const LocationRecorder& parent_location,
+ const FileDescriptorProto* containing_file,
+ const int optionsFieldNumber,
+ Message* mutable_options) {
+ // Options!
+ ConsumeEndOfDeclaration("{", &parent_location);
+ while (!TryConsumeEndOfDeclaration("}", NULL)) {
+ if (AtEnd()) {
+ AddError("Reached end of input in method options (missing '}').");
+ return false;
+ }
+
+ if (TryConsumeEndOfDeclaration(";", NULL)) {
+ // empty statement; ignore
+ } else {
+ LocationRecorder location(parent_location,
+ optionsFieldNumber);
+ if (!ParseOption(mutable_options, location,
+ containing_file, OPTION_STATEMENT)) {
+ // This statement failed to parse. Skip it, but keep looping to
+ // parse other statements.
+ SkipStatement();
}
}
- } else {
- DO(Consume(";"));
}
return true;
@@ -1315,7 +1740,8 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
// -------------------------------------------------------------------
-bool Parser::ParseLabel(FieldDescriptorProto::Label* label) {
+bool Parser::ParseLabel(FieldDescriptorProto::Label* label,
+ const FileDescriptorProto* containing_file) {
if (TryConsume("optional")) {
*label = FieldDescriptorProto::LABEL_OPTIONAL;
return true;
@@ -1325,13 +1751,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,
@@ -1384,7 +1805,8 @@ bool Parser::ParseUserDefinedType(string* type_name) {
// ===================================================================
bool Parser::ParsePackage(FileDescriptorProto* file,
- const LocationRecorder& root_location) {
+ const LocationRecorder& root_location,
+ const FileDescriptorProto* containing_file) {
if (file->has_package()) {
AddError("Multiple package definitions.");
// Don't append the new package to the old one. Just replace it. Not
@@ -1406,32 +1828,45 @@ bool Parser::ParsePackage(FileDescriptorProto* file,
if (!TryConsume(".")) break;
file->mutable_package()->append(".");
}
+
+ location.EndAt(input_->previous());
+
+ DO(ConsumeEndOfDeclaration(";", &location));
}
- DO(Consume(";"));
return true;
}
-bool Parser::ParseImport(string* import_filename,
+bool Parser::ParseImport(RepeatedPtrField<string>* dependency,
+ RepeatedField<int32>* public_dependency,
+ RepeatedField<int32>* weak_dependency,
const LocationRecorder& root_location,
- int index) {
+ const FileDescriptorProto* containing_file) {
DO(Consume("import"));
+ if (LookingAt("public")) {
+ LocationRecorder location(
+ root_location, FileDescriptorProto::kPublicDependencyFieldNumber,
+ public_dependency->size());
+ DO(Consume("public"));
+ *public_dependency->Add() = dependency->size();
+ } else if (LookingAt("weak")) {
+ LocationRecorder location(
+ root_location, FileDescriptorProto::kWeakDependencyFieldNumber,
+ weak_dependency->size());
+ DO(Consume("weak"));
+ *weak_dependency->Add() = dependency->size();
+ }
{
LocationRecorder location(root_location,
FileDescriptorProto::kDependencyFieldNumber,
- index);
- DO(ConsumeString(import_filename,
+ dependency->size());
+ DO(ConsumeString(dependency->Add(),
"Expected a string naming the file to import."));
- }
- DO(Consume(";"));
- return true;
-}
-bool Parser::ParseOption(Message* options,
- const LocationRecorder& options_location) {
- DO(Consume("option"));
- DO(ParseOptionAssignment(options, options_location));
- DO(Consume(";"));
+ location.EndAt(input_->previous());
+
+ DO(ConsumeEndOfDeclaration(";", &location));
+ }
return true;
}
@@ -1445,7 +1880,7 @@ bool SourceLocationTable::Find(
DescriptorPool::ErrorCollector::ErrorLocation location,
int* line, int* column) const {
const pair<int, int>* result =
- FindOrNull(location_map_, make_pair(descriptor, location));
+ FindOrNull(location_map_, std::make_pair(descriptor, location));
if (result == NULL) {
*line = -1;
*column = 0;
@@ -1461,7 +1896,8 @@ void SourceLocationTable::Add(
const Message* descriptor,
DescriptorPool::ErrorCollector::ErrorLocation location,
int line, int column) {
- location_map_[make_pair(descriptor, location)] = make_pair(line, column);
+ location_map_[std::make_pair(descriptor, location)] =
+ std::make_pair(line, column);
}
void SourceLocationTable::Clear() {
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index 4cc90a29..7cb1678a 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -40,7 +40,6 @@
#include <map>
#include <string>
#include <utility>
-#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/repeated_field.h>
@@ -116,6 +115,8 @@ class LIBPROTOBUF_EXPORT Parser {
}
private:
+ class LocationRecorder;
+
// =================================================================
// Error recovery helpers
@@ -164,6 +165,8 @@ class LIBPROTOBUF_EXPORT Parser {
bool ConsumeIdentifier(string* output, const char* error);
// Consume an integer and store its value in "output".
bool ConsumeInteger(int* output, const char* error);
+ // Consume a signed integer and store its value in "output".
+ bool ConsumeSignedInteger(int* output, const char* error);
// Consume a 64-bit integer and store its value in "output". If the value
// is greater than max_value, an error will be reported.
bool ConsumeInteger64(uint64 max_value, uint64* output, const char* error);
@@ -173,6 +176,23 @@ class LIBPROTOBUF_EXPORT Parser {
// Consume a string literal and store its (unescaped) value in "output".
bool ConsumeString(string* output, const char* error);
+ // Consume a token representing the end of the statement. Comments between
+ // this token and the next will be harvested for documentation. The given
+ // LocationRecorder should refer to the declaration that was just parsed;
+ // it will be populated with these comments.
+ //
+ // TODO(kenton): The LocationRecorder is const because historically locations
+ // have been passed around by const reference, for no particularly good
+ // reason. We should probably go through and change them all to mutable
+ // pointer to make this more intuitive.
+ bool TryConsumeEndOfDeclaration(
+ const char* text, const LocationRecorder* location);
+ bool TryConsumeEndOfDeclarationFinishScope(
+ const char* text, const LocationRecorder* location);
+
+ bool ConsumeEndOfDeclaration(
+ const char* text, const LocationRecorder* location);
+
// -----------------------------------------------------------------
// Error logging helpers
@@ -215,6 +235,9 @@ class LIBPROTOBUF_EXPORT Parser {
// location to the given token instead.
void StartAt(const io::Tokenizer::Token& token);
+ // Start at the same location as some other LocationRecorder.
+ void StartAt(const LocationRecorder& other);
+
// By default the location is considered to end at the previous token at
// the time the LocationRecorder is destroyed. EndAt() sets the end
// location to the given token instead.
@@ -227,7 +250,19 @@ class LIBPROTOBUF_EXPORT Parser {
void RecordLegacyLocation(const Message* descriptor,
DescriptorPool::ErrorCollector::ErrorLocation location);
+ // Attaches leading and trailing comments to the location. The two strings
+ // will be swapped into place, so after this is called *leading and
+ // *trailing will be empty.
+ //
+ // TODO(kenton): See comment on TryConsumeEndOfDeclaration(), above, for
+ // why this is const.
+ void AttachComments(string* leading, string* trailing,
+ vector<string>* detached_comments) const;
+
private:
+ // Indexes of parent and current location in the parent
+ // SourceCodeInfo.location repeated field. For top-level elements,
+ // parent_index_ is -1.
Parser* parser_;
SourceCodeInfo::Location* location_;
@@ -240,7 +275,7 @@ class LIBPROTOBUF_EXPORT Parser {
// Parses the "syntax = \"proto2\";" line at the top of the file. Returns
// false if it failed to parse or if the syntax identifier was not
// recognized.
- bool ParseSyntaxIdentifier();
+ bool ParseSyntaxIdentifier(const LocationRecorder& parent);
// These methods parse various individual bits of code. They return
// false if they completely fail to parse the construct. In this case,
@@ -258,37 +293,47 @@ class LIBPROTOBUF_EXPORT Parser {
// Parse various language high-level language construrcts.
bool ParseMessageDefinition(DescriptorProto* message,
- const LocationRecorder& message_location);
+ const LocationRecorder& message_location,
+ const FileDescriptorProto* containing_file);
bool ParseEnumDefinition(EnumDescriptorProto* enum_type,
- const LocationRecorder& enum_location);
+ const LocationRecorder& enum_location,
+ const FileDescriptorProto* containing_file);
bool ParseServiceDefinition(ServiceDescriptorProto* service,
- const LocationRecorder& service_location);
+ const LocationRecorder& service_location,
+ const FileDescriptorProto* containing_file);
bool ParsePackage(FileDescriptorProto* file,
- const LocationRecorder& root_location);
- bool ParseImport(string* import_filename,
+ const LocationRecorder& root_location,
+ const FileDescriptorProto* containing_file);
+ bool ParseImport(RepeatedPtrField<string>* dependency,
+ RepeatedField<int32>* public_dependency,
+ RepeatedField<int32>* weak_dependency,
const LocationRecorder& root_location,
- int index);
- bool ParseOption(Message* options,
- const LocationRecorder& options_location);
+ const FileDescriptorProto* containing_file);
// These methods parse the contents of a message, enum, or service type and
// add them to the given object. They consume the entire block including
// the beginning and ending brace.
bool ParseMessageBlock(DescriptorProto* message,
- const LocationRecorder& message_location);
+ const LocationRecorder& message_location,
+ const FileDescriptorProto* containing_file);
bool ParseEnumBlock(EnumDescriptorProto* enum_type,
- const LocationRecorder& enum_location);
+ const LocationRecorder& enum_location,
+ const FileDescriptorProto* containing_file);
bool ParseServiceBlock(ServiceDescriptorProto* service,
- const LocationRecorder& service_location);
+ const LocationRecorder& service_location,
+ const FileDescriptorProto* containing_file);
// Parse one statement within a message, enum, or service block, inclunding
// final semicolon.
bool ParseMessageStatement(DescriptorProto* message,
- const LocationRecorder& message_location);
+ const LocationRecorder& message_location,
+ const FileDescriptorProto* containing_file);
bool ParseEnumStatement(EnumDescriptorProto* message,
- const LocationRecorder& enum_location);
+ const LocationRecorder& enum_location,
+ const FileDescriptorProto* containing_file);
bool ParseServiceStatement(ServiceDescriptorProto* message,
- const LocationRecorder& service_location);
+ const LocationRecorder& service_location,
+ const FileDescriptorProto* containing_file);
// Parse a field of a message. If the field is a group, its type will be
// added to "messages".
@@ -302,11 +347,22 @@ class LIBPROTOBUF_EXPORT Parser {
RepeatedPtrField<DescriptorProto>* messages,
const LocationRecorder& parent_location,
int location_field_number_for_nested_type,
- const LocationRecorder& field_location);
+ const LocationRecorder& field_location,
+ const FileDescriptorProto* containing_file);
+
+ // Like ParseMessageField() but expects the label has already been filled in
+ // by the caller.
+ bool ParseMessageFieldNoLabel(FieldDescriptorProto* field,
+ RepeatedPtrField<DescriptorProto>* messages,
+ const LocationRecorder& parent_location,
+ int location_field_number_for_nested_type,
+ const LocationRecorder& field_location,
+ const FileDescriptorProto* containing_file);
// Parse an "extensions" declaration.
bool ParseExtensions(DescriptorProto* message,
- const LocationRecorder& extensions_location);
+ const LocationRecorder& extensions_location,
+ const FileDescriptorProto* containing_file);
// Parse an "extend" declaration. (See also comments for
// ParseMessageField().)
@@ -314,24 +370,46 @@ class LIBPROTOBUF_EXPORT Parser {
RepeatedPtrField<DescriptorProto>* messages,
const LocationRecorder& parent_location,
int location_field_number_for_nested_type,
- const LocationRecorder& extend_location);
+ const LocationRecorder& extend_location,
+ const FileDescriptorProto* containing_file);
+
+ // Parse a "oneof" declaration. The caller is responsible for setting
+ // oneof_decl->label() since it will have had to parse the label before it
+ // knew it was parsing a oneof.
+ bool ParseOneof(OneofDescriptorProto* oneof_decl,
+ DescriptorProto* containing_type,
+ int oneof_index,
+ const LocationRecorder& oneof_location,
+ const LocationRecorder& containing_type_location,
+ const FileDescriptorProto* containing_file);
// Parse a single enum value within an enum block.
bool ParseEnumConstant(EnumValueDescriptorProto* enum_value,
- const LocationRecorder& enum_value_location);
+ const LocationRecorder& enum_value_location,
+ const FileDescriptorProto* containing_file);
// Parse enum constant options, i.e. the list in square brackets at the end
// of the enum constant value definition.
bool ParseEnumConstantOptions(EnumValueDescriptorProto* value,
- const LocationRecorder& enum_value_location);
+ const LocationRecorder& enum_value_location,
+ const FileDescriptorProto* containing_file);
// Parse a single method within a service definition.
bool ParseServiceMethod(MethodDescriptorProto* method,
- const LocationRecorder& method_location);
+ const LocationRecorder& method_location,
+ const FileDescriptorProto* containing_file);
+
+
+ // Parse options of a single method or stream.
+ bool ParseMethodOptions(const LocationRecorder& parent_location,
+ const FileDescriptorProto* containing_file,
+ const int optionsFieldNumber,
+ Message* mutable_options);
// Parse "required", "optional", or "repeated" and fill in "label"
- // with the value.
- bool ParseLabel(FieldDescriptorProto::Label* label);
+ // with the value. Returns true if shuch a label is consumed.
+ bool ParseLabel(FieldDescriptorProto::Label* label,
+ const FileDescriptorProto* containing_file);
// Parse a type name and fill in "type" (if it is a primitive) or
// "type_name" (if it is not) with the type parsed.
@@ -344,25 +422,35 @@ class LIBPROTOBUF_EXPORT Parser {
// Parses field options, i.e. the stuff in square brackets at the end
// of a field definition. Also parses default value.
bool ParseFieldOptions(FieldDescriptorProto* field,
- const LocationRecorder& field_location);
+ const LocationRecorder& field_location,
+ const FileDescriptorProto* containing_file);
// Parse the "default" option. This needs special handling because its
// type is the field's type.
bool ParseDefaultAssignment(FieldDescriptorProto* field,
- const LocationRecorder& field_location);
+ const LocationRecorder& field_location,
+ const FileDescriptorProto* containing_file);
+
+ enum OptionStyle {
+ OPTION_ASSIGNMENT, // just "name = value"
+ OPTION_STATEMENT // "option name = value;"
+ };
// Parse a single option name/value pair, e.g. "ctype = CORD". The name
// identifies a field of the given Message, and the value of that field
// is set to the parsed value.
- bool ParseOptionAssignment(Message* options,
- const LocationRecorder& options_location);
+ bool ParseOption(Message* options,
+ const LocationRecorder& options_location,
+ const FileDescriptorProto* containing_file,
+ OptionStyle style);
// Parses a single part of a multipart option name. A multipart name consists
// of names separated by dots. Each name is either an identifier or a series
// of identifiers separated by dots and enclosed in parentheses. E.g.,
// "foo.(bar.baz).qux".
bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
- const LocationRecorder& part_location);
+ const LocationRecorder& part_location,
+ const FileDescriptorProto* containing_file);
// Parses a string surrounded by balanced braces. Strips off the outer
// braces and stores the enclosed string in *value.
@@ -376,6 +464,28 @@ class LIBPROTOBUF_EXPORT Parser {
// the ending brace.
bool ParseUninterpretedBlock(string* value);
+ struct MapField {
+ // Whether the field is a map field.
+ bool is_map_field;
+ // The types of the key and value if they are primitive types.
+ FieldDescriptorProto::Type key_type;
+ FieldDescriptorProto::Type value_type;
+ // Or the type names string if the types are customized types.
+ string key_type_name;
+ string value_type_name;
+
+ MapField() : is_map_field(false) {}
+ };
+ // Desugar the map syntax to generate a nested map entry message.
+ void GenerateMapEntry(const MapField& map_field, FieldDescriptorProto* field,
+ RepeatedPtrField<DescriptorProto>* messages);
+
+ // Whether fields without label default to optional fields.
+ bool DefaultToOptionalFields() const {
+ return syntax_identifier_ == "proto3";
+ }
+
+
// =================================================================
io::Tokenizer* input_;
@@ -387,6 +497,17 @@ class LIBPROTOBUF_EXPORT Parser {
bool stop_after_syntax_identifier_;
string syntax_identifier_;
+ // Leading doc comments for the next declaration. These are not complete
+ // yet; use ConsumeEndOfDeclaration() to get the complete comments.
+ string upcoming_doc_comments_;
+
+ // Detached comments are not connected to any syntax entities. Elements in
+ // this vector are paragraphs of comments separated by empty lines. The
+ // detached comments will be put into the leading_detached_comments field for
+ // the next element (See SourceCodeInfo.Location in descriptor.proto), when
+ // ConsumeEndOfDeclaration() is called.
+ vector<string> upcoming_detached_comments_;
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser);
};
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 156c0dc3..1684bebe 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,6 +32,10 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <vector>
#include <algorithm>
#include <map>
@@ -44,9 +48,10 @@
#include <google/protobuf/wire_format.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_custom_options.pb.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
-#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
@@ -173,9 +178,9 @@ class ParserTest : public testing::Test {
MockErrorCollector error_collector_;
DescriptorPool pool_;
- scoped_ptr<io::ZeroCopyInputStream> raw_input_;
- scoped_ptr<io::Tokenizer> input_;
- scoped_ptr<Parser> parser_;
+ google::protobuf::scoped_ptr<io::ZeroCopyInputStream> raw_input_;
+ google::protobuf::scoped_ptr<io::Tokenizer> input_;
+ google::protobuf::scoped_ptr<Parser> parser_;
bool require_syntax_identifier_;
};
@@ -211,6 +216,15 @@ TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) {
EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
}
+TEST_F(ParserTest, WarnIfSyntaxIdentifierOmmitted) {
+ SetupParser("message A {}");
+ FileDescriptorProto file;
+ CaptureTestStderr();
+ EXPECT_TRUE(parser_->Parse(input_.get(), &file));
+ EXPECT_TRUE(
+ GetCapturedTestStderr().find("No syntax specified") != string::npos);
+}
+
// ===================================================================
typedef ParserTest ParseMessageTest;
@@ -248,6 +262,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 }"
@@ -263,6 +278,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 }"
@@ -363,35 +379,49 @@ TEST_F(ParseMessageTest, FieldDefaults) {
#define ETC "name:\"foo\" label:LABEL_REQUIRED number:1"
"message_type {"
" name: \"TestMessage\""
- " field { type:TYPE_INT32 default_value:\"1\" "ETC" }"
- " field { type:TYPE_INT32 default_value:\"-2\" "ETC" }"
- " field { type:TYPE_INT64 default_value:\"3\" "ETC" }"
- " field { type:TYPE_INT64 default_value:\"-4\" "ETC" }"
- " field { type:TYPE_UINT32 default_value:\"5\" "ETC" }"
- " field { type:TYPE_UINT64 default_value:\"6\" "ETC" }"
- " field { type:TYPE_FLOAT default_value:\"7.5\" "ETC" }"
- " field { type:TYPE_FLOAT default_value:\"-8.5\" "ETC" }"
- " field { type:TYPE_FLOAT default_value:\"9\" "ETC" }"
- " field { type:TYPE_DOUBLE default_value:\"10.5\" "ETC" }"
- " field { type:TYPE_DOUBLE default_value:\"-11.5\" "ETC" }"
- " field { type:TYPE_DOUBLE default_value:\"12\" "ETC" }"
- " field { type:TYPE_DOUBLE default_value:\"inf\" "ETC" }"
- " field { type:TYPE_DOUBLE default_value:\"-inf\" "ETC" }"
- " field { type:TYPE_DOUBLE default_value:\"nan\" "ETC" }"
- " field { type:TYPE_STRING default_value:\"13\\001\" "ETC" }"
- " field { type:TYPE_STRING default_value:\"abc\" "ETC" }"
- " field { type:TYPE_BYTES default_value:\"14\\\\002\" "ETC" }"
- " field { type:TYPE_BYTES default_value:\"abc\" "ETC" }"
- " field { type:TYPE_BOOL default_value:\"true\" "ETC" }"
- " field { type_name:\"Foo\" default_value:\"FOO\" "ETC" }"
-
- " field { type:TYPE_INT32 default_value:\"2147483647\" "ETC" }"
- " field { type:TYPE_INT32 default_value:\"-2147483648\" "ETC" }"
- " field { type:TYPE_UINT32 default_value:\"4294967295\" "ETC" }"
- " field { type:TYPE_INT64 default_value:\"9223372036854775807\" "ETC" }"
- " field { type:TYPE_INT64 default_value:\"-9223372036854775808\" "ETC" }"
- " field { type:TYPE_UINT64 default_value:\"18446744073709551615\" "ETC" }"
- " field { type:TYPE_DOUBLE default_value:\"43981\" "ETC" }"
+ " field { type:TYPE_INT32 default_value:\"1\" " ETC " }"
+ " field { type:TYPE_INT32 default_value:\"-2\" " ETC " }"
+ " field { type:TYPE_INT64 default_value:\"3\" " ETC " }"
+ " field { type:TYPE_INT64 default_value:\"-4\" " ETC " }"
+ " field { type:TYPE_UINT32 default_value:\"5\" " ETC " }"
+ " field { type:TYPE_UINT64 default_value:\"6\" " ETC " }"
+ " field { type:TYPE_FLOAT default_value:\"7.5\" " ETC " }"
+ " field { type:TYPE_FLOAT default_value:\"-8.5\" " ETC " }"
+ " field { type:TYPE_FLOAT default_value:\"9\" " ETC " }"
+ " field { type:TYPE_DOUBLE default_value:\"10.5\" " ETC " }"
+ " field { type:TYPE_DOUBLE default_value:\"-11.5\" " ETC " }"
+ " field { type:TYPE_DOUBLE default_value:\"12\" " ETC " }"
+ " field { type:TYPE_DOUBLE default_value:\"inf\" " ETC " }"
+ " field { type:TYPE_DOUBLE default_value:\"-inf\" " ETC " }"
+ " field { type:TYPE_DOUBLE default_value:\"nan\" " ETC " }"
+ " field { type:TYPE_STRING default_value:\"13\\001\" " ETC " }"
+ " field { type:TYPE_STRING default_value:\"abc\" " ETC " }"
+ " field { type:TYPE_BYTES default_value:\"14\\\\002\" " ETC " }"
+ " field { type:TYPE_BYTES default_value:\"abc\" " ETC " }"
+ " field { type:TYPE_BOOL default_value:\"true\" " ETC " }"
+ " field { type_name:\"Foo\" default_value:\"FOO\" " ETC " }"
+
+ " field {"
+ " type:TYPE_INT32 default_value:\"2147483647\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_INT32 default_value:\"-2147483648\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_UINT32 default_value:\"4294967295\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_INT64 default_value:\"9223372036854775807\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_INT64 default_value:\"-9223372036854775808\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_UINT64 default_value:\"18446744073709551615\" " ETC
+ " }"
+ " field {"
+ " type:TYPE_DOUBLE default_value:\"43981\" " ETC
+ " }"
"}");
#undef ETC
}
@@ -435,6 +465,117 @@ TEST_F(ParseMessageTest, FieldOptions) {
"}");
}
+TEST_F(ParseMessageTest, Oneof) {
+ ExpectParsesTo(
+ "message TestMessage {\n"
+ " oneof foo {\n"
+ " int32 a = 1;\n"
+ " string b = 2;\n"
+ " TestMessage c = 3;\n"
+ " group D = 4 { optional int32 i = 5; }\n"
+ " }\n"
+ "}\n",
+
+ "message_type {"
+ " name: \"TestMessage\""
+ " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
+ " oneof_index:0 }"
+ " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
+ " oneof_index:0 }"
+ " field { name:\"c\" label:LABEL_OPTIONAL type_name:\"TestMessage\" "
+ " number:3 oneof_index:0 }"
+ " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_GROUP "
+ " type_name:\"D\" number:4 oneof_index:0 }"
+ " oneof_decl {"
+ " name: \"foo\""
+ " }"
+ " nested_type {"
+ " name: \"D\""
+ " field { name:\"i\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 }"
+ " }"
+ "}");
+}
+
+TEST_F(ParseMessageTest, MultipleOneofs) {
+ ExpectParsesTo(
+ "message TestMessage {\n"
+ " oneof foo {\n"
+ " int32 a = 1;\n"
+ " string b = 2;\n"
+ " }\n"
+ " oneof bar {\n"
+ " int32 c = 3;\n"
+ " string d = 4;\n"
+ " }\n"
+ "}\n",
+
+ "message_type {"
+ " name: \"TestMessage\""
+ " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
+ " oneof_index:0 }"
+ " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
+ " oneof_index:0 }"
+ " field { name:\"c\" label:LABEL_OPTIONAL type:TYPE_INT32 number:3 "
+ " oneof_index:1 }"
+ " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_STRING number:4 "
+ " oneof_index:1 }"
+ " oneof_decl {"
+ " name: \"foo\""
+ " }"
+ " oneof_decl {"
+ " name: \"bar\""
+ " }"
+ "}");
+}
+
+TEST_F(ParseMessageTest, Maps) {
+ ExpectParsesTo(
+ "message TestMessage {\n"
+ " map<int32, string> primitive_type_map = 1;\n"
+ " map<KeyType, ValueType> composite_type_map = 2;\n"
+ "}\n",
+
+ "message_type {"
+ " name: \"TestMessage\""
+ " nested_type {"
+ " name: \"PrimitiveTypeMapEntry\""
+ " field { "
+ " name: \"key\" number: 1 label:LABEL_OPTIONAL"
+ " type:TYPE_INT32"
+ " }"
+ " field { "
+ " name: \"value\" number: 2 label:LABEL_OPTIONAL"
+ " type:TYPE_STRING"
+ " }"
+ " options { map_entry: true }"
+ " }"
+ " nested_type {"
+ " name: \"CompositeTypeMapEntry\""
+ " field { "
+ " name: \"key\" number: 1 label:LABEL_OPTIONAL"
+ " type_name: \"KeyType\""
+ " }"
+ " field { "
+ " name: \"value\" number: 2 label:LABEL_OPTIONAL"
+ " type_name: \"ValueType\""
+ " }"
+ " options { map_entry: true }"
+ " }"
+ " field {"
+ " name: \"primitive_type_map\""
+ " label: LABEL_REPEATED"
+ " type_name: \"PrimitiveTypeMapEntry\""
+ " number: 1"
+ " }"
+ " field {"
+ " name: \"composite_type_map\""
+ " label: LABEL_REPEATED"
+ " type_name: \"CompositeTypeMapEntry\""
+ " number: 2"
+ " }"
+ "}");
+}
+
TEST_F(ParseMessageTest, Group) {
ExpectParsesTo(
"message TestMessage {\n"
@@ -509,6 +650,31 @@ TEST_F(ParseMessageTest, CompoundExtensionRange) {
"}");
}
+TEST_F(ParseMessageTest, LargerMaxForMessageSetWireFormatMessages) {
+ // Messages using the message_set_wire_format option can accept larger
+ // extension numbers, as the numbers are not encoded as int32 field values
+ // rather than tags.
+ ExpectParsesTo(
+ "message TestMessage {\n"
+ " extensions 4 to max;\n"
+ " option message_set_wire_format = true;\n"
+ "}\n",
+
+ "message_type {"
+ " name: \"TestMessage\""
+ " extension_range { start:4 end: 0x7fffffff }"
+ " options {\n"
+ " uninterpreted_option { \n"
+ " name {\n"
+ " name_part: \"message_set_wire_format\"\n"
+ " is_extension: false\n"
+ " }\n"
+ " identifier_value: \"true\"\n"
+ " }\n"
+ " }\n"
+ "}");
+}
+
TEST_F(ParseMessageTest, Extensions) {
ExpectParsesTo(
"extend Extendee1 { optional int32 foo = 12; }\n"
@@ -549,6 +715,21 @@ 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 } }");
+}
+
// ===================================================================
typedef ParserTest ParseEnumTest;
@@ -571,6 +752,10 @@ TEST_F(ParseEnumTest, Values) {
" FOO = 13;\n"
" BAR = -10;\n"
" BAZ = 500;\n"
+ " HEX_MAX = 0x7FFFFFFF;\n"
+ " HEX_MIN = -0x80000000;\n"
+ " INT_MAX = 2147483647;\n"
+ " INT_MIN = -2147483648;\n"
"}\n",
"enum_type {"
@@ -578,6 +763,10 @@ TEST_F(ParseEnumTest, Values) {
" value { name:\"FOO\" number:13 }"
" value { name:\"BAR\" number:-10 }"
" value { name:\"BAZ\" number:500 }"
+ " value { name:\"HEX_MAX\" number:2147483647 }"
+ " value { name:\"HEX_MIN\" number:-2147483648 }"
+ " value { name:\"INT_MAX\" number:2147483647 }"
+ " value { name:\"INT_MIN\" number:-2147483648 }"
"}");
}
@@ -631,7 +820,7 @@ TEST_F(ParseServiceTest, SimpleService) {
"}");
}
-TEST_F(ParseServiceTest, Methods) {
+TEST_F(ParseServiceTest, MethodsAndStreams) {
ExpectParsesTo(
"service TestService {\n"
" rpc Foo(In1) returns (Out1);\n"
@@ -647,6 +836,8 @@ TEST_F(ParseServiceTest, Methods) {
"}");
}
+
+
// ===================================================================
// imports and packages
@@ -668,6 +859,20 @@ TEST_F(ParseMiscTest, ParseMultipleImports) {
"dependency: \"baz.proto\"");
}
+TEST_F(ParseMiscTest, ParsePublicImports) {
+ ExpectParsesTo(
+ "import \"foo.proto\";\n"
+ "import public \"bar.proto\";\n"
+ "import \"baz.proto\";\n"
+ "import public \"qux.proto\";\n",
+ "dependency: \"foo.proto\""
+ "dependency: \"bar.proto\""
+ "dependency: \"baz.proto\""
+ "dependency: \"qux.proto\""
+ "public_dependency: 1 "
+ "public_dependency: 3 ");
+}
+
TEST_F(ParseMiscTest, ParsePackage) {
ExpectParsesTo(
"package foo.bar.baz;\n",
@@ -713,9 +918,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());
}
@@ -723,7 +928,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());
}
@@ -822,7 +1027,7 @@ TEST_F(ParseErrorTest, DefaultValueTypeMismatch) {
"message TestMessage {\n"
" optional uint32 foo = 1 [default=true];\n"
"}\n",
- "1:35: Expected integer.\n");
+ "1:35: Expected integer for field default value.\n");
}
TEST_F(ParseErrorTest, DefaultValueNotBoolean) {
@@ -838,7 +1043,7 @@ TEST_F(ParseErrorTest, DefaultValueNotString) {
"message TestMessage {\n"
" optional string foo = 1 [default=1];\n"
"}\n",
- "1:35: Expected string.\n");
+ "1:35: Expected string for field default value.\n");
}
TEST_F(ParseErrorTest, DefaultValueUnsignedNegative) {
@@ -867,12 +1072,26 @@ TEST_F(ParseErrorTest, DefaultValueTooLarge) {
"6:36: Integer out of range.\n");
}
+TEST_F(ParseErrorTest, EnumValueOutOfRange) {
+ ExpectHasErrors(
+ "enum TestEnum {\n"
+ " HEX_TOO_BIG = 0x80000000;\n"
+ " HEX_TOO_SMALL = -0x80000001;\n"
+ " INT_TOO_BIG = 2147483648;\n"
+ " INT_TOO_SMALL = -2147483649;\n"
+ "}\n",
+ "1:19: Integer out of range.\n"
+ "2:19: Integer out of range.\n"
+ "3:19: Integer out of range.\n"
+ "4:19: Integer out of range.\n");
+}
+
TEST_F(ParseErrorTest, DefaultValueMissing) {
ExpectHasErrors(
"message TestMessage {\n"
" optional uint32 foo = 1 [default=];\n"
"}\n",
- "1:35: Expected integer.\n");
+ "1:35: Expected integer for field default value.\n");
}
TEST_F(ParseErrorTest, DefaultValueForGroup) {
@@ -891,6 +1110,76 @@ TEST_F(ParseErrorTest, DuplicateDefaultValue) {
"1:37: Already set option \"default\".\n");
}
+TEST_F(ParseErrorTest, MissingOneofName) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " oneof {\n"
+ " int32 bar = 1;\n"
+ " }\n"
+ "}\n",
+ "1:8: Expected oneof name.\n");
+}
+
+TEST_F(ParseErrorTest, LabelInOneof) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " oneof foo {\n"
+ " optional int32 bar = 1;\n"
+ " }\n"
+ "}\n",
+ "2:4: Fields in oneofs must not have labels (required / optional "
+ "/ repeated).\n");
+}
+
+TEST_F(ParseErrorTest, MapInOneof) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " oneof foo {\n"
+ " map<int32, int32> foo_map = 1;\n"
+ " map message_field = 2;\n" // a normal message field is OK
+ " }\n"
+ "}\n",
+ "2:7: Map fields are not allowed in oneofs.\n");
+}
+
+TEST_F(ParseErrorTest, LabelForMap) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " optional map<int32, int32> int_map = 1;\n"
+ " required map<int32, int32> int_map2 = 2;\n"
+ " repeated map<int32, int32> int_map3 = 3;\n"
+ " optional map map_message = 4;\n" // a normal message field is OK
+ "}\n",
+ "1:14: Field labels (required/optional/repeated) are not allowed on map "
+ "fields.\n"
+ "2:14: Field labels (required/optional/repeated) are not allowed on map "
+ "fields.\n"
+ "3:14: Field labels (required/optional/repeated) are not allowed on map "
+ "fields.\n");
+}
+
+TEST_F(ParseErrorTest, MalformedMaps) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " map map_message = 1;\n" // a normal message field lacking label
+ " map<string> str_map = 2;\n"
+ " map<string,> str_map2 = 3;\n"
+ " map<,string> str_map3 = 4;\n"
+ " map<> empty_map = 5;\n"
+ " map<string,string str_map6 = 6;\n"
+ "}"
+ "extend SomeMessage {\n"
+ " map<int32, int32> int_map = 1;\n"
+ "}",
+ "1:6: Expected \"required\", \"optional\", or \"repeated\".\n"
+ "2:12: Expected \",\".\n"
+ "3:13: Expected type name.\n"
+ "4:6: Expected type name.\n"
+ "5:6: Expected type name.\n"
+ "6:20: Expected \">\".\n"
+ "8:5: Map fields are not allowed to be extensions.\n");
+}
+
TEST_F(ParseErrorTest, GroupNotCapitalized) {
ExpectHasErrors(
"message TestMessage {\n"
@@ -976,6 +1265,7 @@ TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) {
"1:26: Expected message type.\n");
}
+
TEST_F(ParseErrorTest, EofInMethodOptions) {
ExpectHasErrors(
"service TestService {\n"
@@ -984,6 +1274,7 @@ TEST_F(ParseErrorTest, EofInMethodOptions) {
"1:29: Reached end of input in service definition (missing '}').\n");
}
+
TEST_F(ParseErrorTest, PrimitiveMethodInput) {
ExpectHasErrors(
"service TestService {\n"
@@ -992,6 +1283,7 @@ TEST_F(ParseErrorTest, PrimitiveMethodInput) {
"1:10: Expected message type.\n");
}
+
TEST_F(ParseErrorTest, MethodOptionTypeError) {
// This used to cause an infinite loop.
ExpectHasErrors(
@@ -1002,6 +1294,7 @@ TEST_F(ParseErrorTest, MethodOptionTypeError) {
"2:45: Expected \"=\".\n");
}
+
// -------------------------------------------------------------------
// Import and package errors
@@ -1157,6 +1450,7 @@ TEST_F(ParserValidationErrorTest, MethodNameError) {
"3:6: \"Bar\" is already defined in \"Foo\".\n");
}
+
TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
ExpectHasValidationErrors(
"message Baz {}\n"
@@ -1166,6 +1460,7 @@ TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
"2:10: \"Qux\" is not defined.\n");
}
+
TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
ExpectHasValidationErrors(
"message Baz {}\n"
@@ -1175,17 +1470,94 @@ TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
"2:23: \"Qux\" is not defined.\n");
}
+
+TEST_F(ParserValidationErrorTest, ResovledUndefinedError) {
+ // Create another file which defines symbol ".base.bar".
+ FileDescriptorProto other_file;
+ other_file.set_name("base.proto");
+ other_file.set_package("base");
+ other_file.add_message_type()->set_name("bar");
+ EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
+
+ // Define "foo.base" and try "base.bar".
+ // "base.bar" is resolved to "foo.base.bar" which is not defined.
+ ExpectHasValidationErrors(
+ "package foo.base;\n"
+ "import \"base.proto\";\n"
+ "message qux {\n"
+ " optional base.bar baz = 1;\n"
+ " optional .base.bar quz = 2;\n"
+ "}\n",
+ "3:11: \"base.bar\" is resolved to \"foo.base.bar\","
+ " which is not defined. The innermost scope is searched first "
+ "in name resolution. Consider using a leading '.'(i.e., \".base.bar\")"
+ " to start from the outermost scope.\n");
+}
+
+TEST_F(ParserValidationErrorTest, ResovledUndefinedOptionError) {
+ // Build descriptor message in test pool
+ FileDescriptorProto descriptor_proto;
+ DescriptorProto::descriptor()->file()->CopyTo(&descriptor_proto);
+ ASSERT_TRUE(pool_.BuildFile(descriptor_proto) != NULL);
+
+ // base2.proto:
+ // package baz
+ // import google/protobuf/descriptor.proto
+ // message Bar { optional int32 foo = 1; }
+ // extend FileOptions { optional Bar bar = 7672757; }
+ FileDescriptorProto other_file;
+ other_file.set_name("base2.proto");
+ other_file.set_package("baz");
+ other_file.add_dependency();
+ other_file.set_dependency(0, descriptor_proto.name());
+
+ DescriptorProto* message(other_file.add_message_type());
+ message->set_name("Bar");
+ FieldDescriptorProto* field(message->add_field());
+ field->set_name("foo");
+ field->set_number(1);
+ field->set_label(FieldDescriptorProto_Label_LABEL_OPTIONAL);
+ field->set_type(FieldDescriptorProto_Type_TYPE_INT32);
+
+ FieldDescriptorProto* extension(other_file.add_extension());
+ extension->set_name("bar");
+ extension->set_number(7672757);
+ extension->set_label(FieldDescriptorProto_Label_LABEL_OPTIONAL);
+ extension->set_type(FieldDescriptorProto_Type_TYPE_MESSAGE);
+ extension->set_type_name("Bar");
+ extension->set_extendee("google.protobuf.FileOptions");
+
+ EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
+
+ // qux.proto:
+ // package qux.baz
+ // option (baz.bar).foo = 1;
+ //
+ // Although "baz.bar" is already defined, the lookup code will try
+ // "qux.baz.bar", since it's the match from the innermost scope,
+ // which will cause a symbol not defined error.
+ ExpectHasValidationErrors(
+ "package qux.baz;\n"
+ "import \"base2.proto\";\n"
+ "option (baz.bar).foo = 1;\n",
+ "2:7: Option \"(baz.bar)\" is resolved to \"(qux.baz.bar)\","
+ " which is not defined. The innermost scope is searched first "
+ "in name resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\")"
+ " to start from the outermost scope.\n");
+}
+
// ===================================================================
// Test that the output from FileDescriptor::DebugString() (and all other
// descriptor types) is parseable, and results in the same Descriptor
-// definitions again afoter parsing (not, however, that the order of messages
+// 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:
- bool operator()(const DescriptorProto* left, const DescriptorProto* right) {
+ bool operator()(const DescriptorProto* left,
+ const DescriptorProto* right) const {
return left->name() < right->name();
}
};
@@ -1199,7 +1571,7 @@ void SortMessages(DescriptorProto *descriptor_proto) {
}
DescriptorProto **data =
descriptor_proto->mutable_nested_type()->mutable_data();
- sort(data, data + size, CompareDescriptorNames());
+ std::sort(data, data + size, CompareDescriptorNames());
}
// Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
@@ -1211,10 +1583,31 @@ void SortMessages(FileDescriptorProto *file_descriptor_proto) {
}
DescriptorProto **data =
file_descriptor_proto->mutable_message_type()->mutable_data();
- sort(data, data + size, CompareDescriptorNames());
+ std::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;
@@ -1229,13 +1622,19 @@ TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) {
FileDescriptorProto parsed;
parser_->Parse(input_.get(), &parsed);
EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
- ASSERT_EQ("", error_collector_.text_);
+ ASSERT_EQ("", error_collector_.text_)
+ << "Failed to parse:\n" << debug_string;
// We now have a FileDescriptorProto, but to compare with the expected we
// need to link to a FileDecriptor, then output back to a proto. We'll
// also need to give it the same name as the original.
parsed.set_name("google/protobuf/unittest.proto");
// We need the imported dependency before we can build our parsed proto
+ const FileDescriptor* public_import =
+ protobuf_unittest_import::PublicImportMessage::descriptor()->file();
+ FileDescriptorProto public_import_proto;
+ public_import->CopyTo(&public_import_proto);
+ ASSERT_TRUE(pool_.BuildFile(public_import_proto) != NULL);
const FileDescriptor* import =
protobuf_unittest_import::ImportMessage::descriptor()->file();
FileDescriptorProto import_proto;
@@ -1243,6 +1642,8 @@ TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) {
ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
const FileDescriptor* actual = pool_.BuildFile(parsed);
parsed.Clear();
+ ASSERT_TRUE(actual != NULL)
+ << "Failed to validate:\n" << debug_string;
actual->CopyTo(&parsed);
ASSERT_TRUE(actual != NULL);
@@ -1258,6 +1659,184 @@ TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) {
EXPECT_EQ(expected.DebugString(), parsed.DebugString());
}
+TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
+ const FileDescriptor* original_file =
+ protobuf_unittest::AggregateMessage::descriptor()->file();
+ FileDescriptorProto expected;
+ original_file->CopyTo(&expected);
+
+ string debug_string = original_file->DebugString();
+
+ // Parse the debug string
+ SetupParser(debug_string.c_str());
+ FileDescriptorProto parsed;
+ parser_->Parse(input_.get(), &parsed);
+ EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+ ASSERT_EQ("", error_collector_.text_);
+
+ // We now have a FileDescriptorProto, but to compare with the expected we
+ // need to link to a FileDecriptor, then output back to a proto. We'll
+ // also need to give it the same name as the original.
+ parsed.set_name(original_file->name());
+
+ // unittest_custom_options.proto depends on descriptor.proto.
+ const FileDescriptor* import = FileDescriptorProto::descriptor()->file();
+ FileDescriptorProto import_proto;
+ import->CopyTo(&import_proto);
+ ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
+ const FileDescriptor* actual = pool_.BuildFile(parsed);
+ ASSERT_TRUE(actual != NULL);
+ parsed.Clear();
+ actual->CopyTo(&parsed);
+
+ // The messages might be in different orders, making them hard to compare.
+ // So, sort the messages in the descriptor protos (including nested messages,
+ // recursively).
+ SortMessages(&expected);
+ SortMessages(&parsed);
+
+ 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(
+ "// Detached comment before syntax.\n"
+ "\n"
+ "// Syntax comment.\n"
+ "syntax = \"proto2\";\n"
+ "\n"
+ "// Detached comment before package.\n"
+ "\n"
+ "// Package comment.\n"
+ "package comment_test;\n"
+ "\n"
+ "// Detached comment before TestMessage1.\n"
+ "\n"
+ "// Message comment.\n"
+ "message TestMessage1 {\n"
+ "\n"
+ " // Detached comment before foo.\n"
+ "\n"
+ " // Field comment.\n"
+ " optional int32 foo = 1;\n"
+ "\n"
+ " // Detached comment before NestedMessage.\n"
+ "\n"
+ " // Nested-message comment.\n"
+ " message NestedMessage {\n"
+ " optional int32 bar = 1;\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "// Detached comment before MyEnumType.\n"
+ "\n"
+ "// Enum comment.\n"
+ "enum MyEnumType {\n"
+ "\n"
+ " // Detached comment before ASDF.\n"
+ "\n"
+ " // Enum-value comment.\n"
+ " ASDF = 1;\n"
+ "}\n"
+ "\n"
+ "// Detached comment before MyService.\n"
+ "\n"
+ "// Service comment.\n"
+ "service MyService {\n"
+ "\n"
+ " // Detached comment before MyRPCCall.\n"
+ "\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().
+ // We don't test the exact comment placement or formatting, because we do not
+ // want to be too fragile here.
+ const char* expected_comments[] = {
+ "Detached comment before syntax.",
+ "Syntax comment.",
+ "Detached comment before package.",
+ "Package comment.",
+ "Detached comment before TestMessage1.",
+ "Message comment.",
+ "Detached comment before foo.",
+ "Field comment",
+ "Detached comment before NestedMessage.",
+ "Nested-message comment",
+ "Detached comment before MyEnumType.",
+ "Enum comment",
+ "Detached comment before ASDF.",
+ "Enum-value comment",
+ "Detached comment before MyService.",
+ "Service comment",
+ "Detached comment before MyRPCCall.",
+ "RPC comment",
+ };
+
+ for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
+ string::size_type found_pos = debug_string.find(expected_comments[i]);
+ EXPECT_TRUE(found_pos != string::npos)
+ << "\"" << expected_comments[i] << "\" not found.";
+ }
+}
+
+TEST_F(ParseDescriptorDebugTest, TestMaps) {
+ SetupParser(
+ "syntax = \"proto3\"; "
+ "message Foo { "
+ " message Bar { } "
+ " map<int32, Bar> enum_message_map = 1; "
+ " map<string, float> primitive_map = 2; "
+ "} ");
+ FileDescriptorProto original;
+ EXPECT_TRUE(parser_->Parse(input_.get(), &original));
+ original.set_name("foo.proto");
+ const FileDescriptor* file = pool_.BuildFile(original);
+ ASSERT_TRUE(file != NULL);
+
+ // Make sure the debug string uses map syntax and does not have the auto
+ // generated entry.
+ string debug_string = file->DebugString();
+ EXPECT_TRUE(debug_string.find("map<") != string::npos);
+ EXPECT_TRUE(debug_string.find("option map_entry") == string::npos);
+ EXPECT_TRUE(debug_string.find("MapEntry") == string::npos);
+
+ // Make sure the descriptor debug string is parsable.
+ FileDescriptorProto parsed;
+ SetupParser(debug_string.c_str());
+ parsed.set_name("foo.proto");
+ ASSERT_TRUE(parser_->Parse(input_.get(), &parsed));
+
+ original.clear_source_code_info();
+ parsed.clear_source_code_info();
+ StripFieldTypeName(&original);
+ StripFieldTypeName(&parsed);
+ EXPECT_EQ(original.DebugString(), parsed.DebugString());
+}
+
// ===================================================================
// SourceCodeInfo tests.
@@ -1353,67 +1932,6 @@ bool FollowPath(const Message& root,
}
}
-// Split some text on line breaks. The line breaks are retained in the output,
-// so each line (except the last) ends with a '\n', and the lines can be
-// concatenated to produce the original text.
-//
-// I couldn't find the proper string utility function for this. Our
-// split-on-delimiter functions don't include the delimiter in the output.
-void SplitLines(const string& text, vector<string>* lines) {
- string::size_type pos = 0;
-
- while (pos != string::npos) {
- string::size_type last_pos = pos;
- pos = text.find_first_of('\n', pos);
- if (pos != string::npos) ++pos;
- lines->push_back(text.substr(last_pos, pos - last_pos));
- }
-}
-
-// Look for the given tags in the given text and construct a span (as defined
-// by SourceCodeInfo.Location.span) from them. E.g. for text like:
-// /*a*/message /*b*/Foo/*c*/ {}/*d*/
-// There are four tags: "a", "b", "c", and "d". The constructed span starts
-// immediately after the start tag's trailing '/' and ends immediately before
-// the end tags leading '/'.
-void MakeExpectedSpan(const vector<string>& lines,
- const string& start_tag, const string& end_tag,
- RepeatedField<int>* output) {
- string start_comment = "/*" + start_tag + "*/";
- string end_comment = "/*" + end_tag + "*/";
-
- int start_line = -1;
- int start_column = -1;
- for (int i = 0; i < lines.size(); i++) {
- string::size_type pos = lines[i].find(start_comment);
- if (pos != string::npos) {
- start_line = i;
- start_column = pos + start_comment.size();
- break;
- }
- }
- ASSERT_NE(start_line, -1)
- << "Tag \"" << start_comment << "\" not found in text.";
-
- int end_line = -1;
- int end_column = -1;
- for (int i = start_line; i < lines.size(); i++) {
- string::size_type pos = lines[i].find(end_comment);
- if (pos != string::npos) {
- end_line = i;
- end_column = pos;
- break;
- }
- }
- ASSERT_NE(end_line, -1)
- << "Tag \"" << end_comment << "\" not found in text.";
-
- output->Add(start_line);
- output->Add(start_column);
- if (end_line != start_line) output->Add(end_line);
- output->Add(end_column);
-}
-
// Check if two spans are equal.
bool CompareSpans(const RepeatedField<int>& span1,
const RepeatedField<int>& span2) {
@@ -1434,8 +1952,8 @@ class SourceInfoTest : public ParserTest {
// Parse the given text as a .proto file and populate the spans_ map with
// all the source location spans in its SourceCodeInfo table.
bool Parse(const char* text) {
- SetupParser(text);
- SplitLines(text, &lines_);
+ ExtractMarkers(text);
+ SetupParser(text_without_markers_.c_str());
if (!parser_->Parse(input_.get(), &file_)) {
return false;
}
@@ -1451,8 +1969,8 @@ class SourceInfoTest : public ParserTest {
return false;
}
- spans_.insert(make_pair(SpanKey(*descriptor_proto, field, index),
- &location));
+ spans_.insert(
+ std::make_pair(SpanKey(*descriptor_proto, field, index), &location));
}
return true;
@@ -1470,19 +1988,41 @@ class SourceInfoTest : public ParserTest {
// part of the FileDescriptorProto. (If unclear, look at the actual tests;
// it should quickly become obvious.)
- bool HasSpan(const char* start_tag, const char* end_tag,
+ bool HasSpan(char start_marker, char end_marker,
const Message& descriptor_proto) {
- return HasSpan(start_tag, end_tag, descriptor_proto, NULL, -1);
+ return HasSpanWithComment(
+ start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL, NULL);
}
- bool HasSpan(const char* start_tag, const char* end_tag,
+ bool HasSpanWithComment(char start_marker, char end_marker,
+ const Message& descriptor_proto,
+ const char* expected_leading_comments,
+ const char* expected_trailing_comments,
+ const char* expected_leading_detached_comments) {
+ return HasSpanWithComment(
+ start_marker, end_marker, descriptor_proto, NULL, -1,
+ expected_leading_comments, expected_trailing_comments,
+ expected_leading_detached_comments);
+ }
+
+ bool HasSpan(char start_marker, char end_marker,
const Message& descriptor_proto, const string& field_name) {
- return HasSpan(start_tag, end_tag, descriptor_proto, field_name, -1);
+ return HasSpan(start_marker, end_marker, descriptor_proto, field_name, -1);
}
- bool HasSpan(const char* start_tag, const char* end_tag,
+ bool HasSpan(char start_marker, char end_marker,
const Message& descriptor_proto, const string& field_name,
int index) {
+ return HasSpan(start_marker, end_marker, descriptor_proto,
+ field_name, index, NULL, NULL, NULL);
+ }
+
+ bool HasSpan(char start_marker, char end_marker,
+ const Message& descriptor_proto,
+ const string& field_name, int index,
+ const char* expected_leading_comments,
+ const char* expected_trailing_comments,
+ const char* expected_leading_detached_comments) {
const FieldDescriptor* field =
descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
if (field == NULL) {
@@ -1491,29 +2031,36 @@ class SourceInfoTest : public ParserTest {
return false;
}
- return HasSpan(start_tag, end_tag, descriptor_proto, field, index);
+ return HasSpanWithComment(
+ start_marker, end_marker, descriptor_proto, field, index,
+ expected_leading_comments, expected_trailing_comments,
+ expected_leading_detached_comments);
}
bool HasSpan(const Message& descriptor_proto) {
- return HasSpan(NULL, NULL, descriptor_proto, NULL, -1);
+ return HasSpanWithComment(
+ '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL, NULL);
}
bool HasSpan(const Message& descriptor_proto, const string& field_name) {
- return HasSpan(NULL, NULL, descriptor_proto, field_name, -1);
+ return HasSpan('\0', '\0', descriptor_proto, field_name, -1);
}
bool HasSpan(const Message& descriptor_proto, const string& field_name,
int index) {
- return HasSpan(NULL, NULL, descriptor_proto, field_name, index);
+ return HasSpan('\0', '\0', descriptor_proto, field_name, index);
}
- bool HasSpan(const char* start_tag, const char* end_tag,
- const Message& descriptor_proto, const FieldDescriptor* field,
- int index) {
+ bool HasSpanWithComment(
+ char start_marker, char end_marker, const Message& descriptor_proto,
+ const FieldDescriptor* field, int index,
+ const char* expected_leading_comments,
+ const char* expected_trailing_comments,
+ const char* expected_leading_detached_comments) {
pair<SpanMap::iterator, SpanMap::iterator> range =
spans_.equal_range(SpanKey(descriptor_proto, field, index));
- if (start_tag == NULL) {
+ if (start_marker == '\0') {
if (range.first == range.second) {
return false;
} else {
@@ -1521,11 +2068,41 @@ class SourceInfoTest : public ParserTest {
return true;
}
} else {
+ pair<int, int> start_pos = FindOrDie(markers_, start_marker);
+ pair<int, int> end_pos = FindOrDie(markers_, end_marker);
+
RepeatedField<int> expected_span;
- MakeExpectedSpan(lines_, start_tag, end_tag, &expected_span);
+ expected_span.Add(start_pos.first);
+ expected_span.Add(start_pos.second);
+ if (end_pos.first != start_pos.first) {
+ expected_span.Add(end_pos.first);
+ }
+ expected_span.Add(end_pos.second);
for (SpanMap::iterator iter = range.first; iter != range.second; ++iter) {
if (CompareSpans(expected_span, iter->second->span())) {
+ if (expected_leading_comments == NULL) {
+ EXPECT_FALSE(iter->second->has_leading_comments());
+ } else {
+ EXPECT_TRUE(iter->second->has_leading_comments());
+ EXPECT_EQ(expected_leading_comments,
+ iter->second->leading_comments());
+ }
+ if (expected_trailing_comments == NULL) {
+ EXPECT_FALSE(iter->second->has_trailing_comments());
+ } else {
+ EXPECT_TRUE(iter->second->has_trailing_comments());
+ EXPECT_EQ(expected_trailing_comments,
+ iter->second->trailing_comments());
+ }
+ if (expected_leading_detached_comments == NULL) {
+ EXPECT_EQ(0, iter->second->leading_detached_comments_size());
+ } else {
+ EXPECT_EQ(
+ expected_leading_detached_comments,
+ Join(iter->second->leading_detached_comments(), "\n"));
+ }
+
spans_.erase(iter);
return true;
}
@@ -1542,10 +2119,11 @@ class SourceInfoTest : public ParserTest {
int index;
inline SpanKey() {}
- inline SpanKey(const Message& descriptor_proto,
- const FieldDescriptor* field,
- int index)
- : descriptor_proto(&descriptor_proto), field(field), index(index) {}
+ inline SpanKey(const Message& descriptor_proto_param,
+ const FieldDescriptor* field_param,
+ int index_param)
+ : descriptor_proto(&descriptor_proto_param), field(field_param),
+ index(index_param) {}
inline bool operator<(const SpanKey& other) const {
if (descriptor_proto < other.descriptor_proto) return true;
@@ -1558,32 +2136,64 @@ class SourceInfoTest : public ParserTest {
typedef multimap<SpanKey, const SourceCodeInfo::Location*> SpanMap;
SpanMap spans_;
- vector<string> lines_;
+ map<char, pair<int, int> > markers_;
+ string text_without_markers_;
+
+ void ExtractMarkers(const char* text) {
+ markers_.clear();
+ text_without_markers_.clear();
+ int line = 0;
+ int column = 0;
+ while (*text != '\0') {
+ if (*text == '$') {
+ ++text;
+ GOOGLE_CHECK_NE('\0', *text);
+ if (*text == '$') {
+ text_without_markers_ += '$';
+ ++column;
+ } else {
+ markers_[*text] = std::make_pair(line, column);
+ ++text;
+ GOOGLE_CHECK_EQ('$', *text);
+ }
+ } else if (*text == '\n') {
+ ++line;
+ column = 0;
+ text_without_markers_ += *text;
+ } else {
+ text_without_markers_ += *text;
+ ++column;
+ }
+ ++text;
+ }
+ }
};
TEST_F(SourceInfoTest, BasicFileDecls) {
EXPECT_TRUE(Parse(
- "/*a*/syntax = \"proto2\";\n"
- "package /*b*/foo.bar/*c*/;\n"
- "import /*d*/\"baz.proto\"/*e*/;\n"
- "import /*f*/\"qux.proto\"/*g*/;/*h*/\n"
+ "$a$syntax = \"proto2\";$i$\n"
+ "package $b$foo.bar$c$;\n"
+ "import $d$\"baz.proto\"$e$;\n"
+ "import $f$\"qux.proto\"$g$;$h$\n"
+ "\n"
"// comment ignored\n"));
- EXPECT_TRUE(HasSpan("a", "h", file_));
- EXPECT_TRUE(HasSpan("b", "c", file_, "package"));
- EXPECT_TRUE(HasSpan("d", "e", file_, "dependency", 0));
- EXPECT_TRUE(HasSpan("f", "g", file_, "dependency", 1));
+ EXPECT_TRUE(HasSpan('a', 'h', file_));
+ EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
+ EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
+ EXPECT_TRUE(HasSpan('f', 'g', file_, "dependency", 1));
+ EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax"));
}
TEST_F(SourceInfoTest, Messages) {
EXPECT_TRUE(Parse(
- "/*a*/message /*b*/Foo/*c*/ {}/*d*/\n"
- "/*e*/message /*f*/Bar/*g*/ {}/*h*/\n"));
+ "$a$message $b$Foo$c$ {}$d$\n"
+ "$e$message $f$Bar$g$ {}$h$\n"));
- EXPECT_TRUE(HasSpan("a", "d", file_.message_type(0)));
- EXPECT_TRUE(HasSpan("b", "c", file_.message_type(0), "name"));
- EXPECT_TRUE(HasSpan("e", "h", file_.message_type(1)));
- EXPECT_TRUE(HasSpan("f", "g", file_.message_type(1), "name"));
+ EXPECT_TRUE(HasSpan('a', 'd', file_.message_type(0)));
+ EXPECT_TRUE(HasSpan('b', 'c', file_.message_type(0), "name"));
+ EXPECT_TRUE(HasSpan('e', 'h', file_.message_type(1)));
+ EXPECT_TRUE(HasSpan('f', 'g', file_.message_type(1), "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1592,24 +2202,24 @@ TEST_F(SourceInfoTest, Messages) {
TEST_F(SourceInfoTest, Fields) {
EXPECT_TRUE(Parse(
"message Foo {\n"
- " /*a*/optional/*b*/ /*c*/int32/*d*/ /*e*/bar/*f*/ = /*g*/1/*h*/;/*i*/\n"
- " /*j*/repeated/*k*/ /*l*/X.Y/*m*/ /*n*/baz/*o*/ = /*p*/2/*q*/;/*r*/\n"
+ " $a$optional$b$ $c$int32$d$ $e$bar$f$ = $g$1$h$;$i$\n"
+ " $j$repeated$k$ $l$X.Y$m$ $n$baz$o$ = $p$2$q$;$r$\n"
"}\n"));
const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
- EXPECT_TRUE(HasSpan("a", "i", field1));
- EXPECT_TRUE(HasSpan("a", "b", field1, "label"));
- EXPECT_TRUE(HasSpan("c", "d", field1, "type"));
- EXPECT_TRUE(HasSpan("e", "f", field1, "name"));
- EXPECT_TRUE(HasSpan("g", "h", field1, "number"));
+ EXPECT_TRUE(HasSpan('a', 'i', field1));
+ EXPECT_TRUE(HasSpan('a', 'b', field1, "label"));
+ EXPECT_TRUE(HasSpan('c', 'd', field1, "type"));
+ EXPECT_TRUE(HasSpan('e', 'f', field1, "name"));
+ EXPECT_TRUE(HasSpan('g', 'h', field1, "number"));
- EXPECT_TRUE(HasSpan("j", "r", field2));
- EXPECT_TRUE(HasSpan("j", "k", field2, "label"));
- EXPECT_TRUE(HasSpan("l", "m", field2, "type_name"));
- EXPECT_TRUE(HasSpan("n", "o", field2, "name"));
- EXPECT_TRUE(HasSpan("p", "q", field2, "number"));
+ EXPECT_TRUE(HasSpan('j', 'r', field2));
+ EXPECT_TRUE(HasSpan('j', 'k', field2, "label"));
+ EXPECT_TRUE(HasSpan('l', 'm', field2, "type_name"));
+ EXPECT_TRUE(HasSpan('n', 'o', field2, "name"));
+ EXPECT_TRUE(HasSpan('p', 'q', field2, "number"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1619,31 +2229,31 @@ TEST_F(SourceInfoTest, Fields) {
TEST_F(SourceInfoTest, Extensions) {
EXPECT_TRUE(Parse(
- "/*a*/extend /*b*/Foo/*c*/ {\n"
- " /*d*/optional/*e*/ int32 bar = 1;/*f*/\n"
- " /*g*/repeated/*h*/ X.Y baz = 2;/*i*/\n"
- "}/*j*/\n"
- "/*k*/extend /*l*/Bar/*m*/ {\n"
- " /*n*/optional int32 qux = 1;/*o*/\n"
- "}/*p*/\n"));
+ "$a$extend $b$Foo$c$ {\n"
+ " $d$optional$e$ int32 bar = 1;$f$\n"
+ " $g$repeated$h$ X.Y baz = 2;$i$\n"
+ "}$j$\n"
+ "$k$extend $l$Bar$m$ {\n"
+ " $n$optional int32 qux = 1;$o$\n"
+ "}$p$\n"));
const FieldDescriptorProto& field1 = file_.extension(0);
const FieldDescriptorProto& field2 = file_.extension(1);
const FieldDescriptorProto& field3 = file_.extension(2);
- EXPECT_TRUE(HasSpan("a", "j", file_, "extension"));
- EXPECT_TRUE(HasSpan("k", "p", file_, "extension"));
+ EXPECT_TRUE(HasSpan('a', 'j', file_, "extension"));
+ EXPECT_TRUE(HasSpan('k', 'p', file_, "extension"));
- EXPECT_TRUE(HasSpan("d", "f", field1));
- EXPECT_TRUE(HasSpan("d", "e", field1, "label"));
- EXPECT_TRUE(HasSpan("b", "c", field1, "extendee"));
+ EXPECT_TRUE(HasSpan('d', 'f', field1));
+ EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
+ EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
- EXPECT_TRUE(HasSpan("g", "i", field2));
- EXPECT_TRUE(HasSpan("g", "h", field2, "label"));
- EXPECT_TRUE(HasSpan("b", "c", field2, "extendee"));
+ EXPECT_TRUE(HasSpan('g', 'i', field2));
+ EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
+ EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
- EXPECT_TRUE(HasSpan("n", "o", field3));
- EXPECT_TRUE(HasSpan("l", "m", field3, "extendee"));
+ EXPECT_TRUE(HasSpan('n', 'o', field3));
+ EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1662,32 +2272,32 @@ TEST_F(SourceInfoTest, Extensions) {
TEST_F(SourceInfoTest, NestedExtensions) {
EXPECT_TRUE(Parse(
"message Message {\n"
- " /*a*/extend /*b*/Foo/*c*/ {\n"
- " /*d*/optional/*e*/ int32 bar = 1;/*f*/\n"
- " /*g*/repeated/*h*/ X.Y baz = 2;/*i*/\n"
- " }/*j*/\n"
- " /*k*/extend /*l*/Bar/*m*/ {\n"
- " /*n*/optional int32 qux = 1;/*o*/\n"
- " }/*p*/\n"
+ " $a$extend $b$Foo$c$ {\n"
+ " $d$optional$e$ int32 bar = 1;$f$\n"
+ " $g$repeated$h$ X.Y baz = 2;$i$\n"
+ " }$j$\n"
+ " $k$extend $l$Bar$m$ {\n"
+ " $n$optional int32 qux = 1;$o$\n"
+ " }$p$\n"
"}\n"));
const FieldDescriptorProto& field1 = file_.message_type(0).extension(0);
const FieldDescriptorProto& field2 = file_.message_type(0).extension(1);
const FieldDescriptorProto& field3 = file_.message_type(0).extension(2);
- EXPECT_TRUE(HasSpan("a", "j", file_.message_type(0), "extension"));
- EXPECT_TRUE(HasSpan("k", "p", file_.message_type(0), "extension"));
+ EXPECT_TRUE(HasSpan('a', 'j', file_.message_type(0), "extension"));
+ EXPECT_TRUE(HasSpan('k', 'p', file_.message_type(0), "extension"));
- EXPECT_TRUE(HasSpan("d", "f", field1));
- EXPECT_TRUE(HasSpan("d", "e", field1, "label"));
- EXPECT_TRUE(HasSpan("b", "c", field1, "extendee"));
+ EXPECT_TRUE(HasSpan('d', 'f', field1));
+ EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
+ EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
- EXPECT_TRUE(HasSpan("g", "i", field2));
- EXPECT_TRUE(HasSpan("g", "h", field2, "label"));
- EXPECT_TRUE(HasSpan("b", "c", field2, "extendee"));
+ EXPECT_TRUE(HasSpan('g', 'i', field2));
+ EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
+ EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
- EXPECT_TRUE(HasSpan("n", "o", field3));
- EXPECT_TRUE(HasSpan("l", "m", field3, "extendee"));
+ EXPECT_TRUE(HasSpan('n', 'o', field3));
+ EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1708,8 +2318,8 @@ TEST_F(SourceInfoTest, NestedExtensions) {
TEST_F(SourceInfoTest, ExtensionRanges) {
EXPECT_TRUE(Parse(
"message Message {\n"
- " /*a*/extensions /*b*/1/*c*/ to /*d*/4/*e*/, /*f*/6/*g*/;/*h*/\n"
- " /*i*/extensions /*j*/8/*k*/ to /*l*/max/*m*/;/*n*/\n"
+ " $a$extensions $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
+ " $i$extensions $j$8$k$ to $l$max$m$;$n$\n"
"}\n"));
const DescriptorProto::ExtensionRange& range1 =
@@ -1719,20 +2329,45 @@ TEST_F(SourceInfoTest, ExtensionRanges) {
const DescriptorProto::ExtensionRange& range3 =
file_.message_type(0).extension_range(2);
- EXPECT_TRUE(HasSpan("a", "h", file_.message_type(0), "extension_range"));
- EXPECT_TRUE(HasSpan("i", "n", file_.message_type(0), "extension_range"));
+ EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "extension_range"));
+ EXPECT_TRUE(HasSpan('i', 'n', file_.message_type(0), "extension_range"));
- EXPECT_TRUE(HasSpan("b", "e", range1));
- EXPECT_TRUE(HasSpan("b", "c", range1, "start"));
- EXPECT_TRUE(HasSpan("d", "e", range1, "end"));
+ EXPECT_TRUE(HasSpan('b', 'e', range1));
+ EXPECT_TRUE(HasSpan('b', 'c', range1, "start"));
+ EXPECT_TRUE(HasSpan('d', 'e', range1, "end"));
- EXPECT_TRUE(HasSpan("f", "g", range2));
- EXPECT_TRUE(HasSpan("f", "g", range2, "start"));
- EXPECT_TRUE(HasSpan("f", "g", range2, "end"));
+ EXPECT_TRUE(HasSpan('f', 'g', range2));
+ EXPECT_TRUE(HasSpan('f', 'g', range2, "start"));
+ EXPECT_TRUE(HasSpan('f', 'g', range2, "end"));
- EXPECT_TRUE(HasSpan("j", "m", range3));
- EXPECT_TRUE(HasSpan("j", "k", range3, "start"));
- EXPECT_TRUE(HasSpan("l", "m", range3, "end"));
+ EXPECT_TRUE(HasSpan('j', 'm', range3));
+ EXPECT_TRUE(HasSpan('j', 'k', range3, "start"));
+ EXPECT_TRUE(HasSpan('l', 'm', range3, "end"));
+
+ // Ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+ EXPECT_TRUE(HasSpan(file_.message_type(0)));
+ EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Oneofs) {
+ EXPECT_TRUE(Parse(
+ "message Foo {\n"
+ " $a$oneof $c$foo$d$ {\n"
+ " $e$int32$f$ $g$a$h$ = $i$1$j$;$k$\n"
+ " }$r$\n"
+ "}\n"));
+
+ const OneofDescriptorProto& oneof_decl = file_.message_type(0).oneof_decl(0);
+ const FieldDescriptorProto& field = file_.message_type(0).field(0);
+
+ EXPECT_TRUE(HasSpan('a', 'r', oneof_decl));
+ EXPECT_TRUE(HasSpan('c', 'd', oneof_decl, "name"));
+
+ EXPECT_TRUE(HasSpan('e', 'k', field));
+ EXPECT_TRUE(HasSpan('e', 'f', field, "type"));
+ EXPECT_TRUE(HasSpan('g', 'h', field, "name"));
+ EXPECT_TRUE(HasSpan('i', 'j', field, "number"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1743,22 +2378,22 @@ TEST_F(SourceInfoTest, ExtensionRanges) {
TEST_F(SourceInfoTest, NestedMessages) {
EXPECT_TRUE(Parse(
"message Foo {\n"
- " /*a*/message /*b*/Bar/*c*/ {\n"
- " /*d*/message /*e*/Baz/*f*/ {}/*g*/\n"
- " }/*h*/\n"
- " /*i*/message /*j*/Qux/*k*/ {}/*l*/\n"
+ " $a$message $b$Bar$c$ {\n"
+ " $d$message $e$Baz$f$ {}$g$\n"
+ " }$h$\n"
+ " $i$message $j$Qux$k$ {}$l$\n"
"}\n"));
const DescriptorProto& bar = file_.message_type(0).nested_type(0);
const DescriptorProto& baz = bar.nested_type(0);
const DescriptorProto& qux = file_.message_type(0).nested_type(1);
- EXPECT_TRUE(HasSpan("a", "h", bar));
- EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
- EXPECT_TRUE(HasSpan("d", "g", baz));
- EXPECT_TRUE(HasSpan("e", "f", baz, "name"));
- EXPECT_TRUE(HasSpan("i", "l", qux));
- EXPECT_TRUE(HasSpan("j", "k", qux, "name"));
+ EXPECT_TRUE(HasSpan('a', 'h', bar));
+ EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
+ EXPECT_TRUE(HasSpan('d', 'g', baz));
+ EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
+ EXPECT_TRUE(HasSpan('i', 'l', qux));
+ EXPECT_TRUE(HasSpan('j', 'k', qux, "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1770,9 +2405,9 @@ TEST_F(SourceInfoTest, Groups) {
EXPECT_TRUE(Parse(
"message Foo {\n"
" message Bar {}\n"
- " /*a*/optional/*b*/ /*c*/group/*d*/ /*e*/Baz/*f*/ = /*g*/1/*h*/ {\n"
- " /*i*/message Qux {}/*j*/\n"
- " }/*k*/\n"
+ " $a$optional$b$ $c$group$d$ $e$Baz$f$ = $g$1$h$ {\n"
+ " $i$message Qux {}$j$\n"
+ " }$k$\n"
"}\n"));
const DescriptorProto& bar = file_.message_type(0).nested_type(0);
@@ -1780,16 +2415,16 @@ TEST_F(SourceInfoTest, Groups) {
const DescriptorProto& qux = baz.nested_type(0);
const FieldDescriptorProto& field = file_.message_type(0).field(0);
- EXPECT_TRUE(HasSpan("a", "k", field));
- EXPECT_TRUE(HasSpan("a", "b", field, "label"));
- EXPECT_TRUE(HasSpan("c", "d", field, "type"));
- EXPECT_TRUE(HasSpan("e", "f", field, "name"));
- EXPECT_TRUE(HasSpan("e", "f", field, "type_name"));
- EXPECT_TRUE(HasSpan("g", "h", field, "number"));
+ EXPECT_TRUE(HasSpan('a', 'k', field));
+ EXPECT_TRUE(HasSpan('a', 'b', field, "label"));
+ EXPECT_TRUE(HasSpan('c', 'd', field, "type"));
+ EXPECT_TRUE(HasSpan('e', 'f', field, "name"));
+ EXPECT_TRUE(HasSpan('e', 'f', field, "type_name"));
+ EXPECT_TRUE(HasSpan('g', 'h', field, "number"));
- EXPECT_TRUE(HasSpan("a", "k", baz));
- EXPECT_TRUE(HasSpan("e", "f", baz, "name"));
- EXPECT_TRUE(HasSpan("i", "j", qux));
+ EXPECT_TRUE(HasSpan('a', 'k', baz));
+ EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
+ EXPECT_TRUE(HasSpan('i', 'j', qux));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1802,13 +2437,13 @@ TEST_F(SourceInfoTest, Groups) {
TEST_F(SourceInfoTest, Enums) {
EXPECT_TRUE(Parse(
- "/*a*/enum /*b*/Foo/*c*/ {}/*d*/\n"
- "/*e*/enum /*f*/Bar/*g*/ {}/*h*/\n"));
+ "$a$enum $b$Foo$c$ {}$d$\n"
+ "$e$enum $f$Bar$g$ {}$h$\n"));
- EXPECT_TRUE(HasSpan("a", "d", file_.enum_type(0)));
- EXPECT_TRUE(HasSpan("b", "c", file_.enum_type(0), "name"));
- EXPECT_TRUE(HasSpan("e", "h", file_.enum_type(1)));
- EXPECT_TRUE(HasSpan("f", "g", file_.enum_type(1), "name"));
+ EXPECT_TRUE(HasSpan('a', 'd', file_.enum_type(0)));
+ EXPECT_TRUE(HasSpan('b', 'c', file_.enum_type(0), "name"));
+ EXPECT_TRUE(HasSpan('e', 'h', file_.enum_type(1)));
+ EXPECT_TRUE(HasSpan('f', 'g', file_.enum_type(1), "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1817,19 +2452,19 @@ TEST_F(SourceInfoTest, Enums) {
TEST_F(SourceInfoTest, EnumValues) {
EXPECT_TRUE(Parse(
"enum Foo {\n"
- " /*a*/BAR/*b*/ = /*c*/1/*d*/;/*e*/\n"
- " /*f*/BAZ/*g*/ = /*h*/2/*i*/;/*j*/\n"
+ " $a$BAR$b$ = $c$1$d$;$e$\n"
+ " $f$BAZ$g$ = $h$2$i$;$j$\n"
"}"));
const EnumValueDescriptorProto& bar = file_.enum_type(0).value(0);
const EnumValueDescriptorProto& baz = file_.enum_type(0).value(1);
- EXPECT_TRUE(HasSpan("a", "e", bar));
- EXPECT_TRUE(HasSpan("a", "b", bar, "name"));
- EXPECT_TRUE(HasSpan("c", "d", bar, "number"));
- EXPECT_TRUE(HasSpan("f", "j", baz));
- EXPECT_TRUE(HasSpan("f", "g", baz, "name"));
- EXPECT_TRUE(HasSpan("h", "i", baz, "number"));
+ EXPECT_TRUE(HasSpan('a', 'e', bar));
+ EXPECT_TRUE(HasSpan('a', 'b', bar, "name"));
+ EXPECT_TRUE(HasSpan('c', 'd', bar, "number"));
+ EXPECT_TRUE(HasSpan('f', 'j', baz));
+ EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
+ EXPECT_TRUE(HasSpan('h', 'i', baz, "number"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1840,17 +2475,17 @@ TEST_F(SourceInfoTest, EnumValues) {
TEST_F(SourceInfoTest, NestedEnums) {
EXPECT_TRUE(Parse(
"message Foo {\n"
- " /*a*/enum /*b*/Bar/*c*/ {}/*d*/\n"
- " /*e*/enum /*f*/Baz/*g*/ {}/*h*/\n"
+ " $a$enum $b$Bar$c$ {}$d$\n"
+ " $e$enum $f$Baz$g$ {}$h$\n"
"}\n"));
const EnumDescriptorProto& bar = file_.message_type(0).enum_type(0);
const EnumDescriptorProto& baz = file_.message_type(0).enum_type(1);
- EXPECT_TRUE(HasSpan("a", "d", bar));
- EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
- EXPECT_TRUE(HasSpan("e", "h", baz));
- EXPECT_TRUE(HasSpan("f", "g", baz, "name"));
+ EXPECT_TRUE(HasSpan('a', 'd', bar));
+ EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
+ EXPECT_TRUE(HasSpan('e', 'h', baz));
+ EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1860,37 +2495,37 @@ TEST_F(SourceInfoTest, NestedEnums) {
TEST_F(SourceInfoTest, Services) {
EXPECT_TRUE(Parse(
- "/*a*/service /*b*/Foo/*c*/ {}/*d*/\n"
- "/*e*/service /*f*/Bar/*g*/ {}/*h*/\n"));
+ "$a$service $b$Foo$c$ {}$d$\n"
+ "$e$service $f$Bar$g$ {}$h$\n"));
- EXPECT_TRUE(HasSpan("a", "d", file_.service(0)));
- EXPECT_TRUE(HasSpan("b", "c", file_.service(0), "name"));
- EXPECT_TRUE(HasSpan("e", "h", file_.service(1)));
- EXPECT_TRUE(HasSpan("f", "g", file_.service(1), "name"));
+ EXPECT_TRUE(HasSpan('a', 'd', file_.service(0)));
+ EXPECT_TRUE(HasSpan('b', 'c', file_.service(0), "name"));
+ EXPECT_TRUE(HasSpan('e', 'h', file_.service(1)));
+ EXPECT_TRUE(HasSpan('f', 'g', file_.service(1), "name"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
}
-TEST_F(SourceInfoTest, Methods) {
+TEST_F(SourceInfoTest, MethodsAndStreams) {
EXPECT_TRUE(Parse(
"service Foo {\n"
- " /*a*/rpc /*b*/Bar/*c*/(/*d*/X/*e*/) returns(/*f*/Y/*g*/);/*h*/"
- " /*i*/rpc /*j*/Baz/*k*/(/*l*/Z/*m*/) returns(/*n*/W/*o*/);/*p*/"
+ " $a$rpc $b$Bar$c$($d$X$e$) returns($f$Y$g$);$h$"
+ " $i$rpc $j$Baz$k$($l$Z$m$) returns($n$W$o$);$p$"
"}"));
const MethodDescriptorProto& bar = file_.service(0).method(0);
const MethodDescriptorProto& baz = file_.service(0).method(1);
- EXPECT_TRUE(HasSpan("a", "h", bar));
- EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
- EXPECT_TRUE(HasSpan("d", "e", bar, "input_type"));
- EXPECT_TRUE(HasSpan("f", "g", bar, "output_type"));
+ EXPECT_TRUE(HasSpan('a', 'h', bar));
+ EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
+ EXPECT_TRUE(HasSpan('d', 'e', bar, "input_type"));
+ EXPECT_TRUE(HasSpan('f', 'g', bar, "output_type"));
- EXPECT_TRUE(HasSpan("i", "p", baz));
- EXPECT_TRUE(HasSpan("j", "k", baz, "name"));
- EXPECT_TRUE(HasSpan("l", "m", baz, "input_type"));
- EXPECT_TRUE(HasSpan("n", "o", baz, "output_type"));
+ EXPECT_TRUE(HasSpan('i', 'p', baz));
+ EXPECT_TRUE(HasSpan('j', 'k', baz, "name"));
+ EXPECT_TRUE(HasSpan('l', 'm', baz, "input_type"));
+ EXPECT_TRUE(HasSpan('n', 'o', baz, "output_type"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1898,15 +2533,16 @@ TEST_F(SourceInfoTest, Methods) {
EXPECT_TRUE(HasSpan(file_.service(0), "name"));
}
+
TEST_F(SourceInfoTest, Options) {
EXPECT_TRUE(Parse(
- "/*a*/option /*b*/foo/*c*/./*d*/(/*e*/bar.baz/*f*/)/*g*/ = "
- "/*h*/123/*i*/;/*j*/\n"
- "/*k*/option qux = /*l*/-123/*m*/;/*n*/\n"
- "/*o*/option corge = /*p*/abc/*q*/;/*r*/\n"
- "/*s*/option grault = /*t*/'blah'/*u*/;/*v*/\n"
- "/*w*/option garply = /*x*/{ yadda yadda }/*y*/;/*z*/\n"
- "/*0*/option waldo = /*1*/123.0/*2*/;/*3*/\n"
+ "$a$option $b$foo$c$.$d$($e$bar.baz$f$)$g$ = "
+ "$h$123$i$;$j$\n"
+ "$k$option qux = $l$-123$m$;$n$\n"
+ "$o$option corge = $p$abc$q$;$r$\n"
+ "$s$option grault = $t$'blah'$u$;$v$\n"
+ "$w$option garply = $x${ yadda yadda }$y$;$z$\n"
+ "$0$option waldo = $1$123.0$2$;$3$\n"
));
const UninterpretedOption& option1 = file_.options().uninterpreted_option(0);
@@ -1916,29 +2552,29 @@ TEST_F(SourceInfoTest, Options) {
const UninterpretedOption& option5 = file_.options().uninterpreted_option(4);
const UninterpretedOption& option6 = file_.options().uninterpreted_option(5);
- EXPECT_TRUE(HasSpan("a", "j", file_.options()));
- EXPECT_TRUE(HasSpan("b", "i", option1));
- EXPECT_TRUE(HasSpan("b", "g", option1, "name"));
- EXPECT_TRUE(HasSpan("b", "c", option1.name(0)));
- EXPECT_TRUE(HasSpan("b", "c", option1.name(0), "name_part"));
- EXPECT_TRUE(HasSpan("d", "g", option1.name(1)));
- EXPECT_TRUE(HasSpan("e", "f", option1.name(1), "name_part"));
- EXPECT_TRUE(HasSpan("h", "i", option1, "positive_int_value"));
+ EXPECT_TRUE(HasSpan('a', 'j', file_.options()));
+ EXPECT_TRUE(HasSpan('a', 'j', option1));
+ EXPECT_TRUE(HasSpan('b', 'g', option1, "name"));
+ EXPECT_TRUE(HasSpan('b', 'c', option1.name(0)));
+ EXPECT_TRUE(HasSpan('b', 'c', option1.name(0), "name_part"));
+ EXPECT_TRUE(HasSpan('d', 'g', option1.name(1)));
+ EXPECT_TRUE(HasSpan('e', 'f', option1.name(1), "name_part"));
+ EXPECT_TRUE(HasSpan('h', 'i', option1, "positive_int_value"));
- EXPECT_TRUE(HasSpan("k", "n", file_.options()));
- EXPECT_TRUE(HasSpan("l", "m", option2, "negative_int_value"));
+ EXPECT_TRUE(HasSpan('k', 'n', file_.options()));
+ EXPECT_TRUE(HasSpan('l', 'm', option2, "negative_int_value"));
- EXPECT_TRUE(HasSpan("o", "r", file_.options()));
- EXPECT_TRUE(HasSpan("p", "q", option3, "identifier_value"));
+ EXPECT_TRUE(HasSpan('o', 'r', file_.options()));
+ EXPECT_TRUE(HasSpan('p', 'q', option3, "identifier_value"));
- EXPECT_TRUE(HasSpan("s", "v", file_.options()));
- EXPECT_TRUE(HasSpan("t", "u", option4, "string_value"));
+ EXPECT_TRUE(HasSpan('s', 'v', file_.options()));
+ EXPECT_TRUE(HasSpan('t', 'u', option4, "string_value"));
- EXPECT_TRUE(HasSpan("w", "z", file_.options()));
- EXPECT_TRUE(HasSpan("x", "y", option5, "aggregate_value"));
+ EXPECT_TRUE(HasSpan('w', 'z', file_.options()));
+ EXPECT_TRUE(HasSpan('x', 'y', option5, "aggregate_value"));
- EXPECT_TRUE(HasSpan("0", "3", file_.options()));
- EXPECT_TRUE(HasSpan("1", "2", option6, "double_value"));
+ EXPECT_TRUE(HasSpan('0', '3', file_.options()));
+ EXPECT_TRUE(HasSpan('1', '2', option6, "double_value"));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -1967,22 +2603,25 @@ TEST_F(SourceInfoTest, Options) {
TEST_F(SourceInfoTest, ScopedOptions) {
EXPECT_TRUE(Parse(
"message Foo {\n"
- " /*a*/option mopt = 1;/*b*/\n"
+ " $a$option mopt = 1;$b$\n"
"}\n"
"enum Bar {\n"
- " /*c*/option eopt = 1;/*d*/\n"
+ " $c$option eopt = 1;$d$\n"
"}\n"
"service Baz {\n"
- " /*e*/option sopt = 1;/*f*/\n"
+ " $e$option sopt = 1;$f$\n"
" rpc M(X) returns(Y) {\n"
- " /*g*/option mopt = 1;/*h*/\n"
+ " $g$option mopt = 1;$h$\n"
+ " }\n"
+ " rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n"
+ " $k$option mopt = 1;$l$\n"
" }\n"
"}\n"));
- EXPECT_TRUE(HasSpan("a", "b", file_.message_type(0).options()));
- EXPECT_TRUE(HasSpan("c", "d", file_.enum_type(0).options()));
- EXPECT_TRUE(HasSpan("e", "f", file_.service(0).options()));
- EXPECT_TRUE(HasSpan("g", "h", file_.service(0).method(0).options()));
+ EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
+ EXPECT_TRUE(HasSpan('c', 'd', file_.enum_type(0).options()));
+ EXPECT_TRUE(HasSpan('e', 'f', file_.service(0).options()));
+ EXPECT_TRUE(HasSpan('g', 'h', file_.service(0).method(0).options()));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -2036,6 +2675,26 @@ TEST_F(SourceInfoTest, ScopedOptions) {
.uninterpreted_option(0).name(0), "name_part"));
EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
.uninterpreted_option(0), "positive_int_value"));
+
+ EXPECT_TRUE(HasSpan('k', 'l', file_.service(0).method(1).options()));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1)));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1), "name"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1), "input_type"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1), "output_type"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0)));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0), "name"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0).name(0)));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0).name(0), "name_part"));
+ EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+ .uninterpreted_option(0), "positive_int_value"));
+ EXPECT_TRUE(HasSpan('1', '2', file_.service(0).method(1),
+ "client_streaming"));
+ EXPECT_TRUE(HasSpan('3', '4', file_.service(0).method(1),
+ "server_streaming"));
}
TEST_F(SourceInfoTest, FieldOptions) {
@@ -2045,8 +2704,8 @@ TEST_F(SourceInfoTest, FieldOptions) {
EXPECT_TRUE(Parse(
"message Foo {"
" optional int32 bar = 1 "
- "/*a*/[default=/*b*/123/*c*/,/*d*/opt1=123/*e*/,"
- "/*f*/opt2='hi'/*g*/]/*h*/;"
+ "$a$[default=$b$123$c$,$d$opt1=123$e$,"
+ "$f$opt2='hi'$g$]$h$;"
"}\n"
));
@@ -2054,10 +2713,10 @@ TEST_F(SourceInfoTest, FieldOptions) {
const UninterpretedOption& option1 = field.options().uninterpreted_option(0);
const UninterpretedOption& option2 = field.options().uninterpreted_option(1);
- EXPECT_TRUE(HasSpan("a", "h", field.options()));
- EXPECT_TRUE(HasSpan("b", "c", field, "default_value"));
- EXPECT_TRUE(HasSpan("d", "e", option1));
- EXPECT_TRUE(HasSpan("f", "g", option2));
+ EXPECT_TRUE(HasSpan('a', 'h', field.options()));
+ EXPECT_TRUE(HasSpan('b', 'c', field, "default_value"));
+ EXPECT_TRUE(HasSpan('d', 'e', option1));
+ EXPECT_TRUE(HasSpan('f', 'g', option2));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -2084,7 +2743,7 @@ TEST_F(SourceInfoTest, EnumValueOptions) {
// syntax used for enum options is understood.
EXPECT_TRUE(Parse(
"enum Foo {"
- " BAR = 1 /*a*/[/*b*/opt1=123/*c*/,/*d*/opt2='hi'/*e*/]/*f*/;"
+ " BAR = 1 $a$[$b$opt1=123$c$,$d$opt2='hi'$e$]$f$;"
"}\n"
));
@@ -2092,9 +2751,9 @@ TEST_F(SourceInfoTest, EnumValueOptions) {
const UninterpretedOption& option1 = value.options().uninterpreted_option(0);
const UninterpretedOption& option2 = value.options().uninterpreted_option(1);
- EXPECT_TRUE(HasSpan("a", "f", value.options()));
- EXPECT_TRUE(HasSpan("b", "c", option1));
- EXPECT_TRUE(HasSpan("d", "e", option2));
+ EXPECT_TRUE(HasSpan('a', 'f', value.options()));
+ EXPECT_TRUE(HasSpan('b', 'c', option1));
+ EXPECT_TRUE(HasSpan('d', 'e', option2));
// Ignore these.
EXPECT_TRUE(HasSpan(file_));
@@ -2113,6 +2772,221 @@ TEST_F(SourceInfoTest, EnumValueOptions) {
EXPECT_TRUE(HasSpan(option2, "string_value"));
}
+TEST_F(SourceInfoTest, DocComments) {
+ EXPECT_TRUE(Parse(
+ "// Foo leading\n"
+ "// line 2\n"
+ "$a$message Foo {\n"
+ " // Foo trailing\n"
+ " // line 2\n"
+ "\n"
+ " // detached\n"
+ "\n"
+ " // bar leading\n"
+ " $b$optional int32 bar = 1;$c$\n"
+ " // bar trailing\n"
+ "}$d$\n"
+ "// ignored\n"
+ ));
+
+ const DescriptorProto& foo = file_.message_type(0);
+ const FieldDescriptorProto& bar = foo.field(0);
+
+ EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
+ " Foo leading\n line 2\n",
+ " Foo trailing\n line 2\n",
+ NULL));
+ EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
+ " bar leading\n",
+ " bar trailing\n",
+ " detached\n"));
+
+ // Ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+ EXPECT_TRUE(HasSpan(foo, "name"));
+ EXPECT_TRUE(HasSpan(bar, "label"));
+ EXPECT_TRUE(HasSpan(bar, "type"));
+ EXPECT_TRUE(HasSpan(bar, "name"));
+ EXPECT_TRUE(HasSpan(bar, "number"));
+}
+
+TEST_F(SourceInfoTest, DocComments2) {
+ EXPECT_TRUE(Parse(
+ "// detached before message.\n"
+ "\n"
+ "// Foo leading\n"
+ "// line 2\n"
+ "$a$message Foo {\n"
+ " /* Foo trailing\n"
+ " * line 2 */\n"
+ " // detached\n"
+ " /* bar leading\n"
+ " */"
+ " $b$optional int32 bar = 1;$c$ // bar trailing\n"
+ " // ignored detached\n"
+ "}$d$\n"
+ "// ignored\n"
+ "\n"
+ "// detached before option\n"
+ "\n"
+ "// option leading\n"
+ "$e$option baz = 123;$f$\n"
+ "// option trailing\n"
+ ));
+
+ const DescriptorProto& foo = file_.message_type(0);
+ const FieldDescriptorProto& bar = foo.field(0);
+ const UninterpretedOption& baz = file_.options().uninterpreted_option(0);
+
+ EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
+ " Foo leading\n line 2\n",
+ " Foo trailing\n line 2 ",
+ " detached before message.\n"));
+ EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
+ " bar leading\n",
+ " bar trailing\n",
+ " detached\n"));
+ EXPECT_TRUE(HasSpanWithComment('e', 'f', baz,
+ " option leading\n",
+ " option trailing\n",
+ " detached before option\n"));
+
+ // Ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+ EXPECT_TRUE(HasSpan(foo, "name"));
+ EXPECT_TRUE(HasSpan(bar, "label"));
+ EXPECT_TRUE(HasSpan(bar, "type"));
+ EXPECT_TRUE(HasSpan(bar, "name"));
+ EXPECT_TRUE(HasSpan(bar, "number"));
+ EXPECT_TRUE(HasSpan(file_.options()));
+ EXPECT_TRUE(HasSpan(baz, "name"));
+ EXPECT_TRUE(HasSpan(baz.name(0)));
+ EXPECT_TRUE(HasSpan(baz.name(0), "name_part"));
+ EXPECT_TRUE(HasSpan(baz, "positive_int_value"));
+}
+
+TEST_F(SourceInfoTest, DocComments3) {
+ EXPECT_TRUE(Parse(
+ "$a$message Foo {\n"
+ " // bar leading\n"
+ " $b$optional int32 bar = 1 [(baz.qux) = {}];$c$\n"
+ " // bar trailing\n"
+ "}$d$\n"
+ "// ignored\n"
+ ));
+
+ const DescriptorProto& foo = file_.message_type(0);
+ const FieldDescriptorProto& bar = foo.field(0);
+
+ EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
+ " bar leading\n",
+ " bar trailing\n",
+ NULL));
+
+ // Ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+ EXPECT_TRUE(HasSpan(foo));
+ EXPECT_TRUE(HasSpan(foo, "name"));
+ EXPECT_TRUE(HasSpan(bar, "label"));
+ EXPECT_TRUE(HasSpan(bar, "type"));
+ EXPECT_TRUE(HasSpan(bar, "name"));
+ EXPECT_TRUE(HasSpan(bar, "number"));
+ EXPECT_TRUE(HasSpan(bar.options()));
+ EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0)));
+ EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0), "name"));
+ EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0).name(0)));
+ EXPECT_TRUE(HasSpan(
+ bar.options().uninterpreted_option(0).name(0), "name_part"));
+ EXPECT_TRUE(HasSpan(
+ bar.options().uninterpreted_option(0), "aggregate_value"));
+}
+
+TEST_F(SourceInfoTest, DocCommentsTopLevel) {
+ EXPECT_TRUE(Parse(
+ "// detached before syntax paragraph 1\n"
+ "\n"
+ "// detached before syntax paragraph 2\n"
+ "\n"
+ "// syntax leading\n"
+ "$a$syntax = \"proto2\";$b$\n"
+ "// syntax trailing\n"
+ "\n"
+ "// syntax-package detached comments\n"
+ "\n"
+ ";\n"
+ "\n"
+ "// detached after empty before package\n"
+ "\n"
+ "// package leading\n"
+ "package $c$foo$d$;\n"
+ "// package trailing\n"
+ "\n"
+ "// ignored detach\n"
+ "\n"));
+
+ EXPECT_TRUE(HasSpan('a', 'b', file_, "syntax", -1,
+ " syntax leading\n",
+ " syntax trailing\n",
+ " detached before syntax paragraph 1\n"
+ "\n"
+ " detached before syntax paragraph 2\n"));
+ EXPECT_TRUE(HasSpan('c', 'd', file_, "package", -1,
+ " package leading\n",
+ " package trailing\n",
+ " syntax-package detached comments\n"
+ "\n"
+ " detached after empty before package\n"));
+
+ // ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+}
+
+TEST_F(SourceInfoTest, DocCommentsOneof) {
+ EXPECT_TRUE(Parse(
+ "// Foo leading\n"
+ "$a$message Foo {\n"
+ " /* Foo trailing\n"
+ " */\n"
+ " // detached before oneof\n"
+ " /* bar leading\n"
+ " * line 2 */\n"
+ " $b$oneof bar {\n"
+ " /* bar trailing\n"
+ " * line 2 */\n"
+ " // detached before bar_int\n"
+ " /* bar_int leading\n"
+ " */\n"
+ " $c$int32 bar_int = 1;$d$ // bar_int trailing\n"
+ " // detach comment ignored\n"
+ " }$e$\n"
+ "}$f$\n"));
+
+ const DescriptorProto& foo = file_.message_type(0);
+ const OneofDescriptorProto& bar = foo.oneof_decl(0);
+ const FieldDescriptorProto& bar_int = foo.field(0);
+
+ EXPECT_TRUE(HasSpanWithComment('a', 'f', foo,
+ " Foo leading\n",
+ " Foo trailing\n",
+ NULL));
+ EXPECT_TRUE(HasSpanWithComment('b', 'e', bar,
+ " bar leading\n line 2 ",
+ " bar trailing\n line 2 ",
+ " detached before oneof\n"));
+ EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int,
+ " bar_int leading\n",
+ " bar_int trailing\n",
+ " detached before bar_int\n"));
+
+ // Ignore these.
+ EXPECT_TRUE(HasSpan(file_));
+ EXPECT_TRUE(HasSpan(foo, "name"));
+ EXPECT_TRUE(HasSpan(bar, "name"));
+ EXPECT_TRUE(HasSpan(bar_int, "type"));
+ EXPECT_TRUE(HasSpan(bar_int, "name"));
+ EXPECT_TRUE(HasSpan(bar_int, "number"));
+}
+
// ===================================================================
} // anonymous namespace
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index 727f9421..ad501acf 100644
--- a/src/google/protobuf/compiler/plugin.cc
+++ b/src/google/protobuf/compiler/plugin.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -95,7 +95,7 @@ class GeneratorResponseContext : public GeneratorContext {
int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
if (argc > 1) {
- cerr << argv[0] << ": Unknown option: " << argv[1] << endl;
+ std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl;
return 1;
}
@@ -106,7 +106,8 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
CodeGeneratorRequest request;
if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
- cerr << argv[0] << ": protoc sent unparseable request to plugin." << endl;
+ std::cerr << argv[0] << ": protoc sent unparseable request to plugin."
+ << std::endl;
return 1;
}
@@ -123,9 +124,9 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
for (int i = 0; i < request.file_to_generate_size(); i++) {
parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
if (parsed_files.back() == NULL) {
- cerr << argv[0] << ": protoc asked plugin to generate a file but "
- "did not provide a descriptor for the file: "
- << request.file_to_generate(i) << endl;
+ std::cerr << argv[0] << ": protoc asked plugin to generate a file but "
+ "did not provide a descriptor for the file: "
+ << request.file_to_generate(i) << std::endl;
return 1;
}
}
@@ -151,7 +152,7 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
}
if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
- cerr << argv[0] << ": Error writing to stdout." << endl;
+ std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
return 1;
}
diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h
index 64dfb1d2..679f9bdb 100644
--- a/src/google/protobuf/compiler/plugin.h
+++ b/src/google/protobuf/compiler/plugin.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -56,7 +56,6 @@
#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
#include <google/protobuf/stubs/common.h>
-
namespace google {
namespace protobuf {
namespace compiler {
@@ -64,7 +63,7 @@ namespace compiler {
class CodeGenerator; // code_generator.h
// Implements main() for a protoc plugin exposing the given code generator.
-int PluginMain(int argc, char* argv[], const CodeGenerator* generator);
+LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator);
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index ad4b4deb..fed1726a 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -1,14 +1,17 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: google/protobuf/compiler/plugin.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "google/protobuf/compiler/plugin.pb.h"
#include <algorithm>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)
@@ -45,32 +48,32 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, proto_file_),
};
CodeGeneratorRequest_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
CodeGeneratorRequest_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(CodeGeneratorRequest));
+ -1,
+ sizeof(CodeGeneratorRequest),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_),
+ -1);
CodeGeneratorResponse_descriptor_ = file->message_type(1);
static const int CodeGeneratorResponse_offsets_[2] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, error_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, file_),
};
CodeGeneratorResponse_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
CodeGeneratorResponse_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(CodeGeneratorResponse));
+ -1,
+ sizeof(CodeGeneratorResponse),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_),
+ -1);
CodeGeneratorResponse_File_descriptor_ = CodeGeneratorResponse_descriptor_->nested_type(0);
static const int CodeGeneratorResponse_File_offsets_[3] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, name_),
@@ -78,16 +81,16 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, content_),
};
CodeGeneratorResponse_File_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
CodeGeneratorResponse_File_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(CodeGeneratorResponse_File));
+ -1,
+ sizeof(CodeGeneratorResponse_File),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_),
+ -1);
}
namespace {
@@ -101,11 +104,11 @@ inline void protobuf_AssignDescriptorsOnce() {
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- CodeGeneratorRequest_descriptor_, &CodeGeneratorRequest::default_instance());
+ CodeGeneratorRequest_descriptor_, &CodeGeneratorRequest::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- CodeGeneratorResponse_descriptor_, &CodeGeneratorResponse::default_instance());
+ CodeGeneratorResponse_descriptor_, &CodeGeneratorResponse::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- CodeGeneratorResponse_File_descriptor_, &CodeGeneratorResponse_File::default_instance());
+ CodeGeneratorResponse_File_descriptor_, &CodeGeneratorResponse_File::default_instance());
}
} // namespace
@@ -136,7 +139,9 @@ void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
"atorResponse\022\r\n\005error\030\001 \001(\t\022B\n\004file\030\017 \003("
"\01324.google.protobuf.compiler.CodeGenerat"
"orResponse.File\032>\n\004File\022\014\n\004name\030\001 \001(\t\022\027\n"
- "\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\t", 399);
+ "\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\tB"
+ "7\n\034com.google.protobuf.compilerB\014PluginP"
+ "rotosZ\tplugin_go", 456);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes);
CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest();
@@ -155,6 +160,15 @@ struct StaticDescriptorInitializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto
}
} static_descriptor_initializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto_;
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+ GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+} // namespace
+
// ===================================================================
@@ -165,33 +179,36 @@ 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)
}
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)
}
void CodeGeneratorRequest::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ parameter_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
CodeGeneratorRequest::~CodeGeneratorRequest() {
+ // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorRequest)
SharedDtor();
}
void CodeGeneratorRequest::SharedDtor() {
- if (parameter_ != &::google::protobuf::internal::kEmptyString) {
- delete parameter_;
- }
+ parameter_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
}
}
@@ -207,90 +224,98 @@ const ::google::protobuf::Descriptor* CodeGeneratorRequest::descriptor() {
}
const CodeGeneratorRequest& CodeGeneratorRequest::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
+ return *default_instance_;
}
CodeGeneratorRequest* CodeGeneratorRequest::default_instance_ = NULL;
-CodeGeneratorRequest* CodeGeneratorRequest::New() const {
- return new CodeGeneratorRequest;
+CodeGeneratorRequest* CodeGeneratorRequest::New(::google::protobuf::Arena* arena) const {
+ CodeGeneratorRequest* n = new CodeGeneratorRequest;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void CodeGeneratorRequest::Clear() {
- if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) {
- if (has_parameter()) {
- if (parameter_ != &::google::protobuf::internal::kEmptyString) {
- parameter_->clear();
- }
- }
+ if (has_parameter()) {
+ parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorRequest)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// repeated string file_to_generate = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
parse_file_to_generate:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->add_file_to_generate()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
- this->file_to_generate(0).data(), this->file_to_generate(0).length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ 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,
+ "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(10)) goto parse_file_to_generate;
if (input->ExpectTag(18)) goto parse_parameter;
break;
}
-
+
// optional string parameter = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_parameter:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_parameter()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->parameter().data(), this->parameter().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.compiler.CodeGeneratorRequest.parameter");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(122)) goto parse_proto_file;
break;
}
-
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
case 15: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 122) {
parse_proto_file:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_proto_file()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(122)) goto parse_proto_file;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -298,96 +323,107 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.compiler.CodeGeneratorRequest)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.compiler.CodeGeneratorRequest)
+ return false;
#undef DO_
}
void CodeGeneratorRequest::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.compiler.CodeGeneratorRequest)
// repeated string file_to_generate = 1;
for (int i = 0; i < this->file_to_generate_size(); i++) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->file_to_generate(i).data(), this->file_to_generate(i).length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->file_to_generate(i), output);
}
-
+
// optional string parameter = 2;
if (has_parameter()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->parameter().data(), this->parameter().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorRequest.parameter");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
2, this->parameter(), output);
}
-
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
- for (int i = 0; i < this->proto_file_size(); i++) {
+ for (unsigned int i = 0, n = this->proto_file_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
15, this->proto_file(i), output);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorRequest)
}
::google::protobuf::uint8* CodeGeneratorRequest::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorRequest)
// repeated string file_to_generate = 1;
for (int i = 0; i < this->file_to_generate_size(); i++) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->file_to_generate(i).data(), this->file_to_generate(i).length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
target = ::google::protobuf::internal::WireFormatLite::
WriteStringToArray(1, this->file_to_generate(i), target);
}
-
+
// optional string parameter = 2;
if (has_parameter()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->parameter().data(), this->parameter().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorRequest.parameter");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->parameter(), target);
}
-
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
- for (int i = 0; i < this->proto_file_size(); i++) {
+ for (unsigned int i = 0, n = this->proto_file_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorRequest)
return target;
}
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++) {
total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
this->file_to_generate(i));
}
-
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
total_size += 1 * this->proto_file_size();
for (int i = 0; i < this->proto_file_size(); i++) {
@@ -395,8 +431,8 @@ int CodeGeneratorRequest::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->proto_file(i));
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -408,7 +444,7 @@ int CodeGeneratorRequest::ByteSize() const {
}
void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const CodeGeneratorRequest* source =
::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorRequest*>(
&from);
@@ -420,15 +456,18 @@ void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) {
}
void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
file_to_generate_.MergeFrom(from.file_to_generate_);
proto_file_.MergeFrom(from.proto_file_);
if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
if (from.has_parameter()) {
- set_parameter(from.parameter());
+ set_has_parameter();
+ parameter_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 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) {
@@ -444,22 +483,22 @@ void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) {
}
bool CodeGeneratorRequest::IsInitialized() const {
-
- for (int i = 0; i < proto_file_size(); i++) {
- if (!this->proto_file(i).IsInitialized()) return false;
- }
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->proto_file())) return false;
return true;
}
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;
+ 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 {
@@ -470,6 +509,147 @@ void CodeGeneratorRequest::Swap(CodeGeneratorRequest* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// CodeGeneratorRequest
+
+// repeated string file_to_generate = 1;
+ int CodeGeneratorRequest::file_to_generate_size() const {
+ return file_to_generate_.size();
+}
+ void CodeGeneratorRequest::clear_file_to_generate() {
+ file_to_generate_.Clear();
+}
+ const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ return file_to_generate_.Get(index);
+}
+ ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ return file_to_generate_.Mutable(index);
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ file_to_generate_.Mutable(index)->assign(value);
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) {
+ file_to_generate_.Mutable(index)->assign(value);
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) {
+ file_to_generate_.Mutable(index)->assign(
+ reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ ::std::string* CodeGeneratorRequest::add_file_to_generate() {
+ return file_to_generate_.Add();
+}
+ void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) {
+ file_to_generate_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::add_file_to_generate(const char* value) {
+ file_to_generate_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) {
+ file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_add_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+CodeGeneratorRequest::file_to_generate() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ return file_to_generate_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+CodeGeneratorRequest::mutable_file_to_generate() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+ return &file_to_generate_;
+}
+
+// optional string parameter = 2;
+ bool CodeGeneratorRequest::has_parameter() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void CodeGeneratorRequest::set_has_parameter() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void CodeGeneratorRequest::clear_has_parameter() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void CodeGeneratorRequest::clear_parameter() {
+ parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_parameter();
+}
+ const ::std::string& CodeGeneratorRequest::parameter() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+ return parameter_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorRequest::set_parameter(const ::std::string& value) {
+ set_has_parameter();
+ parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ void CodeGeneratorRequest::set_parameter(const char* value) {
+ set_has_parameter();
+ parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ void CodeGeneratorRequest::set_parameter(const char* value, size_t size) {
+ set_has_parameter();
+ parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ ::std::string* CodeGeneratorRequest::mutable_parameter() {
+ set_has_parameter();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+ return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorRequest::release_parameter() {
+ clear_has_parameter();
+ return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) {
+ if (parameter != NULL) {
+ set_has_parameter();
+ } else {
+ clear_has_parameter();
+ }
+ parameter_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), parameter);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+
+// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
+ int CodeGeneratorRequest::proto_file_size() const {
+ return proto_file_.size();
+}
+ void CodeGeneratorRequest::clear_proto_file() {
+ proto_file_.Clear();
+}
+ const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return proto_file_.Get(index);
+}
+ ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return proto_file_.Mutable(index);
+}
+ ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
+ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return proto_file_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+CodeGeneratorRequest::proto_file() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return proto_file_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+CodeGeneratorRequest::mutable_proto_file() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+ return &proto_file_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -480,41 +660,40 @@ 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)
}
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)
}
void CodeGeneratorResponse_File::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ 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_));
}
CodeGeneratorResponse_File::~CodeGeneratorResponse_File() {
+ // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorResponse.File)
SharedDtor();
}
void CodeGeneratorResponse_File::SharedDtor() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- delete name_;
- }
- if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
- delete insertion_point_;
- }
- if (content_ != &::google::protobuf::internal::kEmptyString) {
- delete content_;
- }
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ insertion_point_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ content_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
}
}
@@ -530,98 +709,104 @@ const ::google::protobuf::Descriptor* CodeGeneratorResponse_File::descriptor() {
}
const CodeGeneratorResponse_File& CodeGeneratorResponse_File::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
+ return *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 {
+ CodeGeneratorResponse_File* n = new CodeGeneratorResponse_File;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void CodeGeneratorResponse_File::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bits_[0 / 32] & 7) {
if (has_name()) {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_insertion_point()) {
- if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
- insertion_point_->clear();
- }
+ insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_content()) {
- if (content_ != &::google::protobuf::internal::kEmptyString) {
- content_->clear();
- }
+ content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
}
::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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorResponse.File)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string name = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.compiler.CodeGeneratorResponse.File.name");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_insertion_point;
break;
}
-
+
// optional string insertion_point = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_insertion_point:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_insertion_point()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->insertion_point().data(), this->insertion_point().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(122)) goto parse_content;
break;
}
-
+
// optional string content = 15;
case 15: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 122) {
parse_content:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_content()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->content().data(), this->content().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.compiler.CodeGeneratorResponse.File.content");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -629,111 +814,126 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.compiler.CodeGeneratorResponse.File)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.compiler.CodeGeneratorResponse.File)
+ return false;
#undef DO_
}
void CodeGeneratorResponse_File::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.compiler.CodeGeneratorResponse.File)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorResponse.File.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->name(), output);
}
-
+
// optional string insertion_point = 2;
if (has_insertion_point()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->insertion_point().data(), this->insertion_point().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
2, this->insertion_point(), output);
}
-
+
// optional string content = 15;
if (has_content()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->content().data(), this->content().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "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);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorResponse.File)
}
::google::protobuf::uint8* CodeGeneratorResponse_File::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse.File)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorResponse.File.name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional string insertion_point = 2;
if (has_insertion_point()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->insertion_point().data(), this->insertion_point().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->insertion_point(), target);
}
-
+
// optional string content = 15;
if (has_content()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->content().data(), this->content().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse.File)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional string insertion_point = 2;
if (has_insertion_point()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->insertion_point());
}
-
+
// optional string content = 15;
if (has_content()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->content());
}
-
+
}
- if (!unknown_fields().empty()) {
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -745,7 +945,7 @@ int CodeGeneratorResponse_File::ByteSize() const {
}
void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const CodeGeneratorResponse_File* source =
::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse_File*>(
&from);
@@ -757,19 +957,24 @@ void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& fr
}
void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_name()) {
- set_name(from.name());
+ set_has_name();
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
}
if (from.has_insertion_point()) {
- set_insertion_point(from.insertion_point());
+ set_has_insertion_point();
+ insertion_point_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.insertion_point_);
}
if (from.has_content()) {
- set_content(from.content());
+ set_has_content();
+ content_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 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) {
@@ -785,19 +990,21 @@ void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from
}
bool CodeGeneratorResponse_File::IsInitialized() const {
-
+
return true;
}
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;
+ 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 {
@@ -817,33 +1024,36 @@ 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)
}
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)
}
void CodeGeneratorResponse::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ error_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
CodeGeneratorResponse::~CodeGeneratorResponse() {
+ // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorResponse)
SharedDtor();
}
void CodeGeneratorResponse::SharedDtor() {
- if (error_ != &::google::protobuf::internal::kEmptyString) {
- delete error_;
- }
+ error_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
}
}
@@ -859,70 +1069,77 @@ const ::google::protobuf::Descriptor* CodeGeneratorResponse::descriptor() {
}
const CodeGeneratorResponse& CodeGeneratorResponse::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
+ return *default_instance_;
}
CodeGeneratorResponse* CodeGeneratorResponse::default_instance_ = NULL;
-CodeGeneratorResponse* CodeGeneratorResponse::New() const {
- return new CodeGeneratorResponse;
+CodeGeneratorResponse* CodeGeneratorResponse::New(::google::protobuf::Arena* arena) const {
+ CodeGeneratorResponse* n = new CodeGeneratorResponse;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void CodeGeneratorResponse::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
- if (has_error()) {
- if (error_ != &::google::protobuf::internal::kEmptyString) {
- error_->clear();
- }
- }
+ if (has_error()) {
+ error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorResponse)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string error = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_error()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->error().data(), this->error().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.compiler.CodeGeneratorResponse.error");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(122)) goto parse_file;
break;
}
-
+
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
case 15: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 122) {
parse_file:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_file()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(122)) goto parse_file;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -930,71 +1147,80 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.compiler.CodeGeneratorResponse)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.compiler.CodeGeneratorResponse)
+ return false;
#undef DO_
}
void CodeGeneratorResponse::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.compiler.CodeGeneratorResponse)
// optional string error = 1;
if (has_error()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->error().data(), this->error().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorResponse.error");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->error(), output);
}
-
+
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
- for (int i = 0; i < this->file_size(); i++) {
+ for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
15, this->file(i), output);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorResponse)
}
::google::protobuf::uint8* CodeGeneratorResponse::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse)
// optional string error = 1;
if (has_error()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->error().data(), this->error().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.compiler.CodeGeneratorResponse.error");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->error(), target);
}
-
+
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
- for (int i = 0; i < this->file_size(); i++) {
+ for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
15, this->file(i), target);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse)
return target;
}
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++) {
@@ -1002,8 +1228,8 @@ int CodeGeneratorResponse::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->file(i));
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -1015,7 +1241,7 @@ int CodeGeneratorResponse::ByteSize() const {
}
void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const CodeGeneratorResponse* source =
::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse*>(
&from);
@@ -1027,14 +1253,17 @@ void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) {
}
void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
file_.MergeFrom(from.file_);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_error()) {
- set_error(from.error());
+ set_has_error();
+ error_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 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) {
@@ -1050,18 +1279,20 @@ void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) {
}
bool CodeGeneratorResponse::IsInitialized() const {
-
+
return true;
}
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;
+ 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 {
@@ -1072,6 +1303,256 @@ void CodeGeneratorResponse::Swap(CodeGeneratorResponse* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// CodeGeneratorResponse_File
+
+// optional string name = 1;
+ bool CodeGeneratorResponse_File::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void CodeGeneratorResponse_File::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void CodeGeneratorResponse_File::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void CodeGeneratorResponse_File::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& CodeGeneratorResponse_File::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ void CodeGeneratorResponse_File::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ void CodeGeneratorResponse_File::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+
+// optional string insertion_point = 2;
+ bool CodeGeneratorResponse_File::has_insertion_point() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void CodeGeneratorResponse_File::set_has_insertion_point() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void CodeGeneratorResponse_File::clear_has_insertion_point() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void CodeGeneratorResponse_File::clear_insertion_point() {
+ insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_insertion_point();
+}
+ const ::std::string& CodeGeneratorResponse_File::insertion_point() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+ return insertion_point_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) {
+ set_has_insertion_point();
+ insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const char* value) {
+ set_has_insertion_point();
+ insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) {
+ set_has_insertion_point();
+ insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
+ set_has_insertion_point();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+ return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
+ clear_has_insertion_point();
+ return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) {
+ if (insertion_point != NULL) {
+ set_has_insertion_point();
+ } else {
+ clear_has_insertion_point();
+ }
+ insertion_point_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), insertion_point);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+
+// optional string content = 15;
+ bool CodeGeneratorResponse_File::has_content() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void CodeGeneratorResponse_File::set_has_content() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void CodeGeneratorResponse_File::clear_has_content() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void CodeGeneratorResponse_File::clear_content() {
+ content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_content();
+}
+ const ::std::string& CodeGeneratorResponse_File::content() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+ return content_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_content(const ::std::string& value) {
+ set_has_content();
+ content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ void CodeGeneratorResponse_File::set_content(const char* value) {
+ set_has_content();
+ content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ void CodeGeneratorResponse_File::set_content(const char* value, size_t size) {
+ set_has_content();
+ content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_content() {
+ set_has_content();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+ return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_content() {
+ clear_has_content();
+ return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) {
+ if (content != NULL) {
+ set_has_content();
+ } else {
+ clear_has_content();
+ }
+ content_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), content);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+
+// -------------------------------------------------------------------
+
+// CodeGeneratorResponse
+
+// optional string error = 1;
+ bool CodeGeneratorResponse::has_error() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void CodeGeneratorResponse::set_has_error() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void CodeGeneratorResponse::clear_has_error() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void CodeGeneratorResponse::clear_error() {
+ error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_error();
+}
+ const ::std::string& CodeGeneratorResponse::error() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error)
+ return error_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse::set_error(const ::std::string& value) {
+ set_has_error();
+ error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ void CodeGeneratorResponse::set_error(const char* value) {
+ set_has_error();
+ error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ void CodeGeneratorResponse::set_error(const char* value, size_t size) {
+ set_has_error();
+ error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ ::std::string* CodeGeneratorResponse::mutable_error() {
+ set_has_error();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error)
+ return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse::release_error() {
+ clear_has_error();
+ return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse::set_allocated_error(::std::string* error) {
+ if (error != NULL) {
+ set_has_error();
+ } else {
+ clear_has_error();
+ }
+ error_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+
+// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
+ int CodeGeneratorResponse::file_size() const {
+ return file_.size();
+}
+ void CodeGeneratorResponse::clear_file() {
+ file_.Clear();
+}
+ const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return file_.Get(index);
+}
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return file_.Mutable(index);
+}
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
+ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return file_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
+CodeGeneratorResponse::file() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return file_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
+CodeGeneratorResponse::mutable_file() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+ return &file_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index 14216c2a..ea48b8b5 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -8,21 +8,25 @@
#include <google/protobuf/stubs/common.h>
-#if GOOGLE_PROTOBUF_VERSION < 2004000
+#if GOOGLE_PROTOBUF_VERSION < 3000000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 2004001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
-#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
#include "google/protobuf/descriptor.pb.h"
// @@protoc_insertion_point(includes)
@@ -45,37 +49,39 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
public:
CodeGeneratorRequest();
virtual ~CodeGeneratorRequest();
-
+
CodeGeneratorRequest(const CodeGeneratorRequest& from);
-
+
inline CodeGeneratorRequest& operator=(const CodeGeneratorRequest& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const CodeGeneratorRequest& default_instance();
-
+
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);
void MergeFrom(const CodeGeneratorRequest& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -87,71 +93,77 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(CodeGeneratorRequest* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// repeated string file_to_generate = 1;
- inline int file_to_generate_size() const;
- inline void clear_file_to_generate();
+ int file_to_generate_size() const;
+ void clear_file_to_generate();
static const int kFileToGenerateFieldNumber = 1;
- inline const ::std::string& file_to_generate(int index) const;
- inline ::std::string* mutable_file_to_generate(int index);
- inline void set_file_to_generate(int index, const ::std::string& value);
- inline void set_file_to_generate(int index, const char* value);
- inline void set_file_to_generate(int index, const char* value, size_t size);
- inline ::std::string* add_file_to_generate();
- inline void add_file_to_generate(const ::std::string& value);
- inline void add_file_to_generate(const char* value);
- inline void add_file_to_generate(const char* value, size_t size);
- inline const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
- inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
-
+ const ::std::string& file_to_generate(int index) const;
+ ::std::string* mutable_file_to_generate(int index);
+ void set_file_to_generate(int index, const ::std::string& value);
+ void set_file_to_generate(int index, const char* value);
+ void set_file_to_generate(int index, const char* value, size_t size);
+ ::std::string* add_file_to_generate();
+ void add_file_to_generate(const ::std::string& value);
+ void add_file_to_generate(const char* value);
+ void add_file_to_generate(const char* value, size_t size);
+ const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
+ ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
+
// optional string parameter = 2;
- inline bool has_parameter() const;
- inline void clear_parameter();
+ bool has_parameter() const;
+ void clear_parameter();
static const int kParameterFieldNumber = 2;
- inline const ::std::string& parameter() const;
- inline void set_parameter(const ::std::string& value);
- inline void set_parameter(const char* value);
- inline void set_parameter(const char* value, size_t size);
- inline ::std::string* mutable_parameter();
- inline ::std::string* release_parameter();
-
+ const ::std::string& parameter() const;
+ void set_parameter(const ::std::string& value);
+ void set_parameter(const char* value);
+ void set_parameter(const char* value, size_t size);
+ ::std::string* mutable_parameter();
+ ::std::string* release_parameter();
+ void set_allocated_parameter(::std::string* parameter);
+
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
- inline int proto_file_size() const;
- inline void clear_proto_file();
+ int proto_file_size() const;
+ void clear_proto_file();
static const int kProtoFileFieldNumber = 15;
- inline const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
- inline ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
- inline ::google::protobuf::FileDescriptorProto* add_proto_file();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+ const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
+ ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
+ ::google::protobuf::FileDescriptorProto* add_proto_file();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
proto_file() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
mutable_proto_file();
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
private:
inline void set_has_parameter();
inline void clear_has_parameter();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::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_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
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();
-
+
void InitAsDefaultInstance();
static CodeGeneratorRequest* default_instance_;
};
@@ -161,37 +173,39 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
public:
CodeGeneratorResponse_File();
virtual ~CodeGeneratorResponse_File();
-
+
CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from);
-
+
inline CodeGeneratorResponse_File& operator=(const CodeGeneratorResponse_File& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const CodeGeneratorResponse_File& default_instance();
-
+
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);
void MergeFrom(const CodeGeneratorResponse_File& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -203,47 +217,58 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(CodeGeneratorResponse_File* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
- inline bool has_name() const;
- inline void clear_name();
+ bool has_name() const;
+ void clear_name();
static const int kNameFieldNumber = 1;
- inline const ::std::string& name() const;
- inline void set_name(const ::std::string& value);
- inline void set_name(const char* value);
- inline void set_name(const char* value, size_t size);
- inline ::std::string* mutable_name();
- inline ::std::string* release_name();
-
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void set_allocated_name(::std::string* name);
+
// optional string insertion_point = 2;
- inline bool has_insertion_point() const;
- inline void clear_insertion_point();
+ bool has_insertion_point() const;
+ void clear_insertion_point();
static const int kInsertionPointFieldNumber = 2;
- inline const ::std::string& insertion_point() const;
- inline void set_insertion_point(const ::std::string& value);
- inline void set_insertion_point(const char* value);
- inline void set_insertion_point(const char* value, size_t size);
- inline ::std::string* mutable_insertion_point();
- inline ::std::string* release_insertion_point();
-
+ const ::std::string& insertion_point() const;
+ void set_insertion_point(const ::std::string& value);
+ void set_insertion_point(const char* value);
+ void set_insertion_point(const char* value, size_t size);
+ ::std::string* mutable_insertion_point();
+ ::std::string* release_insertion_point();
+ void set_allocated_insertion_point(::std::string* insertion_point);
+
// optional string content = 15;
- inline bool has_content() const;
- inline void clear_content();
+ bool has_content() const;
+ void clear_content();
static const int kContentFieldNumber = 15;
- inline const ::std::string& content() const;
- inline void set_content(const ::std::string& value);
- inline void set_content(const char* value);
- inline void set_content(const char* value, size_t size);
- inline ::std::string* mutable_content();
- inline ::std::string* release_content();
-
+ const ::std::string& content() const;
+ void set_content(const ::std::string& value);
+ void set_content(const char* value);
+ void set_content(const char* value, size_t size);
+ ::std::string* mutable_content();
+ ::std::string* release_content();
+ void set_allocated_content(::std::string* content);
+
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
private:
inline void set_has_name();
@@ -252,20 +277,17 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
inline void clear_has_insertion_point();
inline void set_has_content();
inline void clear_has_content();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* name_;
- ::std::string* insertion_point_;
- ::std::string* content_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
+ ::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();
-
+
void InitAsDefaultInstance();
static CodeGeneratorResponse_File* default_instance_;
};
@@ -275,37 +297,39 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
public:
CodeGeneratorResponse();
virtual ~CodeGeneratorResponse();
-
+
CodeGeneratorResponse(const CodeGeneratorResponse& from);
-
+
inline CodeGeneratorResponse& operator=(const CodeGeneratorResponse& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const CodeGeneratorResponse& default_instance();
-
+
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);
void MergeFrom(const CodeGeneratorResponse& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -317,56 +341,62 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(CodeGeneratorResponse* other);
+ 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 ----------------------------------------------------
-
+
typedef CodeGeneratorResponse_File File;
-
+
// accessors -------------------------------------------------------
-
+
// optional string error = 1;
- inline bool has_error() const;
- inline void clear_error();
+ bool has_error() const;
+ void clear_error();
static const int kErrorFieldNumber = 1;
- inline const ::std::string& error() const;
- inline void set_error(const ::std::string& value);
- inline void set_error(const char* value);
- inline void set_error(const char* value, size_t size);
- inline ::std::string* mutable_error();
- inline ::std::string* release_error();
-
+ const ::std::string& error() const;
+ void set_error(const ::std::string& value);
+ void set_error(const char* value);
+ void set_error(const char* value, size_t size);
+ ::std::string* mutable_error();
+ ::std::string* release_error();
+ void set_allocated_error(::std::string* error);
+
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
- inline int file_size() const;
- inline void clear_file();
+ int file_size() const;
+ void clear_file();
static const int kFileFieldNumber = 15;
- inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
- inline ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
- inline ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
+ const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
file() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
mutable_file();
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
private:
inline void set_has_error();
inline void clear_has_error();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* error_;
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
-
+ ::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();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
-
+
void InitAsDefaultInstance();
static CodeGeneratorResponse* default_instance_;
};
@@ -375,6 +405,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
// ===================================================================
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
// CodeGeneratorRequest
// repeated string file_to_generate = 1;
@@ -385,39 +416,49 @@ inline void CodeGeneratorRequest::clear_file_to_generate() {
file_to_generate_.Clear();
}
inline const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
return file_to_generate_.Get(index);
}
inline ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
return file_to_generate_.Mutable(index);
}
inline void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
file_to_generate_.Mutable(index)->assign(value);
}
inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) {
file_to_generate_.Mutable(index)->assign(value);
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
}
inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) {
file_to_generate_.Mutable(index)->assign(
reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
}
inline ::std::string* CodeGeneratorRequest::add_file_to_generate() {
return file_to_generate_.Add();
}
inline void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) {
file_to_generate_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
}
inline void CodeGeneratorRequest::add_file_to_generate(const char* value) {
file_to_generate_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
}
inline void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) {
file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_add_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
}
inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
CodeGeneratorRequest::file_to_generate() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
return file_to_generate_;
}
inline ::google::protobuf::RepeatedPtrField< ::std::string>*
CodeGeneratorRequest::mutable_file_to_generate() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
return &file_to_generate_;
}
@@ -432,51 +473,46 @@ inline void CodeGeneratorRequest::clear_has_parameter() {
_has_bits_[0] &= ~0x00000002u;
}
inline void CodeGeneratorRequest::clear_parameter() {
- if (parameter_ != &::google::protobuf::internal::kEmptyString) {
- parameter_->clear();
- }
+ parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_parameter();
}
inline const ::std::string& CodeGeneratorRequest::parameter() const {
- return *parameter_;
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+ return parameter_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) {
set_has_parameter();
- if (parameter_ == &::google::protobuf::internal::kEmptyString) {
- parameter_ = new ::std::string;
- }
- parameter_->assign(value);
+ parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- parameter_ = new ::std::string;
- }
- parameter_->assign(value);
+ parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter)
}
inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) {
set_has_parameter();
- if (parameter_ == &::google::protobuf::internal::kEmptyString) {
- parameter_ = new ::std::string;
- }
- parameter_->assign(reinterpret_cast<const char*>(value), size);
+ parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter)
}
inline ::std::string* CodeGeneratorRequest::mutable_parameter() {
set_has_parameter();
- if (parameter_ == &::google::protobuf::internal::kEmptyString) {
- parameter_ = new ::std::string;
- }
- return parameter_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+ return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* CodeGeneratorRequest::release_parameter() {
clear_has_parameter();
- if (parameter_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) {
+ if (parameter != NULL) {
+ set_has_parameter();
} else {
- ::std::string* temp = parameter_;
- parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_parameter();
}
+ parameter_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), parameter);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter)
}
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
@@ -487,20 +523,25 @@ inline void CodeGeneratorRequest::clear_proto_file() {
proto_file_.Clear();
}
inline const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
return proto_file_.Get(index);
}
inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
return proto_file_.Mutable(index);
}
inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
+ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
return proto_file_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
CodeGeneratorRequest::proto_file() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
return proto_file_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
CodeGeneratorRequest::mutable_proto_file() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
return &proto_file_;
}
@@ -519,51 +560,46 @@ inline void CodeGeneratorResponse_File::clear_has_name() {
_has_bits_[0] &= ~0x00000001u;
}
inline void CodeGeneratorResponse_File::clear_name() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_name();
}
inline const ::std::string& CodeGeneratorResponse_File::name() const {
- return *name_;
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name)
}
inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(reinterpret_cast<const char*>(value), size);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name)
}
inline ::std::string* CodeGeneratorResponse_File::mutable_name() {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- return name_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* CodeGeneratorResponse_File::release_name() {
clear_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
} else {
- ::std::string* temp = name_;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_name();
}
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name)
}
// optional string insertion_point = 2;
@@ -577,51 +613,46 @@ 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::kEmptyString) {
- insertion_point_->clear();
- }
+ insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_insertion_point();
}
inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const {
- return *insertion_point_;
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+ return insertion_point_.GetNoArena(&::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::kEmptyString) {
- insertion_point_ = new ::std::string;
- }
- insertion_point_->assign(value);
+ insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- insertion_point_ = new ::std::string;
- }
- insertion_point_->assign(value);
+ insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@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) {
set_has_insertion_point();
- if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
- insertion_point_ = new ::std::string;
- }
- insertion_point_->assign(reinterpret_cast<const char*>(value), size);
+ insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
}
inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
set_has_insertion_point();
- if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
- insertion_point_ = new ::std::string;
- }
- return insertion_point_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+ return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
clear_has_insertion_point();
- if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) {
+ if (insertion_point != NULL) {
+ set_has_insertion_point();
} else {
- ::std::string* temp = insertion_point_;
- insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_insertion_point();
}
+ insertion_point_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), insertion_point);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
}
// optional string content = 15;
@@ -635,51 +666,46 @@ inline void CodeGeneratorResponse_File::clear_has_content() {
_has_bits_[0] &= ~0x00000004u;
}
inline void CodeGeneratorResponse_File::clear_content() {
- if (content_ != &::google::protobuf::internal::kEmptyString) {
- content_->clear();
- }
+ content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_content();
}
inline const ::std::string& CodeGeneratorResponse_File::content() const {
- return *content_;
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+ return content_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) {
set_has_content();
- if (content_ == &::google::protobuf::internal::kEmptyString) {
- content_ = new ::std::string;
- }
- content_->assign(value);
+ content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- content_ = new ::std::string;
- }
- content_->assign(value);
+ content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content)
}
inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) {
set_has_content();
- if (content_ == &::google::protobuf::internal::kEmptyString) {
- content_ = new ::std::string;
- }
- content_->assign(reinterpret_cast<const char*>(value), size);
+ content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content)
}
inline ::std::string* CodeGeneratorResponse_File::mutable_content() {
set_has_content();
- if (content_ == &::google::protobuf::internal::kEmptyString) {
- content_ = new ::std::string;
- }
- return content_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+ return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* CodeGeneratorResponse_File::release_content() {
clear_has_content();
- if (content_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) {
+ if (content != NULL) {
+ set_has_content();
} else {
- ::std::string* temp = content_;
- content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_content();
}
+ content_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), content);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content)
}
// -------------------------------------------------------------------
@@ -697,51 +723,46 @@ inline void CodeGeneratorResponse::clear_has_error() {
_has_bits_[0] &= ~0x00000001u;
}
inline void CodeGeneratorResponse::clear_error() {
- if (error_ != &::google::protobuf::internal::kEmptyString) {
- error_->clear();
- }
+ error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_error();
}
inline const ::std::string& CodeGeneratorResponse::error() const {
- return *error_;
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error)
+ return error_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void CodeGeneratorResponse::set_error(const ::std::string& value) {
set_has_error();
- if (error_ == &::google::protobuf::internal::kEmptyString) {
- error_ = new ::std::string;
- }
- error_->assign(value);
+ error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- error_ = new ::std::string;
- }
- error_->assign(value);
+ error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error)
}
inline void CodeGeneratorResponse::set_error(const char* value, size_t size) {
set_has_error();
- if (error_ == &::google::protobuf::internal::kEmptyString) {
- error_ = new ::std::string;
- }
- error_->assign(reinterpret_cast<const char*>(value), size);
+ error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error)
}
inline ::std::string* CodeGeneratorResponse::mutable_error() {
set_has_error();
- if (error_ == &::google::protobuf::internal::kEmptyString) {
- error_ = new ::std::string;
- }
- return error_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error)
+ return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* CodeGeneratorResponse::release_error() {
clear_has_error();
- if (error_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void CodeGeneratorResponse::set_allocated_error(::std::string* error) {
+ if (error != NULL) {
+ set_has_error();
} else {
- ::std::string* temp = error_;
- error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_error();
}
+ error_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error)
}
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
@@ -752,23 +773,29 @@ inline void CodeGeneratorResponse::clear_file() {
file_.Clear();
}
inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file)
return file_.Get(index);
}
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file)
return file_.Mutable(index);
}
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
+ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
return file_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
CodeGeneratorResponse::file() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
return file_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
CodeGeneratorResponse::mutable_file() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file)
return &file_;
}
+#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
@@ -776,15 +803,6 @@ CodeGeneratorResponse::mutable_file() {
} // namespace protobuf
} // namespace google
-#ifndef SWIG
-namespace google {
-namespace protobuf {
-
-
-} // namespace google
-} // namespace protobuf
-#endif // SWIG
-
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED
diff --git a/src/google/protobuf/compiler/plugin.proto b/src/google/protobuf/compiler/plugin.proto
index 651ed10c..acaee1f4 100644
--- a/src/google/protobuf/compiler/plugin.proto
+++ b/src/google/protobuf/compiler/plugin.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -44,7 +44,12 @@
// 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";
+
+option go_package = "plugin_go";
import "google/protobuf/descriptor.proto";
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 9b109378..7b3b5fa3 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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.
+//#PY25 compatible generated code for GAE.
+// Copyright 2007 Google Inc. All Rights Reserved.
// Author: robinson@google.com (Will Robinson)
//
// This module outputs pure-Python protocol message classes that will
@@ -42,16 +44,22 @@
// performance-minded Python code leverage the fast C++ implementation
// directly.
+#include <google/protobuf/stubs/hash.h>
#include <limits>
#include <map>
-#include <utility>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
+#include <utility>
#include <vector>
#include <google/protobuf/compiler/python/python_generator.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream.h>
@@ -84,6 +92,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|.
@@ -106,6 +145,12 @@ string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
const char kDescriptorKey[] = "DESCRIPTOR";
+// Does the file have top-level enums?
+inline bool HasTopLevelEnums(const FileDescriptor *file) {
+ return file->enum_type_count() > 0;
+}
+
+
// Should we generate generic services for this file?
inline bool HasGenericServices(const FileDescriptor *file) {
return file->service_count() > 0 &&
@@ -120,13 +165,23 @@ void PrintTopBoilerplate(
// TODO(robinson): Allow parameterization of Python version?
printer->Print(
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
- "\n"
- "from google.protobuf import descriptor\n"
- "from google.protobuf import message\n"
- "from google.protobuf import reflection\n");
+ "# source: $filename$\n"
+ "\nimport sys\n_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))" //##PY25
+ "\n",
+ "filename", file->name());
+ if (HasTopLevelEnums(file)) {
+ printer->Print(
+ "from google.protobuf.internal import enum_type_wrapper\n");
+ }
+ printer->Print(
+ "from google.protobuf import descriptor as _descriptor\n"
+ "from google.protobuf import message as _message\n"
+ "from google.protobuf import reflection as _reflection\n"
+ "from google.protobuf import symbol_database as "
+ "_symbol_database\n");
if (HasGenericServices(file)) {
printer->Print(
- "from google.protobuf import service\n"
+ "from google.protobuf import service as _service\n"
"from google.protobuf import service_reflection\n");
}
@@ -136,7 +191,8 @@ void PrintTopBoilerplate(
"from google.protobuf import descriptor_pb2\n");
}
printer->Print(
- "# @@protoc_insertion_point(imports)\n");
+ "# @@protoc_insertion_point(imports)\n\n"
+ "_sym_db = _symbol_database.Default()\n");
printer->Print("\n\n");
}
@@ -202,12 +258,12 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
case FieldDescriptor::CPPTYPE_ENUM:
return SimpleItoa(field.default_value_enum()->number());
case FieldDescriptor::CPPTYPE_STRING:
- if (field.type() == FieldDescriptor::TYPE_STRING) {
- return "unicode(\"" + CEscape(field.default_value_string()) +
- "\", \"utf-8\")";
- } else {
- return "\"" + CEscape(field.default_value_string()) + "\"";
- }
+//##!PY25 return "b\"" + CEscape(field.default_value_string()) +
+//##!PY25 (field.type() != FieldDescriptor::TYPE_STRING ? "\"" :
+//##!PY25 "\".decode('utf-8')");
+ return "_b(\"" + CEscape(field.default_value_string()) + //##PY25
+ (field.type() != FieldDescriptor::TYPE_STRING ? "\")" : //##PY25
+ "\").decode('utf-8')"); //##PY25
case FieldDescriptor::CPPTYPE_MESSAGE:
return "None";
}
@@ -217,6 +273,19 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
return "";
}
+string StringifySyntax(FileDescriptor::Syntax syntax) {
+ switch (syntax) {
+ case FileDescriptor::SYNTAX_PROTO2:
+ return "proto2";
+ case FileDescriptor::SYNTAX_PROTO3:
+ return "proto3";
+ case FileDescriptor::SYNTAX_UNKNOWN:
+ default:
+ GOOGLE_LOG(FATAL) << "Unsupported syntax; this generator only supports proto2 "
+ "and proto3 syntax.";
+ return "";
+ }
+}
} // namespace
@@ -252,7 +321,7 @@ bool Generator::Generate(const FileDescriptor* file,
fdp.SerializeToString(&file_descriptor_serialized_);
- scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
GOOGLE_CHECK(output.get());
io::Printer printer(output.get(), '$');
printer_ = &printer;
@@ -270,6 +339,11 @@ bool Generator::Generate(const FileDescriptor* file,
// since they need to call static RegisterExtension() methods on these
// classes.
FixForeignFieldsInExtensions();
+ // Descriptor options may have custom extensions. These custom options
+ // can only be successfully parsed after we register corresponding
+ // extensions. Therefore we parse all options again here to recognize
+ // custom options that may be unknown when we define the descriptors.
+ FixAllDescriptorOptions();
if (HasGenericServices(file)) {
PrintServices();
}
@@ -283,9 +357,19 @@ 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");
+
+ // Print public imports.
+ for (int i = 0; i < file_->public_dependency_count(); ++i) {
+ string module_name = ModuleName(file_->public_dependency(i)->name());
+ printer_->Print("from $module$ import *\n", "module", module_name);
}
printer_->Print("\n");
}
@@ -296,21 +380,35 @@ void Generator::PrintFileDescriptor() const {
m["descriptor_name"] = kDescriptorKey;
m["name"] = file_->name();
m["package"] = file_->package();
+ m["syntax"] = StringifySyntax(file_->syntax());
const char file_descriptor_template[] =
- "$descriptor_name$ = descriptor.FileDescriptor(\n"
+ "$descriptor_name$ = _descriptor.FileDescriptor(\n"
" name='$name$',\n"
- " package='$package$',\n";
+ " package='$package$',\n"
+ " syntax='$syntax$',\n";
printer_->Print(m, file_descriptor_template);
printer_->Indent();
printer_->Print(
- "serialized_pb='$value$'",
+//##!PY25 "serialized_pb=b'$value$'\n",
+ "serialized_pb=_b('$value$')\n", //##PY25
"value", strings::CHexEscape(file_descriptor_serialized_));
+ if (file_->dependency_count() != 0) {
+ printer_->Print(",\ndependencies=[");
+ for (int i = 0; i < file_->dependency_count(); ++i) {
+ string module_alias = ModuleAlias(file_->dependency(i)->name());
+ printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
+ module_alias);
+ }
+ printer_->Print("]");
+ }
// TODO(falk): Also print options and fix the message_type, enum_type,
// service and extension later in the generation.
printer_->Outdent();
printer_->Print(")\n");
+ printer_->Print("_sym_db.RegisterFileDescriptor($name$)\n", "name",
+ kDescriptorKey);
printer_->Print("\n");
}
@@ -321,12 +419,17 @@ void Generator::PrintTopLevelEnums() const {
for (int i = 0; i < file_->enum_type_count(); ++i) {
const EnumDescriptor& enum_descriptor = *file_->enum_type(i);
PrintEnum(enum_descriptor);
+ printer_->Print("$name$ = "
+ "enum_type_wrapper.EnumTypeWrapper($descriptor_name$)",
+ "name", enum_descriptor.name(),
+ "descriptor_name",
+ ModuleLevelDescriptorName(enum_descriptor));
printer_->Print("\n");
for (int j = 0; j < enum_descriptor.value_count(); ++j) {
const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(j);
top_level_enum_values.push_back(
- make_pair(value_descriptor.name(), value_descriptor.number()));
+ std::make_pair(value_descriptor.name(), value_descriptor.number()));
}
}
@@ -350,12 +453,14 @@ void Generator::PrintAllNestedEnumsInFile() const {
// enum_descriptor.
void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
map<string, string> m;
- m["descriptor_name"] = ModuleLevelDescriptorName(enum_descriptor);
+ string module_level_descriptor_name =
+ ModuleLevelDescriptorName(enum_descriptor);
+ m["descriptor_name"] = module_level_descriptor_name;
m["name"] = enum_descriptor.name();
m["full_name"] = enum_descriptor.full_name();
m["file"] = kDescriptorKey;
const char enum_descriptor_template[] =
- "$descriptor_name$ = descriptor.EnumDescriptor(\n"
+ "$descriptor_name$ = _descriptor.EnumDescriptor(\n"
" name='$name$',\n"
" full_name='$full_name$',\n"
" filename=None,\n"
@@ -380,6 +485,8 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
PrintSerializedPbInterval(enum_descriptor, edp);
printer_->Outdent();
printer_->Print(")\n");
+ printer_->Print("_sym_db.RegisterEnumDescriptor($name$)\n", "name",
+ module_level_descriptor_name);
printer_->Print("\n");
}
@@ -436,7 +543,7 @@ void Generator::PrintServiceDescriptor(
descriptor.options().SerializeToString(&options_string);
printer_->Print(
- "$service_name$ = descriptor.ServiceDescriptor(\n",
+ "$service_name$ = _descriptor.ServiceDescriptor(\n",
"service_name", service_name);
printer_->Indent();
map<string, string> m;
@@ -459,7 +566,6 @@ void Generator::PrintServiceDescriptor(
printer_->Print("methods=[\n");
for (int i = 0; i < descriptor.method_count(); ++i) {
const MethodDescriptor* method = descriptor.method(i);
- string options_string;
method->options().SerializeToString(&options_string);
m.clear();
@@ -470,7 +576,7 @@ void Generator::PrintServiceDescriptor(
m["input_type"] = ModuleLevelDescriptorName(*(method->input_type()));
m["output_type"] = ModuleLevelDescriptorName(*(method->output_type()));
m["options_value"] = OptionsValue("MethodOptions", options_string);
- printer_->Print("descriptor.MethodDescriptor(\n");
+ printer_->Print("_descriptor.MethodDescriptor(\n");
printer_->Indent();
printer_->Print(
m,
@@ -489,29 +595,38 @@ void Generator::PrintServiceDescriptor(
printer_->Print("])\n\n");
}
+
+void Generator::PrintDescriptorKeyAndModuleName(
+ const ServiceDescriptor& descriptor) const {
+ printer_->Print(
+ "$descriptor_key$ = $descriptor_name$,\n",
+ "descriptor_key", kDescriptorKey,
+ "descriptor_name", ModuleLevelServiceDescriptorName(descriptor));
+ printer_->Print(
+ "__module__ = '$module_name$'\n",
+ "module_name", ModuleName(file_->name()));
+}
+
void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const {
// Print the service.
- printer_->Print("class $class_name$(service.Service):\n",
+ printer_->Print("$class_name$ = service_reflection.GeneratedServiceType("
+ "'$class_name$', (_service.Service,), dict(\n",
"class_name", descriptor.name());
printer_->Indent();
- printer_->Print(
- "__metaclass__ = service_reflection.GeneratedServiceType\n"
- "$descriptor_key$ = $descriptor_name$\n",
- "descriptor_key", kDescriptorKey,
- "descriptor_name", ModuleLevelServiceDescriptorName(descriptor));
+ Generator::PrintDescriptorKeyAndModuleName(descriptor);
+ printer_->Print("))\n\n");
printer_->Outdent();
}
void Generator::PrintServiceStub(const ServiceDescriptor& descriptor) const {
// Print the service stub.
- printer_->Print("class $class_name$_Stub($class_name$):\n",
+ printer_->Print("$class_name$_Stub = "
+ "service_reflection.GeneratedServiceStubType("
+ "'$class_name$_Stub', ($class_name$,), dict(\n",
"class_name", descriptor.name());
printer_->Indent();
- printer_->Print(
- "__metaclass__ = service_reflection.GeneratedServiceStubType\n"
- "$descriptor_key$ = $descriptor_name$\n",
- "descriptor_key", kDescriptorKey,
- "descriptor_name", ModuleLevelServiceDescriptorName(descriptor));
+ Generator::PrintDescriptorKeyAndModuleName(descriptor);
+ printer_->Print("))\n\n");
printer_->Outdent();
}
@@ -523,7 +638,7 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const {
PrintNestedDescriptors(message_descriptor);
printer_->Print("\n");
- printer_->Print("$descriptor_name$ = descriptor.Descriptor(\n",
+ printer_->Print("$descriptor_name$ = _descriptor.Descriptor(\n",
"descriptor_name",
ModuleLevelDescriptorName(message_descriptor));
printer_->Indent();
@@ -565,10 +680,12 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const {
message_descriptor.options().SerializeToString(&options_string);
printer_->Print(
"options=$options_value$,\n"
- "is_extendable=$extendable$",
+ "is_extendable=$extendable$,\n"
+ "syntax='$syntax$'",
"options_value", OptionsValue("MessageOptions", options_string),
"extendable", message_descriptor.extension_range_count() > 0 ?
- "True" : "False");
+ "True" : "False",
+ "syntax", StringifySyntax(message_descriptor.file()->syntax()));
printer_->Print(",\n");
// Extension ranges
@@ -581,7 +698,22 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const {
"end", SimpleItoa(range->end));
}
printer_->Print("],\n");
-
+ printer_->Print("oneofs=[\n");
+ printer_->Indent();
+ for (int i = 0; i < message_descriptor.oneof_decl_count(); ++i) {
+ const OneofDescriptor* desc = message_descriptor.oneof_decl(i);
+ map<string, string> m;
+ m["name"] = desc->name();
+ m["full_name"] = desc->full_name();
+ m["index"] = SimpleItoa(desc->index());
+ printer_->Print(
+ m,
+ "_descriptor.OneofDescriptor(\n"
+ " name='$name$', full_name='$full_name$',\n"
+ " index=$index$, containing_type=None, fields=[]),\n");
+ }
+ printer_->Outdent();
+ printer_->Print("],\n");
// Serialization of proto
DescriptorProto edp;
PrintSerializedPbInterval(message_descriptor, edp);
@@ -604,7 +736,12 @@ void Generator::PrintNestedDescriptors(
// Prints all messages in |file|.
void Generator::PrintMessages() const {
for (int i = 0; i < file_->message_type_count(); ++i) {
- PrintMessage(*file_->message_type(i));
+ vector<string> to_register;
+ PrintMessage(*file_->message_type(i), "", &to_register);
+ for (int j = 0; j < to_register.size(); ++j) {
+ printer_->Print("_sym_db.RegisterMessage($name$)\n", "name",
+ to_register[j]);
+ }
printer_->Print("\n");
}
}
@@ -616,33 +753,40 @@ void Generator::PrintMessages() const {
// reflection.py will use to construct the meat of the class itself.
//
// Mutually recursive with PrintNestedMessages().
-void Generator::PrintMessage(
- const Descriptor& message_descriptor) const {
- printer_->Print("class $name$(message.Message):\n", "name",
- message_descriptor.name());
+// Collect nested message names to_register for the symbol_database.
+void Generator::PrintMessage(const Descriptor& message_descriptor,
+ const string& prefix,
+ vector<string>* to_register) const {
+ string qualified_name(prefix + message_descriptor.name());
+ to_register->push_back(qualified_name);
+ printer_->Print(
+ "$name$ = _reflection.GeneratedProtocolMessageType('$name$', "
+ "(_message.Message,), dict(\n",
+ "name", message_descriptor.name());
printer_->Indent();
- printer_->Print("__metaclass__ = reflection.GeneratedProtocolMessageType\n");
- PrintNestedMessages(message_descriptor);
+
+ PrintNestedMessages(message_descriptor, qualified_name + ".", to_register);
map<string, string> m;
m["descriptor_key"] = kDescriptorKey;
m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor);
- printer_->Print(m, "$descriptor_key$ = $descriptor_name$\n");
-
- printer_->Print(
- "\n"
- "# @@protoc_insertion_point(class_scope:$full_name$)\n",
- "full_name", message_descriptor.full_name());
-
+ printer_->Print(m, "$descriptor_key$ = $descriptor_name$,\n");
+ printer_->Print("__module__ = '$module_name$'\n",
+ "module_name", ModuleName(file_->name()));
+ printer_->Print("# @@protoc_insertion_point(class_scope:$full_name$)\n",
+ "full_name", message_descriptor.full_name());
+ printer_->Print("))\n");
printer_->Outdent();
}
// Prints all nested messages within |containing_descriptor|.
// Mutually recursive with PrintMessage().
-void Generator::PrintNestedMessages(
- const Descriptor& containing_descriptor) const {
+void Generator::PrintNestedMessages(const Descriptor& containing_descriptor,
+ const string& prefix,
+ vector<string>* to_register) const {
for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) {
printer_->Print("\n");
- PrintMessage(*containing_descriptor.nested_type(i));
+ PrintMessage(*containing_descriptor.nested_type(i), prefix, to_register);
+ printer_->Print(",\n");
}
}
@@ -670,6 +814,23 @@ void Generator::FixForeignFieldsInDescriptor(
const EnumDescriptor& enum_descriptor = *descriptor.enum_type(i);
FixContainingTypeInDescriptor(enum_descriptor, &descriptor);
}
+ for (int i = 0; i < descriptor.oneof_decl_count(); ++i) {
+ map<string, string> m;
+ const OneofDescriptor* oneof = descriptor.oneof_decl(i);
+ m["descriptor_name"] = ModuleLevelDescriptorName(descriptor);
+ m["oneof_name"] = oneof->name();
+ for (int j = 0; j < oneof->field_count(); ++j) {
+ m["field_name"] = oneof->field(j)->name();
+ printer_->Print(
+ m,
+ "$descriptor_name$.oneofs_by_name['$oneof_name$'].fields.append(\n"
+ " $descriptor_name$.fields_by_name['$field_name$'])\n");
+ printer_->Print(
+ m,
+ "$descriptor_name$.fields_by_name['$field_name$'].containing_oneof = "
+ "$descriptor_name$.oneofs_by_name['$oneof_name$']\n");
+ }
+ }
}
void Generator::AddMessageToFileDescriptor(const Descriptor& descriptor) const {
@@ -683,6 +844,29 @@ void Generator::AddMessageToFileDescriptor(const Descriptor& descriptor) const {
printer_->Print(m, file_descriptor_template);
}
+void Generator::AddEnumToFileDescriptor(
+ const EnumDescriptor& descriptor) const {
+ map<string, string> m;
+ m["descriptor_name"] = kDescriptorKey;
+ m["enum_name"] = descriptor.name();
+ m["enum_descriptor_name"] = ModuleLevelDescriptorName(descriptor);
+ const char file_descriptor_template[] =
+ "$descriptor_name$.enum_types_by_name['$enum_name$'] = "
+ "$enum_descriptor_name$\n";
+ printer_->Print(m, file_descriptor_template);
+}
+
+void Generator::AddExtensionToFileDescriptor(
+ const FieldDescriptor& descriptor) const {
+ map<string, string> m;
+ m["descriptor_name"] = kDescriptorKey;
+ m["field_name"] = descriptor.name();
+ const char file_descriptor_template[] =
+ "$descriptor_name$.extensions_by_name['$field_name$'] = "
+ "$field_name$\n";
+ printer_->Print(m, file_descriptor_template);
+}
+
// Sets any necessary message_type and enum_type attributes
// for the Python version of |field|.
//
@@ -747,7 +931,7 @@ void Generator::FixContainingTypeInDescriptor(
const string parent_name = ModuleLevelDescriptorName(
*containing_descriptor);
printer_->Print(
- "$nested_name$.containing_type = $parent_name$;\n",
+ "$nested_name$.containing_type = $parent_name$\n",
"nested_name", nested_name,
"parent_name", parent_name);
}
@@ -764,6 +948,12 @@ void Generator::FixForeignFieldsInDescriptors() const {
for (int i = 0; i < file_->message_type_count(); ++i) {
AddMessageToFileDescriptor(*file_->message_type(i));
}
+ for (int i = 0; i < file_->enum_type_count(); ++i) {
+ AddEnumToFileDescriptor(*file_->enum_type(i));
+ }
+ for (int i = 0; i < file_->extension_count(); ++i) {
+ AddExtensionToFileDescriptor(*file_->extension(i));
+ }
printer_->Print("\n");
}
@@ -779,6 +969,7 @@ void Generator::FixForeignFieldsInExtensions() const {
for (int i = 0; i < file_->message_type_count(); ++i) {
FixForeignFieldsInNestedExtensions(*file_->message_type(i));
}
+ printer_->Print("\n");
}
void Generator::FixForeignFieldsInExtension(
@@ -829,7 +1020,7 @@ void Generator::PrintEnumValueDescriptor(
m["options"] = OptionsValue("EnumValueOptions", options_string);
printer_->Print(
m,
- "descriptor.EnumValueDescriptor(\n"
+ "_descriptor.EnumValueDescriptor(\n"
" name='$name$', index=$index$, number=$number$,\n"
" options=$options$,\n"
" type=None)");
@@ -843,8 +1034,10 @@ string Generator::OptionsValue(
return "None";
} else {
string full_class_name = "descriptor_pb2." + class_name;
- return "descriptor._ParseOptions(" + full_class_name + "(), '"
- + CEscape(serialized_options)+ "')";
+//##!PY25 return "_descriptor._ParseOptions(" + full_class_name + "(), b'"
+//##!PY25 + CEscape(serialized_options)+ "')";
+ return "_descriptor._ParseOptions(" + full_class_name + "(), _b('" //##PY25
+ + CEscape(serialized_options)+ "'))"; //##PY25
}
}
@@ -869,7 +1062,7 @@ void Generator::PrintFieldDescriptor(
// these fields in correctly after all referenced descriptors have been
// defined and/or imported (see FixForeignFieldsInDescriptors()).
const char field_descriptor_decl[] =
- "descriptor.FieldDescriptor(\n"
+ "_descriptor.FieldDescriptor(\n"
" name='$name$', full_name='$full_name$', index=$index$,\n"
" number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n"
" has_default_value=$has_default_value$, default_value=$default_value$,\n"
@@ -947,7 +1140,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;
}
@@ -959,7 +1152,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;
}
@@ -972,7 +1165,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;
}
@@ -1000,6 +1193,137 @@ void Generator::PrintSerializedPbInterval(
"serialized_end", SimpleItoa(offset + sp.size()));
}
+namespace {
+void PrintDescriptorOptionsFixingCode(const string& descriptor,
+ const string& options,
+ io::Printer* printer) {
+ // TODO(xiaofeng): I have added a method _SetOptions() to DescriptorBase
+ // in proto2 python runtime but it couldn't be used here because appengine
+ // uses a snapshot version of the library in which the new method is not
+ // yet present. After appengine has synced their runtime library, the code
+ // below should be cleaned up to use _SetOptions().
+ printer->Print(
+ "$descriptor$.has_options = True\n"
+ "$descriptor$._options = $options$\n",
+ "descriptor", descriptor, "options", options);
+}
+} // namespace
+
+// Prints expressions that set the options field of all descriptors.
+void Generator::FixAllDescriptorOptions() const {
+ // Prints an expression that sets the file descriptor's options.
+ string file_options = OptionsValue(
+ "FileOptions", file_->options().SerializeAsString());
+ if (file_options != "None") {
+ PrintDescriptorOptionsFixingCode(kDescriptorKey, file_options, printer_);
+ }
+ // Prints expressions that set the options for all top level enums.
+ for (int i = 0; i < file_->enum_type_count(); ++i) {
+ const EnumDescriptor& enum_descriptor = *file_->enum_type(i);
+ FixOptionsForEnum(enum_descriptor);
+ }
+ // Prints expressions that set the options for all top level extensions.
+ for (int i = 0; i < file_->extension_count(); ++i) {
+ const FieldDescriptor& field = *file_->extension(i);
+ FixOptionsForField(field);
+ }
+ // Prints expressions that set the options for all messages, nested enums,
+ // nested extensions and message fields.
+ for (int i = 0; i < file_->message_type_count(); ++i) {
+ FixOptionsForMessage(*file_->message_type(i));
+ }
+}
+
+// Prints expressions that set the options for an enum descriptor and its
+// value descriptors.
+void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const {
+ string descriptor_name = ModuleLevelDescriptorName(enum_descriptor);
+ string enum_options = OptionsValue(
+ "EnumOptions", enum_descriptor.options().SerializeAsString());
+ if (enum_options != "None") {
+ PrintDescriptorOptionsFixingCode(descriptor_name, enum_options, printer_);
+ }
+ for (int i = 0; i < enum_descriptor.value_count(); ++i) {
+ const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(i);
+ string value_options = OptionsValue(
+ "EnumValueOptions", value_descriptor.options().SerializeAsString());
+ if (value_options != "None") {
+ PrintDescriptorOptionsFixingCode(
+ StringPrintf("%s.values_by_name[\"%s\"]", descriptor_name.c_str(),
+ value_descriptor.name().c_str()),
+ value_options, printer_);
+ }
+ }
+}
+
+// Prints expressions that set the options for field descriptors (including
+// extensions).
+void Generator::FixOptionsForField(
+ const FieldDescriptor& field) const {
+ string field_options = OptionsValue(
+ "FieldOptions", field.options().SerializeAsString());
+ if (field_options != "None") {
+ string field_name;
+ if (field.is_extension()) {
+ if (field.extension_scope() == NULL) {
+ // Top level extensions.
+ field_name = field.name();
+ } else {
+ field_name = FieldReferencingExpression(
+ field.extension_scope(), field, "extensions_by_name");
+ }
+ } else {
+ field_name = FieldReferencingExpression(
+ field.containing_type(), field, "fields_by_name");
+ }
+ PrintDescriptorOptionsFixingCode(field_name, field_options, printer_);
+ }
+}
+
+// Prints expressions that set the options for a message and all its inner
+// types (nested messages, nested enums, extensions, fields).
+void Generator::FixOptionsForMessage(const Descriptor& descriptor) const {
+ // Nested messages.
+ for (int i = 0; i < descriptor.nested_type_count(); ++i) {
+ FixOptionsForMessage(*descriptor.nested_type(i));
+ }
+ // Enums.
+ for (int i = 0; i < descriptor.enum_type_count(); ++i) {
+ FixOptionsForEnum(*descriptor.enum_type(i));
+ }
+ // Fields.
+ for (int i = 0; i < descriptor.field_count(); ++i) {
+ const FieldDescriptor& field = *descriptor.field(i);
+ FixOptionsForField(field);
+ }
+ // Extensions.
+ for (int i = 0; i < descriptor.extension_count(); ++i) {
+ const FieldDescriptor& field = *descriptor.extension(i);
+ FixOptionsForField(field);
+ }
+ // Message option for this message.
+ string message_options = OptionsValue(
+ "MessageOptions", descriptor.options().SerializeAsString());
+ if (message_options != "None") {
+ string descriptor_name = ModuleLevelDescriptorName(descriptor);
+ PrintDescriptorOptionsFixingCode(descriptor_name,
+ message_options,
+ printer_);
+ }
+}
+
+// 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 84eaf8ab..2ddac601 100644
--- a/src/google/protobuf/compiler/python/python_generator.h
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -94,8 +94,11 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
void PrintNestedDescriptors(const Descriptor& containing_descriptor) const;
void PrintMessages() const;
- void PrintMessage(const Descriptor& message_descriptor) const;
- void PrintNestedMessages(const Descriptor& containing_descriptor) const;
+ void PrintMessage(const Descriptor& message_descriptor, const string& prefix,
+ vector<string>* to_register) const;
+ void PrintNestedMessages(const Descriptor& containing_descriptor,
+ const string& prefix,
+ vector<string>* to_register) const;
void FixForeignFieldsInDescriptors() const;
void FixForeignFieldsInDescriptor(
@@ -105,6 +108,8 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
const FieldDescriptor& field,
const string& python_dict_name) const;
void AddMessageToFileDescriptor(const Descriptor& descriptor) const;
+ void AddEnumToFileDescriptor(const EnumDescriptor& descriptor) const;
+ void AddExtensionToFileDescriptor(const FieldDescriptor& descriptor) const;
string FieldReferencingExpression(const Descriptor* containing_type,
const FieldDescriptor& field,
const string& python_dict_name) const;
@@ -122,6 +127,8 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
void PrintServiceDescriptor(const ServiceDescriptor& descriptor) const;
void PrintServiceClass(const ServiceDescriptor& descriptor) const;
void PrintServiceStub(const ServiceDescriptor& descriptor) const;
+ void PrintDescriptorKeyAndModuleName(
+ const ServiceDescriptor& descriptor) const ;
void PrintEnumValueDescriptor(const EnumValueDescriptor& descriptor) const;
string OptionsValue(const string& class_name,
@@ -138,6 +145,14 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
void PrintSerializedPbInterval(
const DescriptorT& descriptor, DescriptorProtoT& proto) const;
+ void FixAllDescriptorOptions() const;
+ void FixOptionsForField(const FieldDescriptor& field) const;
+ 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 da619ad3..e82bbae7 100644
--- a/src/google/protobuf/compiler/python/python_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/python/python_plugin_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,6 +34,11 @@
// It seemed like parameterizing it would add more complexity than it is
// worth.
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
#include <google/protobuf/compiler/python/python_generator.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/io/zero_copy_stream.h>
@@ -67,8 +72,8 @@ class TestGenerator : public CodeGenerator {
void TryInsert(const string& filename, const string& insertion_point,
GeneratorContext* context) const {
- scoped_ptr<io::ZeroCopyOutputStream> output(
- context->OpenForInsert(filename, insertion_point));
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->OpenForInsert(filename, insertion_point));
io::Printer printer(output.get(), '$');
printer.Print("// inserted $name$\n", "name", insertion_point);
}
@@ -78,13 +83,13 @@ class TestGenerator : public CodeGenerator {
// not verify that they are correctly-placed; that would require actually
// compiling the output which is a bit more than I care to do for this test.
TEST(PythonPluginTest, PluginTest) {
- File::WriteStringToFileOrDie(
- "syntax = \"proto2\";\n"
- "package foo;\n"
- "message Bar {\n"
- " message Baz {}\n"
- "}\n",
- TestTempDir() + "/test.proto");
+ GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
+ "syntax = \"proto2\";\n"
+ "package foo;\n"
+ "message Bar {\n"
+ " message Baz {}\n"
+ "}\n",
+ true));
google::protobuf::compiler::CommandLineInterface cli;
cli.SetInputsAreProtoPathRelative(true);
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc
new file mode 100644
index 00000000..a9b6837e
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc
@@ -0,0 +1,393 @@
+// 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 <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+
+// Forward decls.
+std::string IntToString(uint32 value);
+std::string StripDotProto(const std::string& proto_file);
+std::string LabelForField(google::protobuf::FieldDescriptor* field);
+std::string TypeName(google::protobuf::FieldDescriptor* field);
+void GenerateMessage(const google::protobuf::Descriptor* message,
+ google::protobuf::io::Printer* printer);
+void GenerateEnum(const google::protobuf::EnumDescriptor* en,
+ google::protobuf::io::Printer* printer);
+void GenerateMessageAssignment(
+ const std::string& prefix,
+ const google::protobuf::Descriptor* message,
+ google::protobuf::io::Printer* printer);
+void GenerateEnumAssignment(
+ const std::string& prefix,
+ const google::protobuf::EnumDescriptor* en,
+ google::protobuf::io::Printer* printer);
+
+std::string IntToString(uint32 value) {
+ std::ostringstream os;
+ os << value;
+ return os.str();
+}
+
+std::string StripDotProto(const std::string& proto_file) {
+ int lastindex = proto_file.find_last_of(".");
+ return proto_file.substr(0, lastindex);
+}
+
+std::string LabelForField(const google::protobuf::FieldDescriptor* field) {
+ switch (field->label()) {
+ case FieldDescriptor::LABEL_OPTIONAL: return "optional";
+ case FieldDescriptor::LABEL_REQUIRED: return "required";
+ case FieldDescriptor::LABEL_REPEATED: return "repeated";
+ default: assert(false); return "";
+ }
+}
+
+std::string TypeName(const google::protobuf::FieldDescriptor* field) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: return "int32";
+ case FieldDescriptor::CPPTYPE_INT64: return "int64";
+ case FieldDescriptor::CPPTYPE_UINT32: return "uint32";
+ case FieldDescriptor::CPPTYPE_UINT64: return "uint64";
+ case FieldDescriptor::CPPTYPE_DOUBLE: return "double";
+ case FieldDescriptor::CPPTYPE_FLOAT: return "float";
+ case FieldDescriptor::CPPTYPE_BOOL: return "bool";
+ case FieldDescriptor::CPPTYPE_ENUM: return "enum";
+ case FieldDescriptor::CPPTYPE_STRING: return "string";
+ case FieldDescriptor::CPPTYPE_MESSAGE: return "message";
+ default: assert(false); return "";
+ }
+}
+
+void GenerateField(const google::protobuf::FieldDescriptor* field,
+ google::protobuf::io::Printer* printer) {
+
+ if (field->is_map()) {
+ const FieldDescriptor* key_field =
+ field->message_type()->FindFieldByNumber(1);
+ const FieldDescriptor* value_field =
+ field->message_type()->FindFieldByNumber(2);
+
+ printer->Print(
+ "map :$name$, :$key_type$, :$value_type$, $number$",
+ "name", field->name(),
+ "key_type", TypeName(key_field),
+ "value_type", TypeName(value_field),
+ "number", IntToString(field->number()));
+
+ if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ ", \"$subtype$\"\n",
+ "subtype", value_field->message_type()->full_name());
+ } else if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+ printer->Print(
+ ", \"$subtype$\"\n",
+ "subtype", value_field->enum_type()->full_name());
+ } else {
+ printer->Print("\n");
+ }
+ } else {
+
+ printer->Print(
+ "$label$ :$name$, ",
+ "label", LabelForField(field),
+ "name", field->name());
+ printer->Print(
+ ":$type$, $number$",
+ "type", TypeName(field),
+ "number", IntToString(field->number()));
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ ", \"$subtype$\"\n",
+ "subtype", field->message_type()->full_name());
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+ printer->Print(
+ ", \"$subtype$\"\n",
+ "subtype", field->enum_type()->full_name());
+ } else {
+ printer->Print("\n");
+ }
+ }
+}
+
+void GenerateOneof(const google::protobuf::OneofDescriptor* oneof,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "oneof :$name$ do\n",
+ "name", oneof->name());
+ printer->Indent();
+
+ for (int i = 0; i < oneof->field_count(); i++) {
+ const FieldDescriptor* field = oneof->field(i);
+ GenerateField(field, printer);
+ }
+
+ printer->Outdent();
+ printer->Print("end\n");
+}
+
+void GenerateMessage(const google::protobuf::Descriptor* message,
+ google::protobuf::io::Printer* printer) {
+
+ // Don't generate MapEntry messages -- we use the Ruby extension's native
+ // support for map fields instead.
+ if (message->options().map_entry()) {
+ return;
+ }
+
+ printer->Print(
+ "add_message \"$name$\" do\n",
+ "name", message->full_name());
+ printer->Indent();
+
+ for (int i = 0; i < message->field_count(); i++) {
+ const FieldDescriptor* field = message->field(i);
+ if (!field->containing_oneof()) {
+ GenerateField(field, printer);
+ }
+ }
+
+ for (int i = 0; i < message->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof = message->oneof_decl(i);
+ GenerateOneof(oneof, printer);
+ }
+
+ printer->Outdent();
+ printer->Print("end\n");
+
+ for (int i = 0; i < message->nested_type_count(); i++) {
+ GenerateMessage(message->nested_type(i), printer);
+ }
+ for (int i = 0; i < message->enum_type_count(); i++) {
+ GenerateEnum(message->enum_type(i), printer);
+ }
+}
+
+void GenerateEnum(const google::protobuf::EnumDescriptor* en,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "add_enum \"$name$\" do\n",
+ "name", en->full_name());
+ printer->Indent();
+
+ for (int i = 0; i < en->value_count(); i++) {
+ const EnumValueDescriptor* value = en->value(i);
+ printer->Print(
+ "value :$name$, $number$\n",
+ "name", value->name(),
+ "number", IntToString(value->number()));
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "end\n");
+}
+
+// Module names, class names, and enum value names need to be Ruby constants,
+// which must start with a capital letter.
+std::string RubifyConstant(const std::string& name) {
+ std::string ret = name;
+ if (!ret.empty()) {
+ if (ret[0] >= 'a' && ret[0] <= 'z') {
+ // If it starts with a lowercase letter, capitalize it.
+ ret[0] = ret[0] - 'a' + 'A';
+ } else if (ret[0] < 'A' || ret[0] > 'Z') {
+ // Otherwise (e.g. if it begins with an underscore), we need to come up
+ // with some prefix that starts with a capital letter. We could be smarter
+ // here, e.g. try to strip leading underscores, but this may cause other
+ // problems if the user really intended the name. So let's just prepend a
+ // well-known suffix.
+ ret = "PB_" + ret;
+ }
+ }
+ return ret;
+}
+
+void GenerateMessageAssignment(
+ const std::string& prefix,
+ const google::protobuf::Descriptor* message,
+ google::protobuf::io::Printer* printer) {
+
+ // Don't generate MapEntry messages -- we use the Ruby extension's native
+ // support for map fields instead.
+ if (message->options().map_entry()) {
+ return;
+ }
+
+ printer->Print(
+ "$prefix$$name$ = ",
+ "prefix", prefix,
+ "name", RubifyConstant(message->name()));
+ printer->Print(
+ "Google::Protobuf::DescriptorPool.generated_pool."
+ "lookup(\"$full_name$\").msgclass\n",
+ "full_name", message->full_name());
+
+ std::string nested_prefix = prefix + message->name() + "::";
+ for (int i = 0; i < message->nested_type_count(); i++) {
+ GenerateMessageAssignment(nested_prefix, message->nested_type(i), printer);
+ }
+ for (int i = 0; i < message->enum_type_count(); i++) {
+ GenerateEnumAssignment(nested_prefix, message->enum_type(i), printer);
+ }
+}
+
+void GenerateEnumAssignment(
+ const std::string& prefix,
+ const google::protobuf::EnumDescriptor* en,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "$prefix$$name$ = ",
+ "prefix", prefix,
+ "name", RubifyConstant(en->name()));
+ printer->Print(
+ "Google::Protobuf::DescriptorPool.generated_pool."
+ "lookup(\"$full_name$\").enummodule\n",
+ "full_name", en->full_name());
+}
+
+int GeneratePackageModules(
+ std::string package_name,
+ google::protobuf::io::Printer* printer) {
+ int levels = 0;
+ while (!package_name.empty()) {
+ size_t dot_index = package_name.find(".");
+ string component;
+ if (dot_index == string::npos) {
+ component = package_name;
+ package_name = "";
+ } else {
+ component = package_name.substr(0, dot_index);
+ package_name = package_name.substr(dot_index + 1);
+ }
+ component = RubifyConstant(component);
+ printer->Print(
+ "module $name$\n",
+ "name", component);
+ printer->Indent();
+ levels++;
+ }
+ return levels;
+}
+
+void EndPackageModules(
+ int levels,
+ google::protobuf::io::Printer* printer) {
+ while (levels > 0) {
+ levels--;
+ printer->Outdent();
+ printer->Print(
+ "end\n");
+ }
+}
+
+void GenerateFile(const google::protobuf::FileDescriptor* file,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "# source: $filename$\n"
+ "\n",
+ "filename", file->name());
+
+ printer->Print(
+ "require 'google/protobuf'\n\n");
+
+ for (int i = 0; i < file->dependency_count(); i++) {
+ const std::string& name = file->dependency(i)->name();
+ printer->Print(
+ "require '$name$'\n", "name", StripDotProto(name));
+ }
+
+ printer->Print(
+ "Google::Protobuf::DescriptorPool.generated_pool.build do\n");
+ printer->Indent();
+ for (int i = 0; i < file->message_type_count(); i++) {
+ GenerateMessage(file->message_type(i), printer);
+ }
+ for (int i = 0; i < file->enum_type_count(); i++) {
+ GenerateEnum(file->enum_type(i), printer);
+ }
+ printer->Outdent();
+ printer->Print(
+ "end\n\n");
+
+ int levels = GeneratePackageModules(file->package(), printer);
+ for (int i = 0; i < file->message_type_count(); i++) {
+ GenerateMessageAssignment("", file->message_type(i), printer);
+ }
+ for (int i = 0; i < file->enum_type_count(); i++) {
+ GenerateEnumAssignment("", file->enum_type(i), printer);
+ }
+ EndPackageModules(levels, printer);
+}
+
+bool Generator::Generate(
+ const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* generator_context,
+ string* error) const {
+
+ if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
+ *error =
+ "Can only generate Ruby code for proto3 .proto files.\n"
+ "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n";
+ return false;
+ }
+
+ std::string filename =
+ StripDotProto(file->name()) + ".rb";
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(filename));
+ io::Printer printer(output.get(), '$');
+
+ GenerateFile(file, &printer);
+
+ return true;
+}
+
+} // namespace ruby
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.h b/src/google/protobuf/compiler/ruby/ruby_generator.h
new file mode 100644
index 00000000..75555c31
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.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_COMPILER_RUBY_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+
+class LIBPROTOC_EXPORT Generator
+ : public google::protobuf::compiler::CodeGenerator {
+ virtual bool Generate(
+ const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* generator_context,
+ string* error) const;
+};
+
+} // namespace ruby
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__
+
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
new file mode 100644
index 00000000..e35ca695
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -0,0 +1,119 @@
+// 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.
+
+#include <memory>
+
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/printer.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/testing/file.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+namespace {
+
+string FindRubyTestDir() {
+ // Inspired by TestSourceDir() in src/google/protobuf/testing/googletest.cc.
+ string prefix = ".";
+ while (!File::Exists(prefix + "/ruby/tests")) {
+ if (!File::Exists(prefix)) {
+ GOOGLE_LOG(FATAL)
+ << "Could not find Ruby test directory. Please run tests from "
+ "somewhere within the protobuf source package.";
+ }
+ prefix += "/..";
+ }
+ return prefix + "/ruby/tests";
+}
+
+// This test is a simple golden-file test over the output of the Ruby code
+// generator. When we make changes to the Ruby extension and alter the Ruby code
+// generator to use those changes, we should (i) manually test the output of the
+// code generator with the extension, and (ii) update the golden output above.
+// Some day, we may integrate build systems between protoc and the language
+// extensions to the point where we can do this test in a more automated way.
+
+TEST(RubyGeneratorTest, GeneratorTest) {
+ string ruby_tests = FindRubyTestDir();
+
+ google::protobuf::compiler::CommandLineInterface cli;
+ cli.SetInputsAreProtoPathRelative(true);
+
+ ruby::Generator ruby_generator;
+ cli.RegisterGenerator("--ruby_out", &ruby_generator, "");
+
+ // Copy generated_code.proto to the temporary test directory.
+ string test_input;
+ GOOGLE_CHECK_OK(File::GetContents(
+ ruby_tests + "/generated_code.proto",
+ &test_input,
+ true));
+ GOOGLE_CHECK_OK(File::SetContents(
+ TestTempDir() + "/generated_code.proto",
+ test_input,
+ true));
+
+ // Invoke the proto compiler (we will be inside TestTempDir() at this point).
+ string ruby_out = "--ruby_out=" + TestTempDir();
+ string proto_path = "--proto_path=" + TestTempDir();
+ const char* argv[] = {
+ "protoc",
+ ruby_out.c_str(),
+ proto_path.c_str(),
+ "generated_code.proto",
+ };
+
+ EXPECT_EQ(0, cli.Run(4, argv));
+
+ // Load the generated output and compare to the expected result.
+ string output;
+ GOOGLE_CHECK_OK(File::GetContents(
+ TestTempDir() + "/generated_code.rb",
+ &output,
+ true));
+ string expected_output;
+ GOOGLE_CHECK_OK(File::GetContents(
+ ruby_tests + "/generated_code.rb",
+ &expected_output,
+ true));
+ EXPECT_EQ(expected_output, output);
+}
+
+} // namespace
+} // namespace ruby
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 5fb5d5cb..61ae4381 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,6 +33,7 @@
#include <google/protobuf/compiler/subprocess.h>
#include <algorithm>
+#include <iostream>
#ifndef _WIN32
#include <errno.h>
@@ -294,8 +295,8 @@ void Subprocess::Start(const string& program, SearchMode search_mode) {
int stdin_pipe[2];
int stdout_pipe[2];
- pipe(stdin_pipe);
- pipe(stdout_pipe);
+ GOOGLE_CHECK(pipe(stdin_pipe) != -1);
+ GOOGLE_CHECK(pipe(stdout_pipe) != -1);
char* argv[2] = { strdup(program.c_str()), NULL };
@@ -323,9 +324,11 @@ void Subprocess::Start(const string& program, SearchMode search_mode) {
// Write directly to STDERR_FILENO to avoid stdio code paths that may do
// stuff that is unsafe here.
- write(STDERR_FILENO, argv[0], strlen(argv[0]));
+ int ignored;
+ ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
const char* message = ": program not found or is not executable\n";
- write(STDERR_FILENO, message, strlen(message));
+ ignored = write(STDERR_FILENO, message, strlen(message));
+ (void) ignored;
// Must use _exit() rather than exit() to avoid flushing output buffers
// that will also be flushed by the parent.
@@ -446,7 +449,7 @@ bool Subprocess::Communicate(const Message& input, Message* output,
}
if (!output->ParseFromString(output_data)) {
- *error = "Plugin output is unparseable.";
+ *error = "Plugin output is unparseable: " + CEscape(output_data);
return false;
}
diff --git a/src/google/protobuf/compiler/subprocess.h b/src/google/protobuf/compiler/subprocess.h
index de9fce9e..25138631 100644
--- a/src/google/protobuf/compiler/subprocess.h
+++ b/src/google/protobuf/compiler/subprocess.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -53,7 +53,7 @@ class Message;
namespace compiler {
// Utility class for launching sub-processes.
-class Subprocess {
+class LIBPROTOC_EXPORT Subprocess {
public:
Subprocess();
~Subprocess();
diff --git a/src/google/protobuf/compiler/test_plugin.cc b/src/google/protobuf/compiler/test_plugin.cc
index 5cbbf3d9..4830fd70 100644
--- a/src/google/protobuf/compiler/test_plugin.cc
+++ b/src/google/protobuf/compiler/test_plugin.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/compiler/zip_output_unittest.sh b/src/google/protobuf/compiler/zip_output_unittest.sh
index 3a024364..6fc7136d 100755
--- a/src/google/protobuf/compiler/zip_output_unittest.sh
+++ b/src/google/protobuf/compiler/zip_output_unittest.sh
@@ -2,7 +2,7 @@
#
# Protocol Buffers - Google's data interchange format
# Copyright 2009 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
diff --git a/src/google/protobuf/compiler/zip_writer.cc b/src/google/protobuf/compiler/zip_writer.cc
index 65d73527..458cced2 100644
--- a/src/google/protobuf/compiler/zip_writer.cc
+++ b/src/google/protobuf/compiler/zip_writer.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,7 +30,7 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/compiler/zip_writer.h b/src/google/protobuf/compiler/zip_writer.h
index be73972a..602e508e 100644
--- a/src/google/protobuf/compiler/zip_writer.h
+++ b/src/google/protobuf/compiler/zip_writer.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,7 +30,7 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 754b5628..bfdacd95 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,6 +35,7 @@
#include <google/protobuf/stubs/hash.h>
#include <map>
#include <set>
+#include <string>
#include <vector>
#include <algorithm>
#include <limits>
@@ -43,18 +44,21 @@
#include <google/protobuf/descriptor_database.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/wire_format.h>
+#include <google/protobuf/io/strtod.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
-#include <google/protobuf/stubs/map-util.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
#undef PACKAGE // autoheader #defines this. :(
@@ -108,6 +112,21 @@ const char * const FieldDescriptor::kTypeToName[MAX_TYPE + 1] = {
"sint64", // TYPE_SINT64
};
+const char * const FieldDescriptor::kCppTypeToName[MAX_CPPTYPE + 1] = {
+ "ERROR", // 0 is reserved for errors
+
+ "int32", // CPPTYPE_INT32
+ "int64", // CPPTYPE_INT64
+ "uint32", // CPPTYPE_UINT32
+ "uint64", // CPPTYPE_UINT64
+ "double", // CPPTYPE_DOUBLE
+ "float", // CPPTYPE_FLOAT
+ "bool", // CPPTYPE_BOOL
+ "enum", // CPPTYPE_ENUM
+ "string", // CPPTYPE_STRING
+ "message", // CPPTYPE_MESSAGE
+};
+
const char * const FieldDescriptor::kLabelToName[MAX_LABEL + 1] = {
"ERROR", // 0 is reserved for errors
@@ -116,6 +135,21 @@ 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";
+ }
+ GOOGLE_LOG(FATAL) << "can't reach here.";
+ return NULL;
+}
+
+static const char * const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty";
+
#ifndef _MSC_VER // MSVC doesn't need these and won't even accept them.
const int FieldDescriptor::kMaxNumber;
const int FieldDescriptor::kFirstReservedNumber;
@@ -124,10 +158,8 @@ const int FieldDescriptor::kLastReservedNumber;
namespace {
-const string kEmptyString;
-
-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());
@@ -148,8 +180,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;
@@ -186,9 +218,11 @@ struct PointerIntegerPairHash {
return reinterpret_cast<intptr_t>(p.first) * ((1 << 16) - 1) + p.second;
}
+#ifdef _MSC_VER
// Used only by MSVC and platforms where hash_map is not available.
static const size_t bucket_size = 4;
static const size_t min_buckets = 8;
+#endif
inline bool operator()(const PairType& a, const PairType& b) const {
return a.first < b.first ||
(a.first == b.first && a.second < b.second);
@@ -207,9 +241,11 @@ struct PointerStringPairHash {
cstring_hash(p.second);
}
+#ifdef _MSC_VER
// Used only by MSVC and platforms where hash_map is not available.
static const size_t bucket_size = 4;
static const size_t min_buckets = 8;
+#endif
inline bool operator()(const PointerStringPair& a,
const PointerStringPair& b) const {
if (a.first < b.first) return true;
@@ -221,12 +257,14 @@ struct PointerStringPairHash {
struct Symbol {
enum Type {
- NULL_SYMBOL, MESSAGE, FIELD, ENUM, ENUM_VALUE, SERVICE, METHOD, PACKAGE
+ NULL_SYMBOL, MESSAGE, FIELD, ONEOF, ENUM, ENUM_VALUE, SERVICE, METHOD,
+ PACKAGE
};
Type type;
union {
const Descriptor* descriptor;
const FieldDescriptor* field_descriptor;
+ const OneofDescriptor* oneof_descriptor;
const EnumDescriptor* enum_descriptor;
const EnumValueDescriptor* enum_value_descriptor;
const ServiceDescriptor* service_descriptor;
@@ -252,6 +290,7 @@ struct Symbol {
CONSTRUCTOR(Descriptor , MESSAGE , descriptor )
CONSTRUCTOR(FieldDescriptor , FIELD , field_descriptor )
+ CONSTRUCTOR(OneofDescriptor , ONEOF , oneof_descriptor )
CONSTRUCTOR(EnumDescriptor , ENUM , enum_descriptor )
CONSTRUCTOR(EnumValueDescriptor, ENUM_VALUE, enum_value_descriptor )
CONSTRUCTOR(ServiceDescriptor , SERVICE , service_descriptor )
@@ -264,6 +303,7 @@ struct Symbol {
case NULL_SYMBOL: return NULL;
case MESSAGE : return descriptor ->file();
case FIELD : return field_descriptor ->file();
+ case ONEOF : return oneof_descriptor ->containing_type()->file();
case ENUM : return enum_descriptor ->file();
case ENUM_VALUE : return enum_value_descriptor->type()->file();
case SERVICE : return service_descriptor ->file();
@@ -300,6 +340,36 @@ typedef hash_map<EnumIntPair, const EnumValueDescriptor*,
// for that.
typedef map<DescriptorIntPair, const FieldDescriptor*>
ExtensionsGroupedByDescriptorMap;
+typedef hash_map<string, const SourceCodeInfo_Location*> LocationsByPathMap;
+
+set<string>* allowed_proto3_extendees_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(allowed_proto3_extendees_init_);
+
+void DeleteAllowedProto3Extendee() {
+ delete allowed_proto3_extendees_;
+}
+
+void InitAllowedProto3Extendee() {
+ allowed_proto3_extendees_ = new set<string>;
+ 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");
+ google::protobuf::internal::OnShutdown(&DeleteAllowedProto3Extendee);
+}
+
+// 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
@@ -311,17 +381,42 @@ class DescriptorPool::Tables {
Tables();
~Tables();
- // Checkpoint the state of the tables. Future calls to Rollback() will
- // return the Tables to this state. This is used when building files, since
- // some kinds of validation errors cannot be detected until the file's
- // descriptors have already been added to the tables. BuildFile() calls
- // Checkpoint() before it starts building and Rollback() if it encounters
- // an error.
- void Checkpoint();
+ // Record the current state of the tables to the stack of checkpoints.
+ // Each call to AddCheckpoint() must be paired with exactly one call to either
+ // ClearLastCheckpoint() or RollbackToLastCheckpoint().
+ //
+ // This is used when building files, since some kinds of validation errors
+ // cannot be detected until the file's descriptors have already been added to
+ // the tables.
+ //
+ // This supports recursive checkpoints, since building a file may trigger
+ // recursive building of other files. Note that recursive checkpoints are not
+ // normally necessary; explicit dependencies are built prior to checkpointing.
+ // So although we recursively build transitive imports, there is at most one
+ // checkpoint in the stack during dependency building.
+ //
+ // Recursive checkpoints only arise during cross-linking of the descriptors.
+ // Symbol references must be resolved, via DescriptorBuilder::FindSymbol and
+ // friends. If the pending file references an unknown symbol
+ // (e.g., it is not defined in the pending file's explicit dependencies), and
+ // the pool is using a fallback database, and that database contains a file
+ // defining that symbol, and that file has not yet been built by the pool,
+ // the pool builds the file during cross-linking, leading to another
+ // checkpoint.
+ void AddCheckpoint();
+
+ // Mark the last checkpoint as having cleared successfully, removing it from
+ // the stack. If the stack is empty, all pending symbols will be committed.
+ //
+ // Note that this does not guarantee that the symbols added since the last
+ // checkpoint won't be rolled back: if a checkpoint gets rolled back,
+ // everything past that point gets rolled back, including symbols added after
+ // checkpoints that were pushed onto the stack after it and marked as cleared.
+ void ClearLastCheckpoint();
- // Roll back the Tables to the state of the last Checkpoint(), removing
- // everything that was added after that point.
- void Rollback();
+ // Roll back the Tables to the state of the checkpoint at the top of the
+ // stack, removing everything that was added after that point.
+ void RollbackToLastCheckpoint();
// The stack of files which are currently being built. Used to detect
// cyclic dependencies when loading files from a DescriptorDatabase. Not
@@ -329,10 +424,18 @@ class DescriptorPool::Tables {
vector<string> pending_files_;
// A set of files which we have tried to load from the fallback database
- // and encountered errors. We will not attempt to load them again.
+ // and encountered errors. We will not attempt to load them again during
+ // execution of the current public API call, but for compatibility with
+ // legacy clients, this is cleared at the beginning of each public API call.
// Not used when fallback_database_ == NULL.
hash_set<string> known_bad_files_;
+ // A set of symbols which we have tried to load from the fallback database
+ // and encountered errors. We will not attempt to load them again during
+ // execution of the current public API call, but for compatibility with
+ // legacy clients, this is cleared at the beginning of each public API call.
+ hash_set<string> known_bad_symbols_;
+
// The set of descriptors for which we've already loaded the full
// set of extensions numbers from fallback_database_.
hash_set<const Descriptor*> extensions_loaded_from_db_;
@@ -349,7 +452,7 @@ class DescriptorPool::Tables {
// declaring Symbol in descriptor.h, which would drag all kinds of other
// stuff into the header. Yay C++.
Symbol FindByNameHelper(
- const DescriptorPool* pool, const string& name) const;
+ const DescriptorPool* pool, const string& name);
// These return NULL if not found.
inline const FileDescriptor* FindFile(const string& key) const;
@@ -405,10 +508,28 @@ class DescriptorPool::Tables {
FilesByNameMap files_by_name_;
ExtensionsGroupedByDescriptorMap extensions_;
- int strings_before_checkpoint_;
- int messages_before_checkpoint_;
- int file_tables_before_checkpoint_;
- int allocations_before_checkpoint_;
+ struct CheckPoint {
+ explicit CheckPoint(const Tables* tables)
+ : strings_before_checkpoint(tables->strings_.size()),
+ messages_before_checkpoint(tables->messages_.size()),
+ file_tables_before_checkpoint(tables->file_tables_.size()),
+ allocations_before_checkpoint(tables->allocations_.size()),
+ pending_symbols_before_checkpoint(
+ tables->symbols_after_checkpoint_.size()),
+ pending_files_before_checkpoint(
+ tables->files_after_checkpoint_.size()),
+ pending_extensions_before_checkpoint(
+ tables->extensions_after_checkpoint_.size()) {
+ }
+ int strings_before_checkpoint;
+ int messages_before_checkpoint;
+ int file_tables_before_checkpoint;
+ int allocations_before_checkpoint;
+ int pending_symbols_before_checkpoint;
+ int pending_files_before_checkpoint;
+ int pending_extensions_before_checkpoint;
+ };
+ vector<CheckPoint> checkpoints_;
vector<const char* > symbols_after_checkpoint_;
vector<const char* > files_after_checkpoint_;
vector<DescriptorIntPair> extensions_after_checkpoint_;
@@ -455,6 +576,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.
@@ -472,20 +596,47 @@ class FileDescriptorTables {
// fails because we allow duplicates; the first field by the name wins.
void AddFieldByStylizedNames(const FieldDescriptor* field);
+ // Populates p->first->locations_by_path_ from p->second.
+ // Unusual signature dictated by GoogleOnceDynamic.
+ static void BuildLocationsByPath(
+ pair<const FileDescriptorTables*, const SourceCodeInfo*>* p);
+
+ // Returns the location denoted by the specified path through info,
+ // or NULL if not found.
+ // The value of info must be that of the corresponding FileDescriptor.
+ // (Conceptually a pure function, but stateful as an optimisation.)
+ const SourceCodeInfo_Location* GetSourceLocation(
+ const vector<int>& path, const SourceCodeInfo* info) const;
+
private:
SymbolsByParentMap symbols_by_parent_;
FieldsByNameMap fields_by_lowercase_name_;
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()
- : strings_before_checkpoint_(0),
- messages_before_checkpoint_(0),
- allocations_before_checkpoint_(0) {}
+ // Start some hash_map and hash_set objects with a small # of buckets
+ : known_bad_files_(3),
+ known_bad_symbols_(3),
+ extensions_loaded_from_db_(3),
+ symbols_by_name_(3),
+ files_by_name_(3) {}
+
DescriptorPool::Tables::~Tables() {
+ GOOGLE_DCHECK(checkpoints_.empty());
// Note that the deletion order is important, since the destructors of some
// messages may refer to objects in allocations_.
STLDeleteElements(&messages_);
@@ -496,51 +647,81 @@ DescriptorPool::Tables::~Tables() {
STLDeleteElements(&file_tables_);
}
-FileDescriptorTables::FileDescriptorTables() {}
+FileDescriptorTables::FileDescriptorTables()
+ // Initialize all the hash tables to start out with a small # of buckets
+ : symbols_by_parent_(3),
+ fields_by_lowercase_name_(3),
+ fields_by_camelcase_name_(3),
+ fields_by_number_(3),
+ enum_values_by_number_(3),
+ unknown_enum_values_by_number_(3) {
+}
+
FileDescriptorTables::~FileDescriptorTables() {}
const FileDescriptorTables FileDescriptorTables::kEmpty;
-void DescriptorPool::Tables::Checkpoint() {
- strings_before_checkpoint_ = strings_.size();
- messages_before_checkpoint_ = messages_.size();
- file_tables_before_checkpoint_ = file_tables_.size();
- allocations_before_checkpoint_ = allocations_.size();
+void DescriptorPool::Tables::AddCheckpoint() {
+ checkpoints_.push_back(CheckPoint(this));
+}
- symbols_after_checkpoint_.clear();
- files_after_checkpoint_.clear();
- extensions_after_checkpoint_.clear();
+void DescriptorPool::Tables::ClearLastCheckpoint() {
+ GOOGLE_DCHECK(!checkpoints_.empty());
+ checkpoints_.pop_back();
+ if (checkpoints_.empty()) {
+ // All checkpoints have been cleared: we can now commit all of the pending
+ // data.
+ symbols_after_checkpoint_.clear();
+ files_after_checkpoint_.clear();
+ extensions_after_checkpoint_.clear();
+ }
}
-void DescriptorPool::Tables::Rollback() {
- for (int i = 0; i < symbols_after_checkpoint_.size(); i++) {
+void DescriptorPool::Tables::RollbackToLastCheckpoint() {
+ GOOGLE_DCHECK(!checkpoints_.empty());
+ const CheckPoint& checkpoint = checkpoints_.back();
+
+ for (int i = checkpoint.pending_symbols_before_checkpoint;
+ i < symbols_after_checkpoint_.size();
+ i++) {
symbols_by_name_.erase(symbols_after_checkpoint_[i]);
}
- for (int i = 0; i < files_after_checkpoint_.size(); i++) {
+ for (int i = checkpoint.pending_files_before_checkpoint;
+ i < files_after_checkpoint_.size();
+ i++) {
files_by_name_.erase(files_after_checkpoint_[i]);
}
- for (int i = 0; i < extensions_after_checkpoint_.size(); i++) {
+ for (int i = checkpoint.pending_extensions_before_checkpoint;
+ i < extensions_after_checkpoint_.size();
+ i++) {
extensions_.erase(extensions_after_checkpoint_[i]);
}
- symbols_after_checkpoint_.clear();
- files_after_checkpoint_.clear();
- extensions_after_checkpoint_.clear();
+ symbols_after_checkpoint_.resize(
+ checkpoint.pending_symbols_before_checkpoint);
+ files_after_checkpoint_.resize(checkpoint.pending_files_before_checkpoint);
+ extensions_after_checkpoint_.resize(
+ checkpoint.pending_extensions_before_checkpoint);
STLDeleteContainerPointers(
- strings_.begin() + strings_before_checkpoint_, strings_.end());
+ strings_.begin() + checkpoint.strings_before_checkpoint, strings_.end());
STLDeleteContainerPointers(
- messages_.begin() + messages_before_checkpoint_, messages_.end());
+ messages_.begin() + checkpoint.messages_before_checkpoint,
+ messages_.end());
STLDeleteContainerPointers(
- file_tables_.begin() + file_tables_before_checkpoint_, file_tables_.end());
- for (int i = allocations_before_checkpoint_; i < allocations_.size(); i++) {
+ file_tables_.begin() + checkpoint.file_tables_before_checkpoint,
+ file_tables_.end());
+ for (int i = checkpoint.allocations_before_checkpoint;
+ i < allocations_.size();
+ i++) {
operator delete(allocations_[i]);
}
- strings_.resize(strings_before_checkpoint_);
- messages_.resize(messages_before_checkpoint_);
- file_tables_.resize(file_tables_before_checkpoint_);
- allocations_.resize(allocations_before_checkpoint_);
+ strings_.resize(checkpoint.strings_before_checkpoint);
+ messages_.resize(checkpoint.messages_before_checkpoint);
+ file_tables_.resize(checkpoint.file_tables_before_checkpoint);
+ allocations_.resize(checkpoint.allocations_before_checkpoint);
+ checkpoints_.pop_back();
}
// -------------------------------------------------------------------
@@ -573,8 +754,10 @@ inline Symbol FileDescriptorTables::FindNestedSymbolOfType(
}
Symbol DescriptorPool::Tables::FindByNameHelper(
- const DescriptorPool* pool, const string& name) const {
+ const DescriptorPool* pool, const string& name) {
MutexLockMaybe lock(pool->mutex_);
+ known_bad_symbols_.clear();
+ known_bad_files_.clear();
Symbol result = FindSymbol(name);
if (result.IsNull() && pool->underlay_ != NULL) {
@@ -600,7 +783,7 @@ inline const FileDescriptor* DescriptorPool::Tables::FindFile(
inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber(
const Descriptor* parent, int number) const {
- return FindPtrOrNull(fields_by_number_, make_pair(parent, number));
+ return FindPtrOrNull(fields_by_number_, std::make_pair(parent, number));
}
inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName(
@@ -617,18 +800,71 @@ inline const FieldDescriptor* FileDescriptorTables::FindFieldByCamelcaseName(
inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber(
const EnumDescriptor* parent, int number) const {
- return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number));
+ return FindPtrOrNull(enum_values_by_number_, std::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_, std::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_, std::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_, std::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::Tables*>(DescriptorPool::generated_pool()->
+ tables_.get());
+ EnumValueDescriptor* result = tables->Allocate<EnumValueDescriptor>();
+ 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_,
+ std::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));
+ return FindPtrOrNull(extensions_, std::make_pair(extendee, number));
}
inline void DescriptorPool::Tables::FindAllExtensions(
const Descriptor* extendee, vector<const FieldDescriptor*>* out) const {
ExtensionsGroupedByDescriptorMap::const_iterator it =
- extensions_.lower_bound(make_pair(extendee, 0));
+ extensions_.lower_bound(std::make_pair(extendee, 0));
for (; it != extensions_.end() && it->first.first == extendee; ++it) {
out->push_back(it->second);
}
@@ -721,7 +957,7 @@ string* DescriptorPool::Tables::AllocateString(const string& value) {
}
template<typename Type>
-Type* DescriptorPool::Tables::AllocateMessage(Type* dummy) {
+Type* DescriptorPool::Tables::AllocateMessage(Type* /* dummy */) {
Type* result = new Type;
messages_.push_back(result);
return result;
@@ -745,6 +981,22 @@ void* DescriptorPool::Tables::AllocateBytes(int size) {
return result;
}
+void FileDescriptorTables::BuildLocationsByPath(
+ pair<const FileDescriptorTables*, const SourceCodeInfo*>* p) {
+ for (int i = 0, len = p->second->location_size(); i < len; ++i) {
+ const SourceCodeInfo_Location* loc = &p->second->location().Get(i);
+ p->first->locations_by_path_[Join(loc->path(), ",")] = loc;
+ }
+}
+
+const SourceCodeInfo_Location* FileDescriptorTables::GetSourceLocation(
+ const vector<int>& path, const SourceCodeInfo* info) const {
+ pair<const FileDescriptorTables*, const SourceCodeInfo*> p(
+ std::make_pair(this, info));
+ locations_by_path_once_.Init(&FileDescriptorTables::BuildLocationsByPath, &p);
+ return FindPtrOrNull(locations_by_path_, Join(path, ","));
+}
+
// ===================================================================
// DescriptorPool
@@ -757,7 +1009,8 @@ DescriptorPool::DescriptorPool()
underlay_(NULL),
tables_(new Tables),
enforce_dependencies_(true),
- allow_unknown_(false) {}
+ allow_unknown_(false),
+ enforce_weak_(false) {}
DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database,
ErrorCollector* error_collector)
@@ -767,7 +1020,8 @@ DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database,
underlay_(NULL),
tables_(new Tables),
enforce_dependencies_(true),
- allow_unknown_(false) {
+ allow_unknown_(false),
+ enforce_weak_(false) {
}
DescriptorPool::DescriptorPool(const DescriptorPool* underlay)
@@ -777,7 +1031,8 @@ DescriptorPool::DescriptorPool(const DescriptorPool* underlay)
underlay_(underlay),
tables_(new Tables),
enforce_dependencies_(true),
- allow_unknown_(false) {}
+ allow_unknown_(false),
+ enforce_weak_(false) {}
DescriptorPool::~DescriptorPool() {
if (mutex_ != NULL) delete mutex_;
@@ -790,6 +1045,14 @@ void DescriptorPool::InternalDontEnforceDependencies() {
enforce_dependencies_ = false;
}
+void DescriptorPool::AddUnusedImportTrackFile(const string& file_name) {
+ unused_import_track_files_.insert(file_name);
+}
+
+void DescriptorPool::ClearUnusedImportTrackFiles() {
+ unused_import_track_files_.clear();
+}
+
bool DescriptorPool::InternalIsFileLoaded(const string& filename) const {
MutexLockMaybe lock(mutex_);
return tables_->FindFile(filename) != NULL;
@@ -811,7 +1074,7 @@ void DeleteGeneratedPool() {
generated_pool_ = NULL;
}
-void InitGeneratedPool() {
+static void InitGeneratedPool() {
generated_database_ = new EncodedDescriptorDatabase;
generated_pool_ = new DescriptorPool(generated_database_);
@@ -871,14 +1134,16 @@ void DescriptorPool::InternalAddGeneratedFile(
const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const {
MutexLockMaybe lock(mutex_);
+ tables_->known_bad_symbols_.clear();
+ tables_->known_bad_files_.clear();
const FileDescriptor* result = tables_->FindFile(name);
if (result != NULL) return result;
if (underlay_ != NULL) {
- const FileDescriptor* result = underlay_->FindFileByName(name);
+ result = underlay_->FindFileByName(name);
if (result != NULL) return result;
}
if (TryFindFileInFallbackDatabase(name)) {
- const FileDescriptor* result = tables_->FindFile(name);
+ result = tables_->FindFile(name);
if (result != NULL) return result;
}
return NULL;
@@ -887,15 +1152,17 @@ const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const {
const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
const string& symbol_name) const {
MutexLockMaybe lock(mutex_);
+ tables_->known_bad_symbols_.clear();
+ tables_->known_bad_files_.clear();
Symbol result = tables_->FindSymbol(symbol_name);
if (!result.IsNull()) return result.GetFile();
if (underlay_ != NULL) {
- const FileDescriptor* result =
+ const FileDescriptor* file_result =
underlay_->FindFileContainingSymbol(symbol_name);
- if (result != NULL) return result;
+ if (file_result != NULL) return file_result;
}
if (TryFindSymbolInFallbackDatabase(symbol_name)) {
- Symbol result = tables_->FindSymbol(symbol_name);
+ result = tables_->FindSymbol(symbol_name);
if (!result.IsNull()) return result.GetFile();
}
return NULL;
@@ -929,6 +1196,12 @@ const FieldDescriptor* DescriptorPool::FindExtensionByName(
}
}
+const OneofDescriptor* DescriptorPool::FindOneofByName(
+ const string& name) const {
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::ONEOF) ? result.oneof_descriptor : NULL;
+}
+
const EnumDescriptor* DescriptorPool::FindEnumTypeByName(
const string& name) const {
Symbol result = tables_->FindByNameHelper(this, name);
@@ -957,17 +1230,18 @@ const MethodDescriptor* DescriptorPool::FindMethodByName(
const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
const Descriptor* extendee, int number) const {
MutexLockMaybe lock(mutex_);
+ tables_->known_bad_symbols_.clear();
+ tables_->known_bad_files_.clear();
const FieldDescriptor* result = tables_->FindExtension(extendee, number);
if (result != NULL) {
return result;
}
if (underlay_ != NULL) {
- const FieldDescriptor* result =
- underlay_->FindExtensionByNumber(extendee, number);
+ result = underlay_->FindExtensionByNumber(extendee, number);
if (result != NULL) return result;
}
if (TryFindExtensionInFallbackDatabase(extendee, number)) {
- const FieldDescriptor* result = tables_->FindExtension(extendee, number);
+ result = tables_->FindExtension(extendee, number);
if (result != NULL) {
return result;
}
@@ -978,6 +1252,8 @@ const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
void DescriptorPool::FindAllExtensions(
const Descriptor* extendee, vector<const FieldDescriptor*>* out) const {
MutexLockMaybe lock(mutex_);
+ tables_->known_bad_symbols_.clear();
+ tables_->known_bad_files_.clear();
// Initialize tables_->extensions_ from the fallback database first
// (but do this only once per descriptor).
@@ -1002,6 +1278,7 @@ void DescriptorPool::FindAllExtensions(
}
}
+
// -------------------------------------------------------------------
const FieldDescriptor*
@@ -1048,6 +1325,17 @@ Descriptor::FindFieldByName(const string& key) const {
}
}
+const OneofDescriptor*
+Descriptor::FindOneofByName(const string& key) const {
+ Symbol result =
+ file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ONEOF);
+ if (!result.IsNull()) {
+ return result.oneof_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
const FieldDescriptor*
Descriptor::FindExtensionByName(const string& key) const {
Symbol result =
@@ -1130,6 +1418,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 =
@@ -1212,16 +1505,17 @@ FileDescriptor::FindExtensionByCamelcaseName(const string& key) const {
}
}
-bool Descriptor::IsExtensionNumber(int number) const {
+const Descriptor::ExtensionRange*
+Descriptor::FindExtensionRangeContainingNumber(int number) const {
// Linear search should be fine because we don't expect a message to have
// more than a couple extension ranges.
for (int i = 0; i < extension_range_count(); i++) {
if (number >= extension_range(i)->start &&
number < extension_range(i)->end) {
- return true;
+ return extension_range(i);
}
}
- return false;
+ return NULL;
}
// -------------------------------------------------------------------
@@ -1237,26 +1531,66 @@ bool DescriptorPool::TryFindFileInFallbackDatabase(const string& name) const {
tables_->known_bad_files_.insert(name);
return false;
}
-
return true;
}
+bool DescriptorPool::IsSubSymbolOfBuiltType(const string& name) const {
+ string prefix = name;
+ for (;;) {
+ string::size_type dot_pos = prefix.find_last_of('.');
+ if (dot_pos == string::npos) {
+ break;
+ }
+ prefix = prefix.substr(0, dot_pos);
+ Symbol symbol = tables_->FindSymbol(prefix);
+ // If the symbol type is anything other than PACKAGE, then its complete
+ // definition is already known.
+ if (!symbol.IsNull() && symbol.type != Symbol::PACKAGE) {
+ return true;
+ }
+ }
+ if (underlay_ != NULL) {
+ // Check to see if any prefix of this symbol exists in the underlay.
+ return underlay_->IsSubSymbolOfBuiltType(name);
+ }
+ return false;
+}
+
bool DescriptorPool::TryFindSymbolInFallbackDatabase(const string& name) const {
if (fallback_database_ == NULL) return false;
- FileDescriptorProto file_proto;
- if (!fallback_database_->FindFileContainingSymbol(name, &file_proto)) {
- return false;
- }
-
- if (tables_->FindFile(file_proto.name()) != NULL) {
- // We've already loaded this file, and it apparently doesn't contain the
- // symbol we're looking for. Some DescriptorDatabases return false
- // positives.
- return false;
- }
+ if (tables_->known_bad_symbols_.count(name) > 0) return false;
- if (BuildFileFromDatabase(file_proto) == NULL) {
+ FileDescriptorProto file_proto;
+ if (// We skip looking in the fallback database if the name is a sub-symbol
+ // of any descriptor that already exists in the descriptor pool (except
+ // for package descriptors). This is valid because all symbols except
+ // for packages are defined in a single file, so if the symbol exists
+ // then we should already have its definition.
+ //
+ // The other reason to do this is to support "overriding" type
+ // definitions by merging two databases that define the same type. (Yes,
+ // people do this.) The main difficulty with making this work is that
+ // FindFileContainingSymbol() is allowed to return both false positives
+ // (e.g., SimpleDescriptorDatabase, UpgradedDescriptorDatabase) and false
+ // negatives (e.g. ProtoFileParser, SourceTreeDescriptorDatabase).
+ // When two such databases are merged, looking up a non-existent
+ // sub-symbol of a type that already exists in the descriptor pool can
+ // result in an attempt to load multiple definitions of the same type.
+ // The check below avoids this.
+ IsSubSymbolOfBuiltType(name)
+
+ // Look up file containing this symbol in fallback database.
+ || !fallback_database_->FindFileContainingSymbol(name, &file_proto)
+
+ // Check if we've already built this file. If so, it apparently doesn't
+ // contain the symbol we're looking for. Some DescriptorDatabases
+ // return false positives.
+ || tables_->FindFile(file_proto.name()) != NULL
+
+ // Build the file.
+ || BuildFileFromDatabase(file_proto) == NULL) {
+ tables_->known_bad_symbols_.insert(name);
return false;
}
@@ -1289,6 +1623,10 @@ bool DescriptorPool::TryFindExtensionInFallbackDatabase(
// ===================================================================
+bool FieldDescriptor::is_map() const {
+ return type() == TYPE_MESSAGE && message_type()->options().map_entry();
+}
+
string FieldDescriptor::DefaultValueAsString(bool quote_string_type) const {
GOOGLE_CHECK(has_default_value()) << "No default value";
switch (cpp_type()) {
@@ -1340,11 +1678,21 @@ 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());
}
+ for (int i = 0; i < public_dependency_count(); i++) {
+ proto->add_public_dependency(public_dependencies_[i]);
+ }
+
+ for (int i = 0; i < weak_dependency_count(); i++) {
+ proto->add_weak_dependency(weak_dependencies_[i]);
+ }
+
for (int i = 0; i < message_type_count(); i++) {
message_type(i)->CopyTo(proto->add_message_type());
}
@@ -1363,12 +1711,22 @@ void FileDescriptor::CopyTo(FileDescriptorProto* proto) const {
}
}
+void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const {
+ if (source_code_info_ &&
+ source_code_info_ != &SourceCodeInfo::default_instance()) {
+ proto->mutable_source_code_info()->CopyFrom(*source_code_info_);
+ }
+}
+
void Descriptor::CopyTo(DescriptorProto* proto) const {
proto->set_name(name());
for (int i = 0; i < field_count(); i++) {
field(i)->CopyTo(proto->add_field());
}
+ for (int i = 0; i < oneof_decl_count(); i++) {
+ oneof_decl(i)->CopyTo(proto->add_oneof_decl());
+ }
for (int i = 0; i < nested_type_count(); i++) {
nested_type(i)->CopyTo(proto->add_nested_type());
}
@@ -1429,11 +1787,19 @@ void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const {
proto->set_default_value(DefaultValueAsString(false));
}
+ if (containing_oneof() != NULL && !is_extension()) {
+ proto->set_oneof_index(containing_oneof()->index());
+ }
+
if (&options() != &FieldOptions::default_instance()) {
proto->mutable_options()->CopyFrom(options());
}
}
+void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
+ proto->set_name(name());
+}
+
void EnumDescriptor::CopyTo(EnumDescriptorProto* proto) const {
proto->set_name(name());
@@ -1483,6 +1849,13 @@ void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const {
if (&options() != &MethodOptions::default_instance()) {
proto->mutable_options()->CopyFrom(options());
}
+
+ if (client_streaming_) {
+ proto->set_client_streaming(true);
+ }
+ if (server_streaming_) {
+ proto->set_server_streaming(true);
+ }
}
// DebugString methods ===============================================
@@ -1490,16 +1863,14 @@ void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const {
namespace {
// Used by each of the option formatters.
-bool RetrieveOptions(const Message &options, vector<string> *option_entries) {
+bool RetrieveOptions(int depth,
+ const Message &options,
+ vector<string> *option_entries) {
option_entries->clear();
const Reflection* reflection = options.GetReflection();
vector<const FieldDescriptor*> fields;
reflection->ListFields(options, &fields);
for (int i = 0; i < fields.size(); i++) {
- // Doesn't make sense to have message type fields here
- if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- continue;
- }
int count = 1;
bool repeated = false;
if (fields[i]->is_repeated()) {
@@ -1508,9 +1879,27 @@ bool RetrieveOptions(const Message &options, vector<string> *option_entries) {
}
for (int j = 0; j < count; j++) {
string fieldval;
- TextFormat::PrintFieldValueToString(options, fields[i],
- repeated ? count : -1, &fieldval);
- option_entries->push_back(fields[i]->name() + " = " + fieldval);
+ if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ string tmp;
+ TextFormat::Printer printer;
+ printer.SetInitialIndentLevel(depth + 1);
+ printer.PrintFieldValueToString(options, fields[i],
+ repeated ? j : -1, &tmp);
+ fieldval.append("{\n");
+ fieldval.append(tmp);
+ fieldval.append(depth * 2, ' ');
+ fieldval.append("}");
+ } else {
+ TextFormat::PrintFieldValueToString(options, fields[i],
+ repeated ? j : -1, &fieldval);
+ }
+ string name;
+ if (fields[i]->is_extension()) {
+ name = "(." + fields[i]->full_name() + ")";
+ } else {
+ name = fields[i]->name();
+ }
+ option_entries->push_back(name + " = " + fieldval);
}
}
return !option_entries->empty();
@@ -1518,10 +1907,10 @@ bool RetrieveOptions(const Message &options, vector<string> *option_entries) {
// Formats options that all appear together in brackets. Does not include
// brackets.
-bool FormatBracketedOptions(const Message &options, string *output) {
+bool FormatBracketedOptions(int depth, const Message &options, string *output) {
vector<string> all_options;
- if (RetrieveOptions(options, &all_options)) {
- output->append(JoinStrings(all_options, ", "));
+ if (RetrieveOptions(depth, options, &all_options)) {
+ output->append(Join(all_options, ", "));
}
return !all_options.empty();
}
@@ -1530,7 +1919,7 @@ bool FormatBracketedOptions(const Message &options, string *output) {
bool FormatLineOptions(int depth, const Message &options, string *output) {
string prefix(depth * 2, ' ');
vector<string> all_options;
- if (RetrieveOptions(options, &all_options)) {
+ if (RetrieveOptions(depth, options, &all_options)) {
for (int i = 0; i < all_options.size(); i++) {
strings::SubstituteAndAppend(output, "$0option $1;\n",
prefix, all_options[i]);
@@ -1539,18 +1928,121 @@ bool FormatLineOptions(int depth, const Message &options, string *output) {
return !all_options.empty();
}
+class SourceLocationCommentPrinter {
+ public:
+ template<typename DescType>
+ 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_);
+ }
+ SourceLocationCommentPrinter(const FileDescriptor* file,
+ const vector<int>& path,
+ 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 &&
+ file->GetSourceLocation(path, &source_loc_);
+ }
+ void AddPreComment(string* output) {
+ if (have_source_loc_) {
+ // Detached leading comments.
+ for (int i = 0 ; i < source_loc_.leading_detached_comments.size(); ++i) {
+ *output += FormatComment(source_loc_.leading_detached_comments[i]);
+ *output += "\n";
+ }
+ // Attached leading comments.
+ if (!source_loc_.leading_comments.empty()) {
+ *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<string> 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:
+ 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;
+ {
+ vector<int> path;
+ path.push_back(FileDescriptorProto::kSyntaxFieldNumber);
+ SourceLocationCommentPrinter syntax_comment(
+ this, path, "", debug_string_options);
+ syntax_comment.AddPreComment(&contents);
+ strings::SubstituteAndAppend(&contents, "syntax = \"$0\";\n\n",
+ SyntaxName(syntax()));
+ syntax_comment.AddPostComment(&contents);
+ }
+
+ SourceLocationCommentPrinter
+ comment_printer(this, "", debug_string_options);
+ comment_printer.AddPreComment(&contents);
+
+ set<int> public_dependencies;
+ set<int> weak_dependencies;
+ public_dependencies.insert(public_dependencies_,
+ public_dependencies_ + public_dependency_count_);
+ weak_dependencies.insert(weak_dependencies_,
+ weak_dependencies_ + weak_dependency_count_);
for (int i = 0; i < dependency_count(); i++) {
- strings::SubstituteAndAppend(&contents, "import \"$0\";\n",
- dependency(i)->name());
+ if (public_dependencies.count(i) > 0) {
+ strings::SubstituteAndAppend(&contents, "import public \"$0\";\n",
+ dependency(i)->name());
+ } else if (weak_dependencies.count(i) > 0) {
+ strings::SubstituteAndAppend(&contents, "import weak \"$0\";\n",
+ dependency(i)->name());
+ } else {
+ strings::SubstituteAndAppend(&contents, "import \"$0\";\n",
+ dependency(i)->name());
+ }
}
if (!package().empty()) {
+ vector<int> path;
+ path.push_back(FileDescriptorProto::kPackageFieldNumber);
+ SourceLocationCommentPrinter package_comment(
+ this, path, "", debug_string_options);
+ package_comment.AddPreComment(&contents);
strings::SubstituteAndAppend(&contents, "package $0;\n\n", package());
+ package_comment.AddPostComment(&contents);
}
if (FormatLineOptions(0, options(), &contents)) {
@@ -1558,7 +2050,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");
}
@@ -1573,15 +2065,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");
}
@@ -1593,23 +2084,46 @@ string FileDescriptor::DebugString() const {
strings::SubstituteAndAppend(&contents, "extend .$0 {\n",
containing_type->full_name());
}
- extension(i)->DebugString(1, &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);
@@ -1631,16 +2145,22 @@ 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++) {
- field(i)->DebugString(depth, contents);
+ if (field(i)->containing_oneof() == NULL) {
+ 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,
+ debug_string_options);
+ }
}
for (int i = 0; i < extension_range_count(); i++) {
@@ -1659,15 +2179,24 @@ void Descriptor::DebugString(int depth, string *contents) const {
strings::SubstituteAndAppend(contents, "$0 extend .$1 {\n",
prefix, containing_type->full_name());
}
- extension(i)->DebugString(depth + 1, contents);
+ extension(i)->DebugString(
+ 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()) {
@@ -1675,30 +2204,56 @@ string FieldDescriptor::DebugString() const {
containing_type()->full_name());
depth = 1;
}
- DebugString(depth, &contents);
+ DebugString(depth, PRINT_LABEL, &contents, debug_string_options);
if (is_extension()) {
- contents.append("}\n");
+ contents.append("}\n");
}
return contents;
}
-void FieldDescriptor::DebugString(int depth, string *contents) const {
- string prefix(depth * 2, ' ');
- string field_type;
- switch (type()) {
+// The field type string used in FieldDescriptor::DebugString()
+string FieldDescriptor::FieldTypeNameDebugString() const {
+ switch(type()) {
case TYPE_MESSAGE:
- field_type = "." + message_type()->full_name();
- break;
+ return "." + message_type()->full_name();
case TYPE_ENUM:
- field_type = "." + enum_type()->full_name();
- break;
+ return "." + enum_type()->full_name();
default:
- field_type = kTypeToName[type()];
+ return kTypeToName[type()];
+ }
+}
+
+void FieldDescriptor::DebugString(int depth,
+ PrintLabelFlag print_label_flag,
+ string *contents,
+ const DebugStringOptions&
+ debug_string_options) const {
+ string prefix(depth * 2, ' ');
+ string field_type;
+
+ // Special case map fields.
+ if (is_map()) {
+ 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 && !is_map()) {
+ label = kLabelToName[this->label()];
+ label.push_back(' ');
}
- strings::SubstituteAndAppend(contents, "$0$1 $2 $3 = $4",
+ SourceLocationCommentPrinter
+ comment_printer(this, prefix, debug_string_options);
+ comment_printer.AddPreComment(contents);
+
+ strings::SubstituteAndAppend(contents, "$0$1$2 $3 = $4",
prefix,
- kLabelToName[label()],
+ label,
field_type,
type() == TYPE_GROUP ? message_type()->name() :
name(),
@@ -1712,7 +2267,7 @@ void FieldDescriptor::DebugString(int depth, string *contents) const {
}
string formatted_options;
- if (FormatBracketedOptions(options(), &formatted_options)) {
+ if (FormatBracketedOptions(depth, options(), &formatted_options)) {
contents->append(bracketed ? ", " : " [");
bracketed = true;
contents->append(formatted_options);
@@ -1723,81 +2278,173 @@ void FieldDescriptor::DebugString(int depth, string *contents) const {
}
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, options);
+ return contents;
+}
+
+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,
+ 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());
string formatted_options;
- if (FormatBracketedOptions(options(), &formatted_options)) {
+ if (FormatBracketedOptions(depth, options(), &formatted_options)) {
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;
- strings::SubstituteAndAppend(contents, "$0rpc $1(.$2) returns (.$3)",
+
+ SourceLocationCommentPrinter
+ comment_printer(this, prefix, debug_string_options);
+ comment_printer.AddPreComment(contents);
+
+ strings::SubstituteAndAppend(contents, "$0rpc $1($4.$2) returns ($5.$3)",
prefix, name(),
input_type()->full_name(),
- output_type()->full_name());
+ output_type()->full_name(),
+ client_streaming() ? "stream " : "",
+ server_streaming() ? "stream " : "");
string formatted_options;
if (FormatLineOptions(depth, options(), &formatted_options)) {
@@ -1806,7 +2453,152 @@ void MethodDescriptor::DebugString(int depth, string *contents) const {
} else {
contents->append(";\n");
}
+
+ comment_printer.AddPostComment(contents);
+}
+
+
+// Location methods ===============================================
+
+bool FileDescriptor::GetSourceLocation(const vector<int>& path,
+ SourceLocation* out_location) const {
+ GOOGLE_CHECK_NOTNULL(out_location);
+ if (source_code_info_) {
+ if (const SourceCodeInfo_Location* loc =
+ tables_->GetSourceLocation(path, source_code_info_)) {
+ const RepeatedField<int32>& span = loc->span();
+ if (span.size() == 3 || span.size() == 4) {
+ out_location->start_line = span.Get(0);
+ out_location->start_column = span.Get(1);
+ out_location->end_line = span.Get(span.size() == 3 ? 0 : 2);
+ out_location->end_column = span.Get(span.size() - 1);
+
+ out_location->leading_comments = loc->leading_comments();
+ out_location->trailing_comments = loc->trailing_comments();
+ out_location->leading_detached_comments.assign(
+ loc->leading_detached_comments().begin(),
+ loc->leading_detached_comments().end());
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool FileDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path; // empty path for root FileDescriptor
+ return GetSourceLocation(path, out_location);
+}
+
+bool FieldDescriptor::is_packed() const {
+ return is_packable() && (options_ != NULL) && options_->packed();
+}
+
+bool Descriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return file()->GetSourceLocation(path, out_location);
+}
+
+bool FieldDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return file()->GetSourceLocation(path, out_location);
+}
+
+bool OneofDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return containing_type()->file()->GetSourceLocation(path, out_location);
+}
+
+bool EnumDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return file()->GetSourceLocation(path, out_location);
+}
+
+bool MethodDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return service()->file()->GetSourceLocation(path, out_location);
+}
+
+bool ServiceDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return file()->GetSourceLocation(path, out_location);
+}
+
+bool EnumValueDescriptor::GetSourceLocation(
+ SourceLocation* out_location) const {
+ vector<int> path;
+ GetLocationPath(&path);
+ return type()->file()->GetSourceLocation(path, out_location);
+}
+
+void Descriptor::GetLocationPath(vector<int>* output) const {
+ if (containing_type()) {
+ containing_type()->GetLocationPath(output);
+ output->push_back(DescriptorProto::kNestedTypeFieldNumber);
+ output->push_back(index());
+ } else {
+ output->push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+ output->push_back(index());
+ }
}
+
+void FieldDescriptor::GetLocationPath(vector<int>* output) const {
+ if (is_extension()) {
+ if (extension_scope() == NULL) {
+ output->push_back(FileDescriptorProto::kExtensionFieldNumber);
+ output->push_back(index());
+ } else {
+ extension_scope()->GetLocationPath(output);
+ output->push_back(DescriptorProto::kExtensionFieldNumber);
+ output->push_back(index());
+ }
+ } else {
+ containing_type()->GetLocationPath(output);
+ output->push_back(DescriptorProto::kFieldFieldNumber);
+ output->push_back(index());
+ }
+}
+
+void OneofDescriptor::GetLocationPath(vector<int>* output) const {
+ containing_type()->GetLocationPath(output);
+ output->push_back(DescriptorProto::kOneofDeclFieldNumber);
+ output->push_back(index());
+}
+
+void EnumDescriptor::GetLocationPath(vector<int>* output) const {
+ if (containing_type()) {
+ containing_type()->GetLocationPath(output);
+ output->push_back(DescriptorProto::kEnumTypeFieldNumber);
+ output->push_back(index());
+ } else {
+ output->push_back(FileDescriptorProto::kEnumTypeFieldNumber);
+ output->push_back(index());
+ }
+}
+
+void EnumValueDescriptor::GetLocationPath(vector<int>* output) const {
+ type()->GetLocationPath(output);
+ output->push_back(EnumDescriptorProto::kValueFieldNumber);
+ output->push_back(index());
+}
+
+void ServiceDescriptor::GetLocationPath(vector<int>* output) const {
+ output->push_back(FileDescriptorProto::kServiceFieldNumber);
+ output->push_back(index());
+}
+
+void MethodDescriptor::GetLocationPath(vector<int>* output) const {
+ service()->GetLocationPath(output);
+ output->push_back(ServiceDescriptorProto::kMethodFieldNumber);
+ output->push_back(index());
+}
+
// ===================================================================
namespace {
@@ -1859,6 +2651,11 @@ class DescriptorBuilder {
string filename_;
FileDescriptor* file_;
FileDescriptorTables* file_tables_;
+ set<const FileDescriptor*> dependencies_;
+
+ // unused_dependency_ is used to record the unused imported files.
+ // Note: public import is not considered.
+ set<const FileDescriptor*> unused_dependency_;
// If LookupSymbol() finds a symbol that is in a file which is not a declared
// dependency of this file, it will fail, but will set
@@ -1870,10 +2667,22 @@ class DescriptorBuilder {
const FileDescriptor* possible_undeclared_dependency_;
string possible_undeclared_dependency_name_;
+ // If LookupSymbol() could resolve a symbol which is not defined,
+ // record the resolved name. This is only used by AddNotDefinedError()
+ // to report a more useful error message.
+ string undefine_resolved_name_;
+
void AddError(const string& element_name,
const Message& descriptor,
DescriptorPool::ErrorCollector::ErrorLocation location,
const string& error);
+ void AddError(const string& element_name,
+ const Message& descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ const char* error);
+ void AddRecursiveImportError(const FileDescriptorProto& proto, int from_here);
+ void AddTwiceListedError(const FileDescriptorProto& proto, int index);
+ void AddImportError(const FileDescriptorProto& proto, int index);
// Adds an error indicating that undefined_symbol was not defined. Must
// only be called after LookupSymbol() fails.
@@ -1883,11 +2692,19 @@ class DescriptorBuilder {
DescriptorPool::ErrorCollector::ErrorLocation location,
const string& undefined_symbol);
+ void AddWarning(const string& element_name, const Message& descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ const string& error);
+
// Silly helper which determines if the given file is in the given package.
// I.e., either file->package() == package_name or file->package() is a
// nested package within package_name.
bool IsInPackage(const FileDescriptor* file, const string& package_name);
+ // Helper function which finds all public dependencies of the given file, and
+ // stores the them in the dependencies_ set in the builder.
+ void RecordPublicDependencies(const FileDescriptor* file);
+
// Like tables_->FindSymbol(), but additionally:
// - Search the pool's underlay if not found in tables_.
// - Insure that the resulting Symbol is from one of the file's declared
@@ -1898,6 +2715,10 @@ class DescriptorBuilder {
// file's declared dependencies.
Symbol FindSymbolNotEnforcingDeps(const string& name);
+ // This implements the body of FindSymbolNotEnforcingDeps().
+ Symbol FindSymbolNotEnforcingDepsHelper(const DescriptorPool* pool,
+ const string& name);
+
// Like FindSymbol(), but looks up the name relative to some other symbol
// name. This first searches siblings of relative_to, then siblings of its
// parents, etc. For example, LookupSymbol("foo.bar", "baz.qux.corge") makes
@@ -1936,7 +2757,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
@@ -2009,6 +2830,9 @@ class DescriptorBuilder {
void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto,
const Descriptor* parent,
Descriptor::ExtensionRange* result);
+ void BuildOneof(const OneofDescriptorProto& proto,
+ Descriptor* parent,
+ OneofDescriptor* result);
void BuildEnum(const EnumDescriptorProto& proto,
const Descriptor* parent,
EnumDescriptor* result);
@@ -2022,6 +2846,8 @@ class DescriptorBuilder {
const ServiceDescriptor* parent,
MethodDescriptor* result);
+ void LogUnusedDependency(const FileDescriptor* result);
+
// Must be run only after building.
//
// NOTE: Options will not be available during cross-linking, as they
@@ -2157,6 +2983,9 @@ class DescriptorBuilder {
static inline bool get_allow_unknown(const DescriptorPool* pool) {
return pool->allow_unknown_;
}
+ static inline bool get_enforce_weak(const DescriptorPool* pool) {
+ return pool->enforce_weak_;
+ }
static inline bool get_is_placeholder(const Descriptor* descriptor) {
return descriptor->is_placeholder_;
}
@@ -2186,9 +3015,25 @@ class DescriptorBuilder {
const ServiceDescriptorProto& proto);
void ValidateMethodOptions(MethodDescriptor* method,
const MethodDescriptorProto& 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);
- void ValidateMapKey(FieldDescriptor* field,
- const FieldDescriptorProto& proto);
};
const FileDescriptor* DescriptorPool::BuildFile(
@@ -2198,6 +3043,8 @@ const FileDescriptor* DescriptorPool::BuildFile(
"DescriptorDatabase. You must instead find a way to get your file "
"into the underlying database.";
GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK.
+ tables_->known_bad_symbols_.clear();
+ tables_->known_bad_files_.clear();
return DescriptorBuilder(this, tables_.get(), NULL).BuildFile(proto);
}
@@ -2209,6 +3056,8 @@ const FileDescriptor* DescriptorPool::BuildFileCollectingErrors(
"DescriptorDatabase. You must instead find a way to get your file "
"into the underlying database.";
GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK.
+ tables_->known_bad_symbols_.clear();
+ tables_->known_bad_files_.clear();
return DescriptorBuilder(this, tables_.get(),
error_collector).BuildFile(proto);
}
@@ -2216,8 +3065,16 @@ const FileDescriptor* DescriptorPool::BuildFileCollectingErrors(
const FileDescriptor* DescriptorPool::BuildFileFromDatabase(
const FileDescriptorProto& proto) const {
mutex_->AssertHeld();
- return DescriptorBuilder(this, tables_.get(),
- default_error_collector_).BuildFile(proto);
+ if (tables_->known_bad_files_.count(proto.name()) > 0) {
+ return NULL;
+ }
+ const FileDescriptor* result =
+ DescriptorBuilder(this, tables_.get(),
+ default_error_collector_).BuildFile(proto);
+ if (result == NULL) {
+ tables_->known_bad_files_.insert(proto.name());
+ }
+ return result;
}
DescriptorBuilder::DescriptorBuilder(
@@ -2228,7 +3085,8 @@ DescriptorBuilder::DescriptorBuilder(
tables_(tables),
error_collector_(error_collector),
had_errors_(false),
- possible_undeclared_dependency_(NULL) {}
+ possible_undeclared_dependency_(NULL),
+ undefine_resolved_name_("") {}
DescriptorBuilder::~DescriptorBuilder() {}
@@ -2250,21 +3108,53 @@ void DescriptorBuilder::AddError(
had_errors_ = true;
}
+void DescriptorBuilder::AddError(
+ const string& element_name,
+ const Message& descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ const char* error) {
+ AddError(element_name, descriptor, location, string(error));
+}
+
void DescriptorBuilder::AddNotDefinedError(
const string& element_name,
const Message& descriptor,
DescriptorPool::ErrorCollector::ErrorLocation location,
const string& undefined_symbol) {
- if (possible_undeclared_dependency_ == NULL) {
+ if (possible_undeclared_dependency_ == NULL &&
+ undefine_resolved_name_.empty()) {
AddError(element_name, descriptor, location,
"\"" + undefined_symbol + "\" is not defined.");
} else {
- AddError(element_name, descriptor, location,
- "\"" + possible_undeclared_dependency_name_ +
- "\" seems to be defined in \"" +
- possible_undeclared_dependency_->name() + "\", which is not "
- "imported by \"" + filename_ + "\". To use it here, please "
- "add the necessary import.");
+ if (possible_undeclared_dependency_ != NULL) {
+ AddError(element_name, descriptor, location,
+ "\"" + possible_undeclared_dependency_name_ +
+ "\" seems to be defined in \"" +
+ possible_undeclared_dependency_->name() + "\", which is not "
+ "imported by \"" + filename_ + "\". To use it here, please "
+ "add the necessary import.");
+ }
+ if (!undefine_resolved_name_.empty()) {
+ AddError(element_name, descriptor, location,
+ "\"" + undefined_symbol + "\" is resolved to \"" +
+ undefine_resolved_name_ + "\", which is not defined. "
+ "The innermost scope is searched first in name resolution. "
+ "Consider using a leading '.'(i.e., \"."
+ + undefined_symbol +
+ "\") to start from the outermost scope.");
+ }
+ }
+}
+
+void DescriptorBuilder::AddWarning(
+ const string& element_name, const Message& descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ const string& error) {
+ if (error_collector_ == NULL) {
+ GOOGLE_LOG(WARNING) << filename_ << " " << element_name << ": " << error;
+ } else {
+ error_collector_->AddWarning(filename_, element_name, &descriptor, location,
+ error);
}
}
@@ -2275,31 +3165,48 @@ bool DescriptorBuilder::IsInPackage(const FileDescriptor* file,
file->package()[package_name.size()] == '.');
}
-Symbol DescriptorBuilder::FindSymbolNotEnforcingDeps(const string& name) {
- Symbol result;
+void DescriptorBuilder::RecordPublicDependencies(const FileDescriptor* file) {
+ if (file == NULL || !dependencies_.insert(file).second) return;
+ for (int i = 0; file != NULL && i < file->public_dependency_count(); i++) {
+ RecordPublicDependencies(file->public_dependency(i));
+ }
+}
- // We need to search our pool and all its underlays.
- const DescriptorPool* pool = pool_;
- while (true) {
- // If we are looking at an underlay, we must lock its mutex_, since we are
- // accessing the underlay's tables_ dircetly.
- MutexLockMaybe lock((pool == pool_) ? NULL : pool->mutex_);
+Symbol DescriptorBuilder::FindSymbolNotEnforcingDepsHelper(
+ const DescriptorPool* pool, const string& name) {
+ // If we are looking at an underlay, we must lock its mutex_, since we are
+ // accessing the underlay's tables_ directly.
+ MutexLockMaybe lock((pool == pool_) ? NULL : pool->mutex_);
- // Note that we don't have to check fallback_database_ here because the
- // symbol has to be in one of its file's direct dependencies, and we have
- // already loaded those by the time we get here.
- result = pool->tables_->FindSymbol(name);
- if (!result.IsNull()) break;
- if (pool->underlay_ == NULL) return kNullSymbol;
- pool = pool->underlay_;
+ Symbol result = pool->tables_->FindSymbol(name);
+ if (result.IsNull() && pool->underlay_ != NULL) {
+ // Symbol not found; check the underlay.
+ result = FindSymbolNotEnforcingDepsHelper(pool->underlay_, name);
+ }
+
+ if (result.IsNull()) {
+ // In theory, we shouldn't need to check fallback_database_ because the
+ // symbol should be in one of its file's direct dependencies, and we have
+ // already loaded those by the time we get here. But we check anyway so
+ // that we can generate better error message when dependencies are missing
+ // (i.e., "missing dependency" rather than "type is not defined").
+ if (pool->TryFindSymbolInFallbackDatabase(name)) {
+ result = pool->tables_->FindSymbol(name);
+ }
}
return result;
}
+Symbol DescriptorBuilder::FindSymbolNotEnforcingDeps(const string& name) {
+ return FindSymbolNotEnforcingDepsHelper(pool_, name);
+}
+
Symbol DescriptorBuilder::FindSymbol(const string& name) {
Symbol result = FindSymbolNotEnforcingDeps(name);
+ if (result.IsNull()) return result;
+
if (!pool_->enforce_dependencies_) {
// Hack for CompilerUpgrader.
return result;
@@ -2308,9 +3215,9 @@ Symbol DescriptorBuilder::FindSymbol(const string& name) {
// Only find symbols which were defined in this file or one of its
// dependencies.
const FileDescriptor* file = result.GetFile();
- if (file == file_) return result;
- for (int i = 0; i < file_->dependency_count(); i++) {
- if (file == file_->dependency(i)) return result;
+ if (file == file_ || dependencies_.count(file) > 0) {
+ unused_dependency_.erase(file);
+ return result;
}
if (result.type == Symbol::PACKAGE) {
@@ -2322,12 +3229,10 @@ Symbol DescriptorBuilder::FindSymbol(const string& name) {
// dependency also defines the same package. We can't really rule out this
// symbol unless none of the dependencies define it.
if (IsInPackage(file_, name)) return result;
- for (int i = 0; i < file_->dependency_count(); i++) {
+ for (set<const FileDescriptor*>::const_iterator it = dependencies_.begin();
+ it != dependencies_.end(); ++it) {
// Note: A dependency may be NULL if it was not found or had errors.
- if (file_->dependency(i) != NULL &&
- IsInPackage(file_->dependency(i), name)) {
- return result;
- }
+ if (*it != NULL && IsInPackage(*it, name)) return result;
}
}
@@ -2339,6 +3244,7 @@ Symbol DescriptorBuilder::FindSymbol(const string& name) {
Symbol DescriptorBuilder::LookupSymbolNoPlaceholder(
const string& name, const string& relative_to, ResolveMode resolve_mode) {
possible_undeclared_dependency_ = NULL;
+ undefine_resolved_name_.clear();
if (name.size() > 0 && name[0] == '.') {
// Fully-qualified name.
@@ -2356,7 +3262,7 @@ Symbol DescriptorBuilder::LookupSymbolNoPlaceholder(
// }
// So, we look for just "Foo" first, then look for "Bar.baz" within it if
// found.
- int name_dot_pos = name.find_first_of('.');
+ string::size_type name_dot_pos = name.find_first_of('.');
string first_part_of_name;
if (name_dot_pos == string::npos) {
first_part_of_name = name;
@@ -2387,7 +3293,11 @@ Symbol DescriptorBuilder::LookupSymbolNoPlaceholder(
if (result.IsAggregate()) {
scope_to_try.append(name, first_part_of_name.size(),
name.size() - first_part_of_name.size());
- return FindSymbol(scope_to_try);
+ result = FindSymbol(scope_to_try);
+ if (result.IsNull()) {
+ undefine_resolved_name_ = scope_to_try;
+ }
+ return result;
} else {
// We found a symbol but it's not an aggregate. Continue the loop.
}
@@ -2440,21 +3350,14 @@ Symbol DescriptorBuilder::NewPlaceholder(const string& name,
placeholder_name = tables_->AllocateString(
placeholder_full_name->substr(dotpos + 1));
} else {
- placeholder_package = &kEmptyString;
+ placeholder_package = &internal::GetEmptyString();
placeholder_name = placeholder_full_name;
}
// Create the placeholders.
- FileDescriptor* placeholder_file = tables_->Allocate<FileDescriptor>();
- memset(placeholder_file, 0, sizeof(*placeholder_file));
-
- 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;
- // All other fields are zero or NULL.
if (placeholder_type == PLACEHOLDER_ENUM) {
placeholder_file->enum_type_count_ = 1;
@@ -2518,16 +3421,19 @@ Symbol DescriptorBuilder::NewPlaceholder(const string& name,
}
}
-const FileDescriptor* DescriptorBuilder::NewPlaceholderFile(
+FileDescriptor* DescriptorBuilder::NewPlaceholderFile(
const string& name) {
FileDescriptor* placeholder = tables_->Allocate<FileDescriptor>();
memset(placeholder, 0, sizeof(*placeholder));
placeholder->name_ = tables_->AllocateString(name);
- placeholder->package_ = &kEmptyString;
+ placeholder->package_ = &internal::GetEmptyString();
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;
@@ -2668,7 +3574,11 @@ template<class DescriptorT> void DescriptorBuilder::AllocateOptionsImpl(
// tables_->AllocateMessage<typename DescriptorT::OptionsType>();
typename DescriptorT::OptionsType* const dummy = NULL;
typename DescriptorT::OptionsType* options = tables_->AllocateMessage(dummy);
- options->CopyFrom(orig_options);
+ // Avoid using MergeFrom()/CopyFrom() in this class to make it -fno-rtti
+ // friendly. Without RTTI, MergeFrom() and CopyFrom() will fallback to the
+ // reflection based method, which requires the Descriptor. However, we are in
+ // the middle of building the descriptors, thus the deadlock.
+ options->ParseFromString(orig_options.SerializeAsString());
descriptor->options_ = options;
// Don't add to options_to_interpret_ unless there were uninterpreted
@@ -2694,6 +3604,45 @@ template<class DescriptorT> void DescriptorBuilder::AllocateOptionsImpl(
METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i); \
}
+void DescriptorBuilder::AddRecursiveImportError(
+ const FileDescriptorProto& proto, int from_here) {
+ string error_message("File recursively imports itself: ");
+ for (int i = from_here; i < tables_->pending_files_.size(); i++) {
+ error_message.append(tables_->pending_files_[i]);
+ error_message.append(" -> ");
+ }
+ error_message.append(proto.name());
+
+ AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+ error_message);
+}
+
+void DescriptorBuilder::AddTwiceListedError(const FileDescriptorProto& proto,
+ int index) {
+ AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+ "Import \"" + proto.dependency(index) + "\" was listed twice.");
+}
+
+void DescriptorBuilder::AddImportError(const FileDescriptorProto& proto,
+ int index) {
+ string message;
+ if (pool_->fallback_database_ == NULL) {
+ message = "Import \"" + proto.dependency(index) +
+ "\" has not been loaded.";
+ } else {
+ message = "Import \"" + proto.dependency(index) +
+ "\" was not found or had errors.";
+ }
+ AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER, message);
+}
+
+static bool ExistingFileMatchesProto(const FileDescriptor* existing_file,
+ const FileDescriptorProto& proto) {
+ FileDescriptorProto existing_proto;
+ existing_file->CopyTo(&existing_proto);
+ return existing_proto.SerializeAsString() == proto.SerializeAsString();
+}
+
const FileDescriptor* DescriptorBuilder::BuildFile(
const FileDescriptorProto& proto) {
filename_ = proto.name();
@@ -2702,13 +3651,11 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
// Note: This only works if the input is canonical -- that is, it
// fully-qualifies all type names, has no UninterpretedOptions, etc.
// This is fine, because this idempotency "feature" really only exists to
- // accomodate one hack in the proto1->proto2 migration layer.
+ // accommodate one hack in the proto1->proto2 migration layer.
const FileDescriptor* existing_file = tables_->FindFile(filename_);
if (existing_file != NULL) {
// File already in pool. Compare the existing one to the input.
- FileDescriptorProto existing_proto;
- existing_file->CopyTo(&existing_proto);
- if (existing_proto.SerializeAsString() == proto.SerializeAsString()) {
+ if (ExistingFileMatchesProto(existing_file, proto)) {
// They're identical. Return the existing descriptor.
return existing_file;
}
@@ -2727,15 +3674,7 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
// at all.
for (int i = 0; i < tables_->pending_files_.size(); i++) {
if (tables_->pending_files_[i] == proto.name()) {
- string error_message("File recursively imports itself: ");
- for (; i < tables_->pending_files_.size(); i++) {
- error_message.append(tables_->pending_files_[i]);
- error_message.append(" -> ");
- }
- error_message.append(proto.name());
-
- AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
- error_message);
+ AddRecursiveImportError(proto, i);
return NULL;
}
}
@@ -2757,11 +3696,20 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
}
// Checkpoint the tables so that we can roll back if something goes wrong.
- tables_->Checkpoint();
+ tables_->AddCheckpoint();
FileDescriptor* result = tables_->Allocate<FileDescriptor>();
file_ = result;
+ result->is_placeholder_ = false;
+ if (proto.has_source_code_info()) {
+ SourceCodeInfo *info = tables_->AllocateMessage<SourceCodeInfo>();
+ info->CopyFrom(proto.source_code_info());
+ result->source_code_info_ = info;
+ } else {
+ result->source_code_info_ = &SourceCodeInfo::default_instance();
+ }
+
file_tables_ = tables_->AllocateFileTables();
file_->tables_ = file_tables_;
@@ -2770,6 +3718,18 @@ 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());
@@ -2788,7 +3748,7 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
"A file with this name is already in the pool.");
// Bail out early so that if this is actually the exact same file, we
// don't end up reporting that every single symbol is already defined.
- tables_->Rollback();
+ tables_->RollbackToLastCheckpoint();
return NULL;
}
if (!result->package().empty()) {
@@ -2800,11 +3760,14 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
result->dependency_count_ = proto.dependency_size();
result->dependencies_ =
tables_->AllocateArray<const FileDescriptor*>(proto.dependency_size());
+ unused_dependency_.clear();
+ set<int> weak_deps;
+ for (int i = 0; i < proto.weak_dependency_size(); ++i) {
+ weak_deps.insert(proto.weak_dependency(i));
+ }
for (int i = 0; i < proto.dependency_size(); i++) {
if (!seen_dependencies.insert(proto.dependency(i)).second) {
- AddError(proto.name(), proto,
- DescriptorPool::ErrorCollector::OTHER,
- "Import \"" + proto.dependency(i) + "\" was listed twice.");
+ AddTwiceListedError(proto, i);
}
const FileDescriptor* dependency = tables_->FindFile(proto.dependency(i));
@@ -2813,26 +3776,67 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
}
if (dependency == NULL) {
- if (pool_->allow_unknown_) {
+ if (pool_->allow_unknown_ ||
+ (!pool_->enforce_weak_ && weak_deps.find(i) != weak_deps.end())) {
dependency = NewPlaceholderFile(proto.dependency(i));
} else {
- string message;
- if (pool_->fallback_database_ == NULL) {
- message = "Import \"" + proto.dependency(i) +
- "\" has not been loaded.";
- } else {
- message = "Import \"" + proto.dependency(i) +
- "\" was not found or had errors.";
- }
- AddError(proto.name(), proto,
- DescriptorPool::ErrorCollector::OTHER,
- message);
+ AddImportError(proto, i);
+ }
+ } else {
+ // Add to unused_dependency_ to track unused imported files.
+ // Note: do not track unused imported files for public import.
+ if (pool_->enforce_dependencies_ &&
+ (pool_->unused_import_track_files_.find(proto.name()) !=
+ pool_->unused_import_track_files_.end()) &&
+ (dependency->public_dependency_count() == 0)) {
+ unused_dependency_.insert(dependency);
}
}
result->dependencies_[i] = dependency;
}
+ // Check public dependencies.
+ int public_dependency_count = 0;
+ result->public_dependencies_ = tables_->AllocateArray<int>(
+ proto.public_dependency_size());
+ for (int i = 0; i < proto.public_dependency_size(); i++) {
+ // Only put valid public dependency indexes.
+ int index = proto.public_dependency(i);
+ if (index >= 0 && index < proto.dependency_size()) {
+ result->public_dependencies_[public_dependency_count++] = index;
+ // Do not track unused imported files for public import.
+ unused_dependency_.erase(result->dependency(index));
+ } else {
+ AddError(proto.name(), proto,
+ DescriptorPool::ErrorCollector::OTHER,
+ "Invalid public dependency index.");
+ }
+ }
+ result->public_dependency_count_ = public_dependency_count;
+
+ // Build dependency set
+ dependencies_.clear();
+ for (int i = 0; i < result->dependency_count(); i++) {
+ RecordPublicDependencies(result->dependency(i));
+ }
+
+ // Check weak dependencies.
+ int weak_dependency_count = 0;
+ result->weak_dependencies_ = tables_->AllocateArray<int>(
+ proto.weak_dependency_size());
+ for (int i = 0; i < proto.weak_dependency_size(); i++) {
+ int index = proto.weak_dependency(i);
+ if (index >= 0 && index < proto.dependency_size()) {
+ result->weak_dependencies_[weak_dependency_count++] = index;
+ } else {
+ AddError(proto.name(), proto,
+ DescriptorPool::ErrorCollector::OTHER,
+ "Invalid weak dependency index.");
+ }
+ }
+ result->weak_dependency_count_ = weak_dependency_count;
+
// Convert children.
BUILD_ARRAY(proto, result, message_type, BuildMessage , NULL);
BUILD_ARRAY(proto, result, enum_type , BuildEnum , NULL);
@@ -2869,11 +3873,24 @@ 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);
+ }
+
if (had_errors_) {
- tables_->Rollback();
+ tables_->RollbackToLastCheckpoint();
return NULL;
} else {
- tables_->Checkpoint();
+ tables_->ClearLastCheckpoint();
return result;
}
}
@@ -2896,6 +3913,8 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
result->is_placeholder_ = false;
result->is_unqualified_placeholder_ = false;
+ // Build oneofs first so that fields and extension ranges can refer to them.
+ BUILD_ARRAY(proto, result, oneof_decl , BuildOneof , result);
BUILD_ARRAY(proto, result, field , BuildField , result);
BUILD_ARRAY(proto, result, nested_type , BuildMessage , result);
BUILD_ARRAY(proto, result, enum_type , BuildEnum , result);
@@ -2977,7 +3996,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.
@@ -2986,10 +4007,22 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
result->label_ = static_cast<FieldDescriptor::Label>(
implicit_cast<int>(proto.label()));
+ // An extension cannot have a required field (b/13365836).
+ if (result->is_extension_ &&
+ result->label_ == FieldDescriptor::LABEL_REQUIRED) {
+ AddError(result->full_name(), proto,
+ // Error location `TYPE`: we would really like to indicate
+ // `LABEL`, but the `ErrorLocation` enum has no entry for this, and
+ // we don't necessarily know about all implementations of the
+ // `ErrorCollector` interface to extend them to handle the new
+ // error location type properly.
+ DescriptorPool::ErrorCollector::TYPE,
+ "Message extensions cannot have required fields.");
+ }
+
// 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;
@@ -3029,7 +4062,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
result->default_value_float_ = numeric_limits<float>::quiet_NaN();
} else {
result->default_value_float_ =
- NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
+ io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
}
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
@@ -3041,7 +4074,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
result->default_value_double_ = numeric_limits<double>::quiet_NaN();
} else {
result->default_value_double_ =
- NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
+ io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
}
break;
case FieldDescriptor::CPPTYPE_BOOL:
@@ -3065,7 +4098,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
UnescapeCEscapeString(proto.default_value()));
} else {
result->default_value_string_ =
- tables_->AllocateString(proto.default_value());
+ tables_->AllocateString(proto.default_value());
}
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
@@ -3083,7 +4116,8 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
if (proto.default_value().empty() || *end_pos != '\0') {
AddError(result->full_name(), proto,
DescriptorPool::ErrorCollector::DEFAULT_VALUE,
- "Couldn't parse default value.");
+ "Couldn't parse default value \"" + proto.default_value() +
+ "\".");
}
}
} else {
@@ -3115,7 +4149,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
result->default_value_enum_ = NULL;
break;
case FieldDescriptor::CPPTYPE_STRING:
- result->default_value_string_ = &kEmptyString;
+ result->default_value_string_ = &internal::GetEmptyString();
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
break;
@@ -3126,7 +4160,15 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
if (result->number() <= 0) {
AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
"Field numbers must be positive integers.");
- } else if (result->number() > FieldDescriptor::kMaxNumber) {
+ } else if (!is_extension && result->number() > FieldDescriptor::kMaxNumber) {
+ // Only validate that the number is within the valid field range if it is
+ // not an extension. Since extension numbers are validated with the
+ // extendee's valid set of extension numbers, and those are in turn
+ // validated against the max allowed number, the check is unnecessary for
+ // extension fields.
+ // This avoids cross-linking issues that arise when attempting to check if
+ // the extendee is a message_set_wire_format message, which has a higher max
+ // on extension numbers.
AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
strings::Substitute("Field numbers cannot be greater than $0.",
FieldDescriptor::kMaxNumber));
@@ -3148,6 +4190,16 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
}
result->extension_scope_ = parent;
+
+ if (proto.has_oneof_index()) {
+ AddError(result->full_name(), proto,
+ DescriptorPool::ErrorCollector::OTHER,
+ "FieldDescriptorProto.oneof_index should not be set for "
+ "extensions.");
+ }
+
+ // Fill in later (maybe).
+ result->containing_oneof_ = NULL;
} else {
if (proto.has_extendee()) {
AddError(result->full_name(), proto,
@@ -3156,6 +4208,23 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
}
result->containing_type_ = parent;
+
+ if (proto.has_oneof_index()) {
+ if (proto.oneof_index() < 0 ||
+ proto.oneof_index() >= parent->oneof_decl_count()) {
+ AddError(result->full_name(), proto,
+ DescriptorPool::ErrorCollector::OTHER,
+ strings::Substitute("FieldDescriptorProto.oneof_index $0 is "
+ "out of range for type \"$1\".",
+ proto.oneof_index(),
+ parent->name()));
+ result->containing_oneof_ = NULL;
+ } else {
+ result->containing_oneof_ = parent->oneof_decl(proto.oneof_index());
+ }
+ } else {
+ result->containing_oneof_ = NULL;
+ }
}
// Copy options.
@@ -3181,12 +4250,10 @@ void DescriptorBuilder::BuildExtensionRange(
"Extension numbers must be positive integers.");
}
- if (result->end > FieldDescriptor::kMaxNumber + 1) {
- AddError(parent->full_name(), proto,
- DescriptorPool::ErrorCollector::NUMBER,
- strings::Substitute("Extension numbers cannot be greater than $0.",
- FieldDescriptor::kMaxNumber));
- }
+ // Checking of the upper bound of the extension range is deferred until after
+ // options interpreting. This allows messages with message_set_wire_format to
+ // have extensions beyond FieldDescriptor::kMaxNumber, since the extension
+ // numbers are actually used as int32s in the message_set_wire_format.
if (result->start >= result->end) {
AddError(parent->full_name(), proto,
@@ -3195,6 +4262,28 @@ void DescriptorBuilder::BuildExtensionRange(
}
}
+void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
+ Descriptor* parent,
+ OneofDescriptor* result) {
+ string* full_name = tables_->AllocateString(parent->full_name());
+ full_name->append(1, '.');
+ full_name->append(proto.name());
+
+ ValidateSymbolName(proto.name(), *full_name, proto);
+
+ result->name_ = tables_->AllocateString(proto.name());
+ result->full_name_ = full_name;
+
+ result->containing_type_ = parent;
+
+ // We need to fill these in later.
+ result->field_count_ = 0;
+ result->fields_ = NULL;
+
+ AddSymbol(result->full_name(), parent, result->name(),
+ proto, Symbol(result));
+}
+
void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
const Descriptor* parent,
EnumDescriptor* result) {
@@ -3303,7 +4392,7 @@ void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto,
}
void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto,
- const void* dummy,
+ const void* /* dummy */,
ServiceDescriptor* result) {
string* full_name = tables_->AllocateString(file_->package());
if (!full_name->empty()) full_name->append(1, '.');
@@ -3352,6 +4441,9 @@ void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto,
AllocateOptions(proto.options(), result);
}
+ result->client_streaming_ = proto.client_streaming();
+ result->server_streaming_ = proto.server_streaming();
+
AddSymbol(result->full_name(), parent, result->name(),
proto, Symbol(result));
}
@@ -3404,6 +4496,46 @@ void DescriptorBuilder::CrossLinkMessage(
for (int i = 0; i < message->extension_count(); i++) {
CrossLinkField(&message->extensions_[i], proto.extension(i));
}
+
+ // Set up field array for each oneof.
+
+ // First count the number of fields per oneof.
+ for (int i = 0; i < message->field_count(); i++) {
+ const OneofDescriptor* oneof_decl = message->field(i)->containing_oneof();
+ if (oneof_decl != NULL) {
+ // Must go through oneof_decls_ array to get a non-const version of the
+ // OneofDescriptor.
+ ++message->oneof_decls_[oneof_decl->index()].field_count_;
+ }
+ }
+
+ // Then allocate the arrays.
+ for (int i = 0; i < message->oneof_decl_count(); i++) {
+ OneofDescriptor* oneof_decl = &message->oneof_decls_[i];
+
+ if (oneof_decl->field_count() == 0) {
+ AddError(message->full_name() + "." + oneof_decl->name(),
+ proto.oneof_decl(i),
+ DescriptorPool::ErrorCollector::NAME,
+ "Oneof must have at least one field.");
+ }
+
+ oneof_decl->fields_ =
+ tables_->AllocateArray<const FieldDescriptor*>(oneof_decl->field_count_);
+ oneof_decl->field_count_ = 0;
+ }
+
+ // Then fill them in.
+ for (int i = 0; i < message->field_count(); i++) {
+ const OneofDescriptor* oneof_decl = message->field(i)->containing_oneof();
+ if (oneof_decl != NULL) {
+ OneofDescriptor* mutable_oneof_decl =
+ &message->oneof_decls_[oneof_decl->index()];
+ message->fields_[i].index_in_oneof_ = mutable_oneof_decl->field_count_;
+ mutable_oneof_decl->fields_[mutable_oneof_decl->field_count_++] =
+ message->field(i);
+ }
+ }
}
void DescriptorBuilder::CrossLinkField(
@@ -3428,7 +4560,10 @@ void DescriptorBuilder::CrossLinkField(
}
field->containing_type_ = extendee.descriptor;
- if (!field->containing_type()->IsExtensionNumber(field->number())) {
+ const Descriptor::ExtensionRange* extension_range = field->containing_type()
+ ->FindExtensionRangeContainingNumber(field->number());
+
+ if (extension_range == NULL) {
AddError(field->full_name(), proto,
DescriptorPool::ErrorCollector::NUMBER,
strings::Substitute("\"$0\" does not declare $1 as an "
@@ -3438,6 +4573,17 @@ void DescriptorBuilder::CrossLinkField(
}
}
+ if (field->containing_oneof() != NULL) {
+ if (field->label() != FieldDescriptor::LABEL_OPTIONAL) {
+ // Note that this error will never happen when parsing .proto files.
+ // It can only happen if you manually construct a FileDescriptorProto
+ // that is incorrect.
+ AddError(field->full_name(), proto,
+ DescriptorPool::ErrorCollector::NAME,
+ "Fields of oneofs must themselves have label LABEL_OPTIONAL.");
+ }
+ }
+
if (proto.has_type_name()) {
// Assume we are expecting a message type unless the proto contains some
// evidence that it expects an enum type. This only makes a difference if
@@ -3450,6 +4596,11 @@ void DescriptorBuilder::CrossLinkField(
expecting_enum ? PLACEHOLDER_ENUM : PLACEHOLDER_MESSAGE,
LOOKUP_TYPES);
+ // If the type is a weak type, we change the type to a google.protobuf.Empty field.
+ if (type.IsNull() && !pool_->enforce_weak_ && proto.options().weak()) {
+ type = FindSymbol(kNonLinkedWeakMessageReplacementName);
+ }
+
if (type.IsNull()) {
AddNotDefinedError(field->full_name(), proto,
DescriptorPool::ErrorCollector::TYPE,
@@ -3501,21 +4652,34 @@ void DescriptorBuilder::CrossLinkField(
}
if (field->has_default_value()) {
- // We can't just use field->enum_type()->FindValueByName() here
- // because that locks the pool's mutex, which we have already locked
- // at this point.
- Symbol default_value =
- LookupSymbolNoPlaceholder(proto.default_value(),
- field->enum_type()->full_name());
-
- if (default_value.type == Symbol::ENUM_VALUE &&
- default_value.enum_value_descriptor->type() == field->enum_type()) {
- field->default_value_enum_ = default_value.enum_value_descriptor;
- } else {
+ // Ensure that the default value is an identifier. Parser cannot always
+ // verify this because it does not have complete type information.
+ // N.B. that this check yields better error messages but is not
+ // necessary for correctness (an enum symbol must be a valid identifier
+ // anyway), only for better errors.
+ if (!io::Tokenizer::IsIdentifier(proto.default_value())) {
AddError(field->full_name(), proto,
DescriptorPool::ErrorCollector::DEFAULT_VALUE,
- "Enum type \"" + field->enum_type()->full_name() +
- "\" has no value named \"" + proto.default_value() + "\".");
+ "Default value for an enum field must be an identifier.");
+ } else {
+ // We can't just use field->enum_type()->FindValueByName() here
+ // because that locks the pool's mutex, which we have already locked
+ // at this point.
+ Symbol default_value =
+ LookupSymbolNoPlaceholder(proto.default_value(),
+ field->enum_type()->full_name());
+
+ if (default_value.type == Symbol::ENUM_VALUE &&
+ default_value.enum_value_descriptor->type() ==
+ field->enum_type()) {
+ field->default_value_enum_ = default_value.enum_value_descriptor;
+ } else {
+ AddError(field->full_name(), proto,
+ DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+ "Enum type \"" + field->enum_type()->full_name() +
+ "\" has no value named \"" + proto.default_value() +
+ "\".");
+ }
}
} else if (field->enum_type()->value_count() > 0) {
// All enums must have at least one value, or we would have reported
@@ -3559,12 +4723,26 @@ void DescriptorBuilder::CrossLinkField(
field->containing_type()->full_name(),
conflicting_field->name()));
}
- }
-
- if (field->is_extension()) {
- // No need for error checking: if the extension number collided,
- // we've already been informed of it by the if() above.
- tables_->AddExtension(field);
+ } else {
+ if (field->is_extension()) {
+ if (!tables_->AddExtension(field)) {
+ const FieldDescriptor* conflicting_field =
+ tables_->FindExtension(field->containing_type(), field->number());
+ string error_msg = strings::Substitute(
+ "Extension number $0 has already been used in \"$1\" by extension "
+ "\"$2\" defined in $3.",
+ field->number(),
+ field->containing_type()->full_name(),
+ conflicting_field->full_name(),
+ conflicting_field->file()->name());
+ // Conflicting extension numbers should be an error. However, before
+ // turning this into an error we need to fix all existing broken
+ // protos first.
+ // TODO(xiaofeng): Change this to an error.
+ AddWarning(field->full_name(), proto,
+ DescriptorPool::ErrorCollector::NUMBER, error_msg);
+ }
+ }
}
// Add the field to the lowercase-name and camelcase-name tables.
@@ -3583,7 +4761,8 @@ void DescriptorBuilder::CrossLinkEnum(
}
void DescriptorBuilder::CrossLinkEnumValue(
- EnumValueDescriptor* enum_value, const EnumValueDescriptorProto& proto) {
+ EnumValueDescriptor* enum_value,
+ const EnumValueDescriptorProto& /* proto */) {
if (enum_value->options_ == NULL) {
enum_value->options_ = &EnumValueOptions::default_instance();
}
@@ -3647,7 +4826,6 @@ static bool IsLite(const FileDescriptor* file) {
// TODO(kenton): I don't even remember how many of these conditions are
// actually possible. I'm just being super-safe.
return file != NULL &&
- &file->options() != NULL &&
&file->options() != &FileOptions::default_instance() &&
file->options().optimize_for() == FileOptions::LITE_RUNTIME;
}
@@ -3673,6 +4851,97 @@ 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,
@@ -3681,12 +4950,31 @@ void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
VALIDATE_OPTIONS_FROM_ARRAY(message, nested_type, Message);
VALIDATE_OPTIONS_FROM_ARRAY(message, enum_type, Enum);
VALIDATE_OPTIONS_FROM_ARRAY(message, extension, Field);
+
+ const int64 max_extension_range =
+ static_cast<int64>(message->options().message_set_wire_format() ?
+ kint32max :
+ FieldDescriptor::kMaxNumber);
+ for (int i = 0; i < message->extension_range_count(); ++i) {
+ if (message->extension_range(i)->end > max_extension_range + 1) {
+ AddError(
+ message->full_name(), proto.extension_range(i),
+ DescriptorPool::ErrorCollector::NUMBER,
+ strings::Substitute("Extension numbers cannot be greater than $0.",
+ max_extension_range));
+ }
+ }
}
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) {
+ AddError(field->full_name(), proto,
+ DescriptorPool::ErrorCollector::TYPE,
+ "[lazy = true] can only be specified for submessage fields.");
+ }
}
// Only repeated primitive fields may be packed.
@@ -3727,15 +5015,52 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
"files. Note that you cannot extend a non-lite type to contain "
"a lite type, but the reverse is allowed.");
}
+
+ // Validate map types.
+ if (field->is_map()) {
+ if (!ValidateMapEntry(field, proto)) {
+ AddError(field->full_name(), proto,
+ DescriptorPool::ErrorCollector::OTHER,
+ "map_entry should not be set explicitly. Use map<KeyType, "
+ "ValueType> instead.");
+ }
+ }
+
}
void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm,
const EnumDescriptorProto& proto) {
VALIDATE_OPTIONS_FROM_ARRAY(enm, value, EnumValue);
+ if (!enm->options().has_allow_alias() || !enm->options().allow_alias()) {
+ map<int, string> used_values;
+ for (int i = 0; i < enm->value_count(); ++i) {
+ const EnumValueDescriptor* enum_value = enm->value(i);
+ if (used_values.find(enum_value->number()) != used_values.end()) {
+ string error =
+ "\"" + enum_value->full_name() +
+ "\" uses the same enum value as \"" +
+ used_values[enum_value->number()] + "\". If this is intended, set "
+ "'option allow_alias = true;' to the enum definition.";
+ if (!enm->options().allow_alias()) {
+ // Generate error if duplicated enum values are explicitly disallowed.
+ AddError(enm->full_name(), proto,
+ DescriptorPool::ErrorCollector::NUMBER,
+ error);
+ } else {
+ // Generate warning if duplicated values are found but the option
+ // isn't set.
+ GOOGLE_LOG(ERROR) << error;
+ }
+ } else {
+ used_values[enum_value->number()] = enum_value->full_name();
+ }
+ }
+ }
}
void DescriptorBuilder::ValidateEnumValueOptions(
- EnumValueDescriptor* enum_value, const EnumValueDescriptorProto& proto) {
+ EnumValueDescriptor* /* enum_value */,
+ const EnumValueDescriptorProto& /* proto */) {
// Nothing to do so far.
}
void DescriptorBuilder::ValidateServiceOptions(ServiceDescriptor* service,
@@ -3753,64 +5078,135 @@ void DescriptorBuilder::ValidateServiceOptions(ServiceDescriptor* service,
VALIDATE_OPTIONS_FROM_ARRAY(service, method, Method);
}
-void DescriptorBuilder::ValidateMethodOptions(MethodDescriptor* method,
- const MethodDescriptorProto& proto) {
+void DescriptorBuilder::ValidateMethodOptions(MethodDescriptor* /* method */,
+ const MethodDescriptorProto& /* proto */) {
// 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 complain 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<string, const Descriptor*> seen_types;
+ for (int i = 0; i < message->nested_type_count(); ++i) {
+ const Descriptor* nested = message->nested_type(i);
+ pair<map<string, const Descriptor*>::iterator, bool> result =
+ seen_types.insert(std::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<string, const Descriptor*>::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<string, const Descriptor*>::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<string, const Descriptor*>::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;
}
+
#undef VALIDATE_OPTIONS_FROM_ARRAY
// -------------------------------------------------------------------
@@ -3901,9 +5297,11 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
// file we're currently building. The descriptor should be there as long as
// the file we're building imported "google/protobuf/descriptors.proto".
- // Note that we use DescriptorBuilder::FindSymbol(), not
+ // Note that we use DescriptorBuilder::FindSymbolNotEnforcingDeps(), not
// DescriptorPool::FindMessageTypeByName() because we're already holding the
- // pool's mutex, and the latter method locks it again.
+ // pool's mutex, and the latter method locks it again. We don't use
+ // FindSymbol() because files that use custom options only need to depend on
+ // the file that defines the option, not descriptor.proto itself.
Symbol symbol = builder_->FindSymbolNotEnforcingDeps(
options->GetDescriptor()->full_name());
if (!symbol.IsNull() && symbol.type == Symbol::MESSAGE) {
@@ -3939,8 +5337,8 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
// DescriptorPool::FindExtensionByName(), for two reasons: 1) It allows
// relative lookups, and 2) because we're already holding the pool's
// mutex, and the latter method locks it again.
- Symbol symbol = builder_->LookupSymbol(name_part,
- options_to_interpret_->name_scope);
+ symbol = builder_->LookupSymbol(name_part,
+ options_to_interpret_->name_scope);
if (!symbol.IsNull() && symbol.type == Symbol::FIELD) {
field = symbol.field_descriptor;
}
@@ -3960,6 +5358,15 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
// so we will just leave it as uninterpreted.
AddWithoutInterpreting(*uninterpreted_option_, options);
return true;
+ } else if (!(builder_->undefine_resolved_name_).empty()) {
+ // Option is resolved to a name which is not defined.
+ return AddNameError(
+ "Option \"" + debug_msg_name + "\" is resolved to \"(" +
+ builder_->undefine_resolved_name_ +
+ ")\", which is not defined. The innermost scope is searched first "
+ "in name resolution. Consider using a leading '.'(i.e., \"(." +
+ debug_msg_name.substr(1) +
+ "\") to start from the outermost scope.");
} else {
return AddNameError("Option \"" + debug_msg_name + "\" unknown.");
}
@@ -3980,14 +5387,15 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
"\" is not a field or extension of message \"" +
descriptor->name() + "\".");
}
- } else if (field->is_repeated()) {
- return AddNameError("Option field \"" + debug_msg_name +
- "\" is repeated. Repeated options are not "
- "supported.");
} else if (i < uninterpreted_option_->name_size() - 1) {
if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
return AddNameError("Option \"" + debug_msg_name +
"\" is an atomic type, not a message.");
+ } else if (field->is_repeated()) {
+ return AddNameError("Option field \"" + debug_msg_name +
+ "\" is a repeated message. Repeated message "
+ "options must be initialized using an "
+ "aggregate value.");
} else {
// Drill down into the submessage.
intermediate_fields.push_back(field);
@@ -4004,7 +5412,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
// known will populate them correctly.
// First see if the option is already set.
- if (!ExamineIfOptionIsSet(
+ if (!field->is_repeated() && !ExamineIfOptionIsSet(
intermediate_fields.begin(),
intermediate_fields.end(),
field, debug_msg_name,
@@ -4344,14 +5752,32 @@ class DescriptorBuilder::OptionInterpreter::AggregateOptionFinder
virtual const FieldDescriptor* FindExtension(
Message* message, const string& name) const {
assert_mutex_held(builder_->pool_);
+ const Descriptor* descriptor = message->GetDescriptor();
Symbol result = builder_->LookupSymbolNoPlaceholder(
- name, message->GetDescriptor()->full_name());
+ name, descriptor->full_name());
if (result.type == Symbol::FIELD &&
result.field_descriptor->is_extension()) {
return result.field_descriptor;
- } else {
- return NULL;
+ } else if (result.type == Symbol::MESSAGE &&
+ descriptor->options().message_set_wire_format()) {
+ const Descriptor* foreign_type = result.descriptor;
+ // The text format allows MessageSet items to be specified using
+ // the type name, rather than the extension identifier. If the symbol
+ // lookup returned a Message, and the enclosing Message has
+ // message_set_wire_format = true, then return the message set
+ // extension, if one exists.
+ for (int i = 0; i < foreign_type->extension_count(); i++) {
+ const FieldDescriptor* extension = foreign_type->extension(i);
+ if (extension->containing_type() == descriptor &&
+ extension->type() == FieldDescriptor::TYPE_MESSAGE &&
+ extension->is_optional() &&
+ extension->message_type() == foreign_type) {
+ // Found it.
+ return extension;
+ }
+ }
}
+ return NULL;
}
};
@@ -4361,14 +5787,16 @@ class AggregateErrorCollector : public io::ErrorCollector {
public:
string error_;
- virtual void AddError(int line, int column, const string& message) {
+ virtual void AddError(int /* line */, int /* column */,
+ const string& message) {
if (!error_.empty()) {
error_ += "; ";
}
error_ += message;
}
- virtual void AddWarning(int line, int column, const string& message) {
+ virtual void AddWarning(int /* line */, int /* column */,
+ const string& /* message */) {
// Ignore warnings
}
};
@@ -4409,7 +5837,13 @@ bool DescriptorBuilder::OptionInterpreter::SetAggregateOption(
} else {
string serial;
dynamic->SerializeToString(&serial); // Never fails
- unknown_fields->AddLengthDelimited(option_field->number(), serial);
+ if (option_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ unknown_fields->AddLengthDelimited(option_field->number(), serial);
+ } else {
+ GOOGLE_CHECK_EQ(option_field->type(), FieldDescriptor::TYPE_GROUP);
+ UnknownFieldSet* group = unknown_fields->AddGroup(option_field->number());
+ group->ParseFromString(serial);
+ }
return true;
}
}
@@ -4493,5 +5927,39 @@ void DescriptorBuilder::OptionInterpreter::SetUInt64(int number, uint64 value,
}
}
+void DescriptorBuilder::LogUnusedDependency(const FileDescriptor* result) {
+
+ if (!unused_dependency_.empty()) {
+ std::set<string> annotation_extensions;
+ annotation_extensions.insert("google.protobuf.MessageOptions");
+ annotation_extensions.insert("google.protobuf.FileOptions");
+ annotation_extensions.insert("google.protobuf.FieldOptions");
+ annotation_extensions.insert("google.protobuf.EnumOptions");
+ annotation_extensions.insert("google.protobuf.EnumValueOptions");
+ annotation_extensions.insert("google.protobuf.ServiceOptions");
+ annotation_extensions.insert("google.protobuf.MethodOptions");
+ annotation_extensions.insert("google.protobuf.StreamOptions");
+ for (set<const FileDescriptor*>::const_iterator
+ it = unused_dependency_.begin();
+ it != unused_dependency_.end(); ++it) {
+ // Do not log warnings for proto files which extend annotations.
+ int i;
+ for (i = 0 ; i < (*it)->extension_count(); ++i) {
+ if (annotation_extensions.find(
+ (*it)->extension(i)->containing_type()->full_name())
+ != annotation_extensions.end()) {
+ break;
+ }
+ }
+ // Log warnings for unused imported files.
+ if (i == (*it)->extension_count()) {
+ GOOGLE_LOG(WARNING) << "Warning: Unused import: \"" << result->name()
+ << "\" imports \"" << (*it)->name()
+ << "\" which is not used.";
+ }
+ }
+ }
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index 7f87dd80..0e264f54 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -54,6 +54,7 @@
#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
#define GOOGLE_PROTOBUF_DESCRIPTOR_H__
+#include <set>
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
@@ -65,6 +66,7 @@ namespace protobuf {
// Defined in this file.
class Descriptor;
class FieldDescriptor;
+class OneofDescriptor;
class EnumDescriptor;
class EnumValueDescriptor;
class ServiceDescriptor;
@@ -76,6 +78,7 @@ class DescriptorPool;
// Defined in descriptor.proto
class DescriptorProto;
class FieldDescriptorProto;
+class OneofDescriptorProto;
class EnumDescriptorProto;
class EnumValueDescriptorProto;
class ServiceDescriptorProto;
@@ -89,6 +92,7 @@ class ServiceOptions;
class MethodOptions;
class FileOptions;
class UninterpretedOption;
+class SourceCodeInfo;
// Defined in message.h
class Message;
@@ -100,6 +104,39 @@ 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;
+ int end_line;
+ int start_column;
+ int end_column;
+
+ // Doc comments found at the source location.
+ // See the comments in SourceCodeInfo.Location (descriptor.proto) for details.
+ string leading_comments;
+ string trailing_comments;
+ vector<string> leading_detached_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
@@ -144,6 +181,15 @@ 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.
+ bool is_placeholder() const;
+
// Field stuff -----------------------------------------------------
// The number of fields in this message type.
@@ -171,6 +217,15 @@ class LIBPROTOBUF_EXPORT Descriptor {
const FieldDescriptor* FindFieldByCamelcaseName(
const string& camelcase_name) const;
+ // The number of oneofs in this message type.
+ int oneof_decl_count() const;
+ // Get a oneof by index, where 0 <= index < oneof_decl_count().
+ // These are returned in the order they were defined in the .proto file.
+ const OneofDescriptor* oneof_decl(int index) const;
+
+ // Looks up a oneof by name. Returns NULL if no such oneof exists.
+ const OneofDescriptor* FindOneofByName(const string& name) const;
+
// Nested type stuff -----------------------------------------------
// The number of nested types in this message type.
@@ -217,6 +272,9 @@ class LIBPROTOBUF_EXPORT Descriptor {
// Returns true if the number is in one of the extension ranges.
bool IsExtensionNumber(int number) const;
+ // Returns NULL if no extension range contains the given number.
+ const ExtensionRange* FindExtensionRangeContainingNumber(int number) const;
+
// The number of extensions -- extending *other* messages -- that were
// defined nested within this message type's scope.
int extension_count() const;
@@ -236,12 +294,27 @@ class LIBPROTOBUF_EXPORT Descriptor {
// this message type's scope.
const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of this message declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
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.
+ void GetLocationPath(std::vector<int>* output) const;
const string* name_;
const string* full_name_;
@@ -256,6 +329,8 @@ class LIBPROTOBUF_EXPORT Descriptor {
int field_count_;
FieldDescriptor* fields_;
+ int oneof_decl_count_;
+ OneofDescriptor* oneof_decls_;
int nested_type_count_;
Descriptor* nested_types_;
int enum_type_count_;
@@ -273,6 +348,7 @@ class LIBPROTOBUF_EXPORT Descriptor {
friend class DescriptorBuilder;
friend class EnumDescriptor;
friend class FieldDescriptor;
+ friend class OneofDescriptor;
friend class MethodDescriptor;
friend class FileDescriptor;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Descriptor);
@@ -388,15 +464,21 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
// when parsing formats which prefer to use camel-case naming style.
const string& camelcase_name() const;
- Type type() const; // Declared type of this field.
- CppType cpp_type() const; // C++ type of this field.
- Label label() const; // optional/required/repeated
+ Type type() const; // Declared type of this field.
+ const char* type_name() const; // Name of the declared type.
+ CppType cpp_type() const; // C++ type of this field.
+ const char* cpp_type_name() const; // Name of the C++ type.
+ Label label() const; // optional/required/repeated
bool is_required() const; // shorthand for label() == LABEL_REQUIRED
bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL
bool is_repeated() const; // shorthand for label() == LABEL_REPEATED
bool is_packable() const; // shorthand for is_repeated() &&
// IsTypePackable(type())
+ bool is_packed() const; // shorthand for is_packable() &&
+ // options().packed()
+ bool is_map() const; // shorthand for type() == TYPE_MESSAGE &&
+ // message_type()->options().map_entry()
// Index of this field within the message's field array, or the file or
// extension scope's extensions array.
@@ -439,6 +521,13 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
// this is the extended type. Never NULL.
const Descriptor* containing_type() const;
+ // If the field is a member of a oneof, this is the one, otherwise this is
+ // NULL.
+ const OneofDescriptor* containing_oneof() const;
+
+ // If the field is a member of a oneof, returns the index in that oneof.
+ int index_in_oneof() const;
+
// An extension may be declared within the scope of another message. If this
// field is an extension (is_extension() is true), then extension_scope()
// returns that message, or NULL if the extension was declared at global
@@ -447,18 +536,12 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
const Descriptor* extension_scope() const;
// If type is TYPE_MESSAGE or TYPE_GROUP, returns a descriptor for the
- // message or the group type. Otherwise, undefined.
+ // message or the group type. Otherwise, returns null.
const Descriptor* message_type() const;
// If type is TYPE_ENUM, returns a descriptor for the enum. Otherwise,
- // undefined.
+ // 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];
@@ -473,23 +556,48 @@ 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);
+ // Helper method to get the name of a Type.
+ static const char* TypeName(Type type);
+
+ // Helper method to get the name of a CppType.
+ static const char* CppTypeName(CppType cpp_type);
+
// Return true iff [packed = true] is valid for fields of this type.
static inline bool IsTypePackable(Type field_type);
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of this field declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
typedef FieldOptions OptionsType;
// See Descriptor::DebugString().
- void DebugString(int depth, string *contents) const;
+ enum PrintLabelFlag { PRINT_LABEL, OMIT_LABEL };
+ void DebugString(int depth, PrintLabelFlag print_label_flag,
+ 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(std::vector<int>* output) const;
+
const string* name_;
const string* full_name_;
const string* lowercase_name_;
@@ -499,11 +607,12 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
Type type_;
Label label_;
bool is_extension_;
+ int index_in_oneof_;
const Descriptor* containing_type_;
+ const OneofDescriptor* containing_oneof_;
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<FieldDescriptor>() and AllocateArray<FieldDescriptor>() in
@@ -527,6 +636,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
static const char * const kTypeToName[MAX_TYPE + 1];
+ static const char * const kCppTypeToName[MAX_CPPTYPE + 1];
+
static const char * const kLabelToName[MAX_LABEL + 1];
// Must be constructed using DescriptorPool.
@@ -534,9 +645,70 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
friend class DescriptorBuilder;
friend class FileDescriptor;
friend class Descriptor;
+ friend class OneofDescriptor;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldDescriptor);
};
+// Describes a oneof defined in a message type.
+class LIBPROTOBUF_EXPORT OneofDescriptor {
+ public:
+ const string& name() const; // Name of this oneof.
+ const string& full_name() const; // Fully-qualified name of the oneof.
+
+ // Index of this oneof within the message's oneof array.
+ int index() const;
+
+ // The Descriptor for the message containing this oneof.
+ const Descriptor* containing_type() const;
+
+ // The number of (non-extension) fields which are members of this oneof.
+ int field_count() const;
+ // Get a member of this oneof, in the order in which they were declared in the
+ // .proto file. Does not include extensions.
+ const FieldDescriptor* field(int index) const;
+
+ // See Descriptor::CopyTo().
+ void CopyTo(OneofDescriptorProto* proto) const;
+
+ // 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
+ // extent of this oneof declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+ // See Descriptor::DebugString().
+ 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.
+ void GetLocationPath(std::vector<int>* output) const;
+
+ const string* name_;
+ const string* full_name_;
+ const Descriptor* containing_type_;
+ bool is_extendable_;
+ int field_count_;
+ const FieldDescriptor** fields_;
+ // IMPORTANT: If you add a new field, make sure to search for all instances
+ // of Allocate<OneofDescriptor>() and AllocateArray<OneofDescriptor>()
+ // in descriptor.cc and update them to initialize the field.
+
+ // Must be constructed using DescriptorPool.
+ OneofDescriptor() {}
+ friend class DescriptorBuilder;
+ friend class Descriptor;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OneofDescriptor);
+};
+
// Describes an enum type defined in a .proto file. To get the EnumDescriptor
// for a generated enum type, call TypeName_descriptor(). Use DescriptorPool
// to construct your own descriptors.
@@ -583,11 +755,44 @@ 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.
+ bool is_placeholder() const;
+
+ // Source Location ---------------------------------------------------
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of this enum declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
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.
+ void GetLocationPath(std::vector<int>* output) const;
const string* name_;
const string* full_name_;
@@ -613,6 +818,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);
};
@@ -650,11 +856,27 @@ 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
+ // extent of this enum value declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
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.
+ void GetLocationPath(std::vector<int>* output) const;
const string* name_;
const string* full_name_;
@@ -669,6 +891,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor {
EnumValueDescriptor() {}
friend class DescriptorBuilder;
friend class EnumDescriptor;
+ friend class FileDescriptorTables;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumValueDescriptor);
};
@@ -703,18 +926,32 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor {
// Look up a MethodDescriptor by name.
const MethodDescriptor* FindMethodByName(const string& name) const;
-
// See Descriptor::CopyTo().
void CopyTo(ServiceDescriptorProto* proto) const;
// 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
+ // extent of this service declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
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.
+ void GetLocationPath(std::vector<int>* output) const;
const string* name_;
const string* full_name_;
@@ -755,6 +992,11 @@ class LIBPROTOBUF_EXPORT MethodDescriptor {
// Gets the type of protocol message which this message produces as output.
const Descriptor* output_type() const;
+ // Gets whether the client streams multiple requests.
+ bool client_streaming() const;
+ // Gets whether the server streams multiple responses.
+ bool server_streaming() const;
+
// Get options for this method. These are specified in the .proto file by
// placing lines like "option foo = 1234;" in curly-braces after a method
// declaration. Allowed options are defined by MethodOptions in
@@ -768,11 +1010,27 @@ 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
+ // extent of this method declaration. Returns false and leaves
+ // |*out_location| unchanged iff location information was not available.
+ bool GetSourceLocation(SourceLocation* out_location) const;
+
private:
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.
+ void GetLocationPath(std::vector<int>* output) const;
const string* name_;
const string* full_name_;
@@ -780,6 +1038,8 @@ class LIBPROTOBUF_EXPORT MethodDescriptor {
const Descriptor* input_type_;
const Descriptor* output_type_;
const MethodOptions* options_;
+ bool client_streaming_;
+ bool server_streaming_;
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<MethodDescriptor>() and AllocateArray<MethodDescriptor>() in
// descriptor.cc and update them to initialize the field.
@@ -791,6 +1051,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptor {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MethodDescriptor);
};
+
// Describes a whole .proto file. To get the FileDescriptor for a compiled-in
// file, get the descriptor for something defined in that file and call
// descriptor->file(). Use DescriptorPool to construct your own descriptors.
@@ -813,6 +1074,22 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
// These are returned in the order they were defined in the .proto file.
const FileDescriptor* dependency(int index) const;
+ // The number of files public imported by this one.
+ // The public dependency list is a subset of the dependency list.
+ int public_dependency_count() const;
+ // Gets a public imported file by index, where 0 <= index <
+ // public_dependency_count().
+ // These are returned in the order they were defined in the .proto file.
+ const FileDescriptor* public_dependency(int index) const;
+
+ // The number of files that are imported for weak fields.
+ // The weak dependency list is a subset of the dependency list.
+ int weak_dependency_count() const;
+ // Gets a weak imported file by index, where 0 <= index <
+ // weak_dependency_count().
+ // These are returned in the order they were defined in the .proto file.
+ const FileDescriptor* weak_dependency(int index) const;
+
// Number of top-level message types defined in this file. (This does not
// include nested types.)
int message_type_count() const;
@@ -847,6 +1124,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.
@@ -866,11 +1152,37 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
// See Descriptor::CopyTo().
+ // Notes:
+ // - This method does NOT copy source code information since it is relatively
+ // large and rarely needed. See CopySourceCodeInfoTo() below.
void CopyTo(FileDescriptorProto* proto) const;
+ // Write the source code information of this FileDescriptor into the given
+ // FileDescriptorProto. See CopyTo() above.
+ void CopySourceCodeInfoTo(FileDescriptorProto* proto) const;
// 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;
+
+ // Updates |*out_location| to the source location of the complete
+ // extent of the declaration or declaration-part denoted by |path|.
+ // Returns false and leaves |*out_location| unchanged iff location
+ // information was not available. (See SourceCodeInfo for
+ // description of path encoding.)
+ bool GetSourceLocation(const std::vector<int>& path,
+ SourceLocation* out_location) const;
+
private:
typedef FileOptions OptionsType;
@@ -879,6 +1191,10 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
const DescriptorPool* pool_;
int dependency_count_;
const FileDescriptor** dependencies_;
+ int public_dependency_count_;
+ int* public_dependencies_;
+ int weak_dependency_count_;
+ int* weak_dependencies_;
int message_type_count_;
Descriptor* message_types_;
int enum_type_count_;
@@ -886,10 +1202,13 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
int service_count_;
ServiceDescriptor* services_;
int extension_count_;
+ Syntax syntax_;
+ bool is_placeholder_;
FieldDescriptor* extensions_;
const FileOptions* options_;
const FileDescriptorTables* tables_;
+ const SourceCodeInfo* source_code_info_;
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<FileDescriptor>() and AllocateArray<FileDescriptor>() in
// descriptor.cc and update them to initialize the field.
@@ -898,7 +1217,10 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
friend class DescriptorBuilder;
friend class Descriptor;
friend class FieldDescriptor;
+ friend class OneofDescriptor;
friend class EnumDescriptor;
+ friend class EnumValueDescriptor;
+ friend class MethodDescriptor;
friend class ServiceDescriptor;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileDescriptor);
};
@@ -953,6 +1275,10 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
// to GOOGLE_LOG(ERROR). Remember that files are built on-demand, so this
// ErrorCollector may be called from any thread that calls one of the
// Find*By*() methods.
+ // - The DescriptorDatabase must not be mutated during the lifetime of
+ // the DescriptorPool. Even if the client takes care to avoid data races,
+ // changes to the content of the DescriptorDatabase may not be reflected
+ // in subsequent lookups in the DescriptorPool.
class ErrorCollector;
explicit DescriptorPool(DescriptorDatabase* fallback_database,
ErrorCollector* error_collector = NULL);
@@ -983,6 +1309,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
const Descriptor* FindMessageTypeByName(const string& name) const;
const FieldDescriptor* FindFieldByName(const string& name) const;
const FieldDescriptor* FindExtensionByName(const string& name) const;
+ const OneofDescriptor* FindOneofByName(const string& name) const;
const EnumDescriptor* FindEnumTypeByName(const string& name) const;
const EnumValueDescriptor* FindEnumValueByName(const string& name) const;
const ServiceDescriptor* FindServiceByName(const string& name) const;
@@ -999,7 +1326,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
// found: extensions defined in the fallback database might not be found
// depending on the database implementation.
void FindAllExtensions(const Descriptor* extendee,
- vector<const FieldDescriptor*>* out) const;
+ std::vector<const FieldDescriptor*>* out) const;
// Building descriptors --------------------------------------------
@@ -1027,7 +1354,8 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
OTHER // some other problem
};
- // Reports an error in the FileDescriptorProto.
+ // Reports an error in the FileDescriptorProto. Use this function if the
+ // problem occurred should interrupt building the FileDescriptorProto.
virtual void AddError(
const string& filename, // File name in which the error occurred.
const string& element_name, // Full name of the erroneous element.
@@ -1036,6 +1364,16 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
const string& message // Human-readable error message.
) = 0;
+ // Reports a warning in the FileDescriptorProto. Use this function if the
+ // problem occurred should NOT interrupt building the FileDescriptorProto.
+ virtual void AddWarning(
+ const string& /*filename*/, // File name in which the error occurred.
+ const string& /*element_name*/, // Full name of the erroneous element.
+ const Message* /*descriptor*/, // Descriptor of the erroneous element.
+ ErrorLocation /*location*/, // One of the location constants, above.
+ const string& /*message*/ // Human-readable error message.
+ ) {}
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
};
@@ -1056,7 +1394,8 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
// to types or other files that are not found in the DescriptorPool (or its
// backing DescriptorDatabase, if any). If you call
// AllowUnknownDependencies(), however, then unknown types and files
- // will be replaced by placeholder descriptors. This can allow you to
+ // will be replaced by placeholder descriptors (which can be identified by
+ // the is_placeholder() method). This can allow you to
// perform some useful operations with a .proto file even if you do not
// have access to other .proto files on which it depends. However, some
// heuristics must be used to fill in the gaps in information, and these
@@ -1065,10 +1404,15 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
// or an enum, as well as what package it resides in. Furthermore,
// placeholder types will not be discoverable via FindMessageTypeByName()
// and similar methods, which could confuse some descriptor-based algorithms.
- // Generally, the results of this option should only be relied upon for
- // debugging purposes.
+ // Generally, the results of this option should be handled with extreme care.
void AllowUnknownDependencies() { allow_unknown_ = true; }
+ // By default, weak imports are allowed to be missing, in which case we will
+ // use a placeholder for the dependency and convert the field to be an Empty
+ // message field. If you call EnforceWeakDependencies(true), however, the
+ // DescriptorPool will report a import not found error.
+ void EnforceWeakDependencies(bool enforce) { enforce_weak_ = enforce; }
+
// Internal stuff --------------------------------------------------
// These methods MUST NOT be called from outside the proto2 library.
// These methods may contain hidden pitfalls and may be removed in a
@@ -1106,7 +1450,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
// For internal use only: Gets a non-const pointer to the generated pool.
// This is called at static-initialization time only, so thread-safety is
// not a concern. If both an underlay and a fallback database are present,
- // the fallback database takes precedence.
+ // the underlay takes precedence.
static DescriptorPool* internal_generated_pool();
// For internal use only: Changes the behavior of BuildFile() such that it
@@ -1124,6 +1468,12 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
// lazy descriptor initialization behavior.
bool InternalIsFileLoaded(const string& filename) const;
+
+ // Add a file to unused_import_track_files_. DescriptorBuilder will log
+ // warnings for those files if there is any unused import.
+ void AddUnusedImportTrackFile(const string& file_name);
+ void ClearUnusedImportTrackFiles();
+
private:
friend class Descriptor;
friend class FieldDescriptor;
@@ -1131,6 +1481,12 @@ 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
+ // definition of such types is already known.)
+ bool IsSubSymbolOfBuiltType(const string& name) const;
// Tries to find something in the fallback database and link in the
// corresponding proto file. Returns true if successful, in which case
@@ -1163,6 +1519,8 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
bool enforce_dependencies_;
bool allow_unknown_;
+ bool enforce_weak_;
+ std::set<string> unused_import_track_files_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPool);
};
@@ -1190,10 +1548,12 @@ PROTOBUF_DEFINE_ACCESSOR(Descriptor, file, const FileDescriptor*)
PROTOBUF_DEFINE_ACCESSOR(Descriptor, containing_type, const Descriptor*)
PROTOBUF_DEFINE_ACCESSOR(Descriptor, field_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, oneof_decl_count, int)
PROTOBUF_DEFINE_ACCESSOR(Descriptor, nested_type_count, int)
PROTOBUF_DEFINE_ACCESSOR(Descriptor, enum_type_count, int)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, field, const FieldDescriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, oneof_decl, const OneofDescriptor*)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, nested_type, const Descriptor*)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, enum_type, const EnumDescriptor*)
@@ -1204,6 +1564,7 @@ PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension_range,
PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension,
const FieldDescriptor*)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions);
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool)
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name)
@@ -1215,12 +1576,13 @@ PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, type, FieldDescriptor::Type)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, label, FieldDescriptor::Label)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_type, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_oneof,
+ const OneofDescriptor*)
+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_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32 , int32 )
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64 , int64 )
@@ -1233,6 +1595,11 @@ PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_enum,
const EnumValueDescriptor*)
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, default_value_string)
+PROTOBUF_DEFINE_STRING_ACCESSOR(OneofDescriptor, name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(OneofDescriptor, full_name)
+PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, containing_type, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, field_count, int)
+
PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, full_name)
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, file, const FileDescriptor*)
@@ -1241,12 +1608,13 @@ PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value,
const EnumValueDescriptor*)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions);
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, is_placeholder, bool)
PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, full_name)
PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int)
PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, full_name)
@@ -1262,16 +1630,21 @@ PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*)
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions);
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, server_streaming, bool)
PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, public_dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, weak_dependency_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int)
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int)
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions);
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, is_placeholder, bool)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*)
PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, enum_type, const EnumDescriptor*)
@@ -1286,6 +1659,10 @@ PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, extension,
// A few accessors differ from the macros...
+inline bool Descriptor::IsExtensionNumber(int number) const {
+ return FindExtensionRangeContainingNumber(number) != NULL;
+}
+
inline bool FieldDescriptor::is_required() const {
return label() == LABEL_REQUIRED;
}
@@ -1306,50 +1683,70 @@ inline bool FieldDescriptor::is_packable() const {
// in the parent's array of children.
inline int FieldDescriptor::index() const {
if (!is_extension_) {
- return this - containing_type_->fields_;
+ return static_cast<int>(this - containing_type_->fields_);
} else if (extension_scope_ != NULL) {
- return this - extension_scope_->extensions_;
+ return static_cast<int>(this - extension_scope_->extensions_);
} else {
- return this - file_->extensions_;
+ return static_cast<int>(this - file_->extensions_);
}
}
inline int Descriptor::index() const {
if (containing_type_ == NULL) {
- return this - file_->message_types_;
+ return static_cast<int>(this - file_->message_types_);
} else {
- return this - containing_type_->nested_types_;
+ return static_cast<int>(this - containing_type_->nested_types_);
}
}
+inline int OneofDescriptor::index() const {
+ return static_cast<int>(this - containing_type_->oneof_decls_);
+}
+
inline int EnumDescriptor::index() const {
if (containing_type_ == NULL) {
- return this - file_->enum_types_;
+ return static_cast<int>(this - file_->enum_types_);
} else {
- return this - containing_type_->enum_types_;
+ return static_cast<int>(this - containing_type_->enum_types_);
}
}
inline int EnumValueDescriptor::index() const {
- return this - type_->values_;
+ return static_cast<int>(this - type_->values_);
}
inline int ServiceDescriptor::index() const {
- return this - file_->services_;
+ return static_cast<int>(this - file_->services_);
}
inline int MethodDescriptor::index() const {
- return this - service_->methods_;
+ return static_cast<int>(this - service_->methods_);
+}
+
+inline const char* FieldDescriptor::type_name() const {
+ return kTypeToName[type_];
}
inline FieldDescriptor::CppType FieldDescriptor::cpp_type() const {
return kTypeToCppTypeMap[type_];
}
+inline const char* FieldDescriptor::cpp_type_name() const {
+ return kCppTypeToName[kTypeToCppTypeMap[type_]];
+}
+
inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) {
return kTypeToCppTypeMap[type];
}
+inline const char* FieldDescriptor::TypeName(Type type) {
+ return kTypeToName[type];
+}
+
+inline const char* FieldDescriptor::CppTypeName(CppType cpp_type) {
+ return kCppTypeToName[cpp_type];
+}
+
inline bool FieldDescriptor::IsTypePackable(Type field_type) {
return (field_type != FieldDescriptor::TYPE_STRING &&
field_type != FieldDescriptor::TYPE_GROUP &&
@@ -1361,6 +1758,26 @@ inline const FileDescriptor* FileDescriptor::dependency(int index) const {
return dependencies_[index];
}
+inline const FileDescriptor* FileDescriptor::public_dependency(
+ int index) const {
+ return dependencies_[public_dependencies_[index]];
+}
+
+inline const FileDescriptor* FileDescriptor::weak_dependency(
+ int index) const {
+ 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 {
+ return fields_[index];
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 87303ef8..9556206c 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -1,14 +1,17 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "google/protobuf/descriptor.pb.h"
#include <algorithm>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)
@@ -35,6 +38,9 @@ const ::google::protobuf::internal::GeneratedMessageReflection*
FieldDescriptorProto_reflection_ = NULL;
const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor_ = NULL;
const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* OneofDescriptorProto_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ OneofDescriptorProto_reflection_ = NULL;
const ::google::protobuf::Descriptor* EnumDescriptorProto_descriptor_ = NULL;
const ::google::protobuf::internal::GeneratedMessageReflection*
EnumDescriptorProto_reflection_ = NULL;
@@ -97,78 +103,82 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, file_),
};
FileDescriptorSet_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
FileDescriptorSet_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(FileDescriptorSet));
+ -1,
+ sizeof(FileDescriptorSet),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _internal_metadata_),
+ -1);
FileDescriptorProto_descriptor_ = file->message_type(1);
- static const int FileDescriptorProto_offsets_[9] = {
+ 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_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, public_dependency_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, weak_dependency_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, message_type_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, enum_type_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, service_),
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(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
FileDescriptorProto_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(FileDescriptorProto));
+ -1,
+ sizeof(FileDescriptorProto),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _internal_metadata_),
+ -1);
DescriptorProto_descriptor_ = file->message_type(2);
- static const int DescriptorProto_offsets_[7] = {
+ static const int DescriptorProto_offsets_[8] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, field_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, nested_type_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, enum_type_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_range_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, oneof_decl_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, options_),
};
DescriptorProto_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
DescriptorProto_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(DescriptorProto));
+ -1,
+ sizeof(DescriptorProto),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _internal_metadata_),
+ -1);
DescriptorProto_ExtensionRange_descriptor_ = DescriptorProto_descriptor_->nested_type(0);
static const int DescriptorProto_ExtensionRange_offsets_[2] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, start_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, end_),
};
DescriptorProto_ExtensionRange_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
DescriptorProto_ExtensionRange_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(DescriptorProto_ExtensionRange));
+ -1,
+ sizeof(DescriptorProto_ExtensionRange),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _internal_metadata_),
+ -1);
FieldDescriptorProto_descriptor_ = file->message_type(3);
- static const int FieldDescriptorProto_offsets_[8] = {
+ static const int FieldDescriptorProto_offsets_[9] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, number_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, label_),
@@ -176,212 +186,243 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, type_name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, extendee_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, default_value_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, oneof_index_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, options_),
};
FieldDescriptorProto_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
FieldDescriptorProto_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(FieldDescriptorProto));
+ -1,
+ sizeof(FieldDescriptorProto),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _internal_metadata_),
+ -1);
FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0);
FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1);
- EnumDescriptorProto_descriptor_ = file->message_type(4);
+ OneofDescriptorProto_descriptor_ = file->message_type(4);
+ static const int OneofDescriptorProto_offsets_[1] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, name_),
+ };
+ OneofDescriptorProto_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ OneofDescriptorProto_descriptor_,
+ OneofDescriptorProto::default_instance_,
+ OneofDescriptorProto_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _has_bits_[0]),
+ -1,
+ -1,
+ sizeof(OneofDescriptorProto),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _internal_metadata_),
+ -1);
+ EnumDescriptorProto_descriptor_ = file->message_type(5);
static const int EnumDescriptorProto_offsets_[3] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, value_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, options_),
};
EnumDescriptorProto_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
EnumDescriptorProto_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(EnumDescriptorProto));
- EnumValueDescriptorProto_descriptor_ = file->message_type(5);
+ -1,
+ sizeof(EnumDescriptorProto),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _internal_metadata_),
+ -1);
+ EnumValueDescriptorProto_descriptor_ = file->message_type(6);
static const int EnumValueDescriptorProto_offsets_[3] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, number_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, options_),
};
EnumValueDescriptorProto_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
EnumValueDescriptorProto_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(EnumValueDescriptorProto));
- ServiceDescriptorProto_descriptor_ = file->message_type(6);
+ -1,
+ sizeof(EnumValueDescriptorProto),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _internal_metadata_),
+ -1);
+ ServiceDescriptorProto_descriptor_ = file->message_type(7);
static const int ServiceDescriptorProto_offsets_[3] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, method_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, options_),
};
ServiceDescriptorProto_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
ServiceDescriptorProto_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(ServiceDescriptorProto));
- MethodDescriptorProto_descriptor_ = file->message_type(7);
- static const int MethodDescriptorProto_offsets_[4] = {
+ -1,
+ sizeof(ServiceDescriptorProto),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _internal_metadata_),
+ -1);
+ MethodDescriptorProto_descriptor_ = file->message_type(8);
+ static const int MethodDescriptorProto_offsets_[6] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, input_type_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, output_type_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, options_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, client_streaming_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, server_streaming_),
};
MethodDescriptorProto_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
MethodDescriptorProto_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(MethodDescriptorProto));
- FileOptions_descriptor_ = file->message_type(8);
- static const int FileOptions_offsets_[9] = {
+ -1,
+ sizeof(MethodDescriptorProto),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_),
+ -1);
+ FileOptions_descriptor_ = file->message_type(9);
+ static const int FileOptions_offsets_[14] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generate_equals_and_hash_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_string_check_utf8_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, optimize_for_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, go_package_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_generic_services_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generic_services_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, py_generic_services_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, deprecated_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_enable_arenas_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, objc_class_prefix_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_),
};
FileOptions_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
FileOptions_descriptor_,
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_),
+ -1);
FileOptions_OptimizeMode_descriptor_ = FileOptions_descriptor_->enum_type(0);
- MessageOptions_descriptor_ = file->message_type(9);
- static const int MessageOptions_offsets_[3] = {
+ MessageOptions_descriptor_ = file->message_type(10);
+ 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_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
MessageOptions_descriptor_,
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));
- FieldOptions_descriptor_ = file->message_type(10);
- static const int FieldOptions_offsets_[5] = {
+ sizeof(MessageOptions),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_),
+ -1);
+ FieldOptions_descriptor_ = file->message_type(11);
+ static const int FieldOptions_offsets_[6] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_),
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_),
};
FieldOptions_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
FieldOptions_descriptor_,
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_),
+ -1);
FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0);
- EnumOptions_descriptor_ = file->message_type(11);
- static const int EnumOptions_offsets_[1] = {
+ EnumOptions_descriptor_ = file->message_type(12);
+ static const int EnumOptions_offsets_[3] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, allow_alias_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, deprecated_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, uninterpreted_option_),
};
EnumOptions_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
EnumOptions_descriptor_,
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));
- EnumValueOptions_descriptor_ = file->message_type(12);
- static const int EnumValueOptions_offsets_[1] = {
+ sizeof(EnumOptions),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _internal_metadata_),
+ -1);
+ EnumValueOptions_descriptor_ = file->message_type(13);
+ static const int EnumValueOptions_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, deprecated_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, uninterpreted_option_),
};
EnumValueOptions_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
EnumValueOptions_descriptor_,
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));
- ServiceOptions_descriptor_ = file->message_type(13);
- static const int ServiceOptions_offsets_[1] = {
+ sizeof(EnumValueOptions),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _internal_metadata_),
+ -1);
+ ServiceOptions_descriptor_ = file->message_type(14);
+ static const int ServiceOptions_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, deprecated_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, uninterpreted_option_),
};
ServiceOptions_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
ServiceOptions_descriptor_,
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));
- MethodOptions_descriptor_ = file->message_type(14);
- static const int MethodOptions_offsets_[1] = {
+ sizeof(ServiceOptions),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _internal_metadata_),
+ -1);
+ MethodOptions_descriptor_ = file->message_type(15);
+ static const int MethodOptions_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, deprecated_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, uninterpreted_option_),
};
MethodOptions_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
MethodOptions_descriptor_,
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));
- UninterpretedOption_descriptor_ = file->message_type(15);
+ sizeof(MethodOptions),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _internal_metadata_),
+ -1);
+ UninterpretedOption_descriptor_ = file->message_type(16);
static const int UninterpretedOption_offsets_[7] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, identifier_value_),
@@ -392,63 +433,66 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, aggregate_value_),
};
UninterpretedOption_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
UninterpretedOption_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(UninterpretedOption));
+ -1,
+ sizeof(UninterpretedOption),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _internal_metadata_),
+ -1);
UninterpretedOption_NamePart_descriptor_ = UninterpretedOption_descriptor_->nested_type(0);
static const int UninterpretedOption_NamePart_offsets_[2] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, name_part_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, is_extension_),
};
UninterpretedOption_NamePart_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
UninterpretedOption_NamePart_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(UninterpretedOption_NamePart));
- SourceCodeInfo_descriptor_ = file->message_type(16);
+ -1,
+ sizeof(UninterpretedOption_NamePart),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _internal_metadata_),
+ -1);
+ SourceCodeInfo_descriptor_ = file->message_type(17);
static const int SourceCodeInfo_offsets_[1] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, location_),
};
SourceCodeInfo_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
SourceCodeInfo_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(SourceCodeInfo));
+ -1,
+ sizeof(SourceCodeInfo),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _internal_metadata_),
+ -1);
SourceCodeInfo_Location_descriptor_ = SourceCodeInfo_descriptor_->nested_type(0);
- static const int SourceCodeInfo_Location_offsets_[2] = {
+ static const int SourceCodeInfo_Location_offsets_[5] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, path_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, span_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, leading_comments_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, trailing_comments_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, leading_detached_comments_),
};
SourceCodeInfo_Location_reflection_ =
- new ::google::protobuf::internal::GeneratedMessageReflection(
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
SourceCodeInfo_Location_descriptor_,
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,
- ::google::protobuf::DescriptorPool::generated_pool(),
- ::google::protobuf::MessageFactory::generated_factory(),
- sizeof(SourceCodeInfo_Location));
+ -1,
+ sizeof(SourceCodeInfo_Location),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_),
+ -1);
}
namespace {
@@ -462,45 +506,47 @@ inline void protobuf_AssignDescriptorsOnce() {
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- FileDescriptorSet_descriptor_, &FileDescriptorSet::default_instance());
+ FileDescriptorSet_descriptor_, &FileDescriptorSet::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- FileDescriptorProto_descriptor_, &FileDescriptorProto::default_instance());
+ FileDescriptorProto_descriptor_, &FileDescriptorProto::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- DescriptorProto_descriptor_, &DescriptorProto::default_instance());
+ DescriptorProto_descriptor_, &DescriptorProto::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance());
+ DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance());
+ FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- EnumDescriptorProto_descriptor_, &EnumDescriptorProto::default_instance());
+ OneofDescriptorProto_descriptor_, &OneofDescriptorProto::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- EnumValueDescriptorProto_descriptor_, &EnumValueDescriptorProto::default_instance());
+ EnumDescriptorProto_descriptor_, &EnumDescriptorProto::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- ServiceDescriptorProto_descriptor_, &ServiceDescriptorProto::default_instance());
+ EnumValueDescriptorProto_descriptor_, &EnumValueDescriptorProto::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- MethodDescriptorProto_descriptor_, &MethodDescriptorProto::default_instance());
+ ServiceDescriptorProto_descriptor_, &ServiceDescriptorProto::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- FileOptions_descriptor_, &FileOptions::default_instance());
+ MethodDescriptorProto_descriptor_, &MethodDescriptorProto::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- MessageOptions_descriptor_, &MessageOptions::default_instance());
+ FileOptions_descriptor_, &FileOptions::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- FieldOptions_descriptor_, &FieldOptions::default_instance());
+ MessageOptions_descriptor_, &MessageOptions::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- EnumOptions_descriptor_, &EnumOptions::default_instance());
+ FieldOptions_descriptor_, &FieldOptions::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- EnumValueOptions_descriptor_, &EnumValueOptions::default_instance());
+ EnumOptions_descriptor_, &EnumOptions::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- ServiceOptions_descriptor_, &ServiceOptions::default_instance());
+ EnumValueOptions_descriptor_, &EnumValueOptions::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- MethodOptions_descriptor_, &MethodOptions::default_instance());
+ ServiceOptions_descriptor_, &ServiceOptions::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- UninterpretedOption_descriptor_, &UninterpretedOption::default_instance());
+ MethodOptions_descriptor_, &MethodOptions::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- UninterpretedOption_NamePart_descriptor_, &UninterpretedOption_NamePart::default_instance());
+ UninterpretedOption_descriptor_, &UninterpretedOption::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- SourceCodeInfo_descriptor_, &SourceCodeInfo::default_instance());
+ UninterpretedOption_NamePart_descriptor_, &UninterpretedOption_NamePart::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
- SourceCodeInfo_Location_descriptor_, &SourceCodeInfo_Location::default_instance());
+ SourceCodeInfo_descriptor_, &SourceCodeInfo::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ SourceCodeInfo_Location_descriptor_, &SourceCodeInfo_Location::default_instance());
}
} // namespace
@@ -516,6 +562,8 @@ void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto() {
delete DescriptorProto_ExtensionRange_reflection_;
delete FieldDescriptorProto::default_instance_;
delete FieldDescriptorProto_reflection_;
+ delete OneofDescriptorProto::default_instance_;
+ delete OneofDescriptorProto_reflection_;
delete EnumDescriptorProto::default_instance_;
delete EnumDescriptorProto_reflection_;
delete EnumValueDescriptorProto::default_instance_;
@@ -558,102 +606,119 @@ 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\"\227\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"
- "6\n\014message_type\030\004 \003(\0132 .google.protobuf."
- "DescriptorProto\0227\n\tenum_type\030\005 \003(\0132$.goo"
- "gle.protobuf.EnumDescriptorProto\0228\n\007serv"
- "ice\030\006 \003(\0132\'.google.protobuf.ServiceDescr"
- "iptorProto\0228\n\textension\030\007 \003(\0132%.google.p"
- "rotobuf.FieldDescriptorProto\022-\n\007options\030"
- "\010 \001(\0132\034.google.protobuf.FileOptions\0229\n\020s"
- "ource_code_info\030\t \001(\0132\037.google.protobuf."
- "SourceCodeInfo\"\251\003\n\017DescriptorProto\022\014\n\004na"
- "me\030\001 \001(\t\0224\n\005field\030\002 \003(\0132%.google.protobu"
- "f.FieldDescriptorProto\0228\n\textension\030\006 \003("
+ "\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"
+ "le.protobuf.DescriptorProto\0227\n\tenum_type"
+ "\030\005 \003(\0132$.google.protobuf.EnumDescriptorP"
+ "roto\0228\n\007service\030\006 \003(\0132\'.google.protobuf."
+ "ServiceDescriptorProto\0228\n\textension\030\007 \003("
"\0132%.google.protobuf.FieldDescriptorProto"
- "\0225\n\013nested_type\030\003 \003(\0132 .google.protobuf."
- "DescriptorProto\0227\n\tenum_type\030\004 \003(\0132$.goo"
- "gle.protobuf.EnumDescriptorProto\022H\n\017exte"
- "nsion_range\030\005 \003(\0132/.google.protobuf.Desc"
- "riptorProto.ExtensionRange\0220\n\007options\030\007 "
- "\001(\0132\037.google.protobuf.MessageOptions\032,\n\016"
- "ExtensionRange\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001"
- "(\005\"\224\005\n\024FieldDescriptorProto\022\014\n\004name\030\001 \001("
- "\t\022\016\n\006number\030\003 \001(\005\022:\n\005label\030\004 \001(\0162+.googl"
- "e.protobuf.FieldDescriptorProto.Label\0228\n"
- "\004type\030\005 \001(\0162*.google.protobuf.FieldDescr"
- "iptorProto.Type\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010ex"
- "tendee\030\002 \001(\t\022\025\n\rdefault_value\030\007 \001(\t\022.\n\007o"
- "ptions\030\010 \001(\0132\035.google.protobuf.FieldOpti"
- "ons\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FL"
- "OAT\020\002\022\016\n\nTYPE_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_GROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\n"
- "TYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_EN"
- "UM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_SFIXED64"
- "\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005"
- "Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n\016LABEL_REQUI"
- "RED\020\002\022\022\n\016LABEL_REPEATED\020\003\"\214\001\n\023EnumDescri"
- "ptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002 \003(\0132)"
- ".google.protobuf.EnumValueDescriptorProt"
- "o\022-\n\007options\030\003 \001(\0132\034.google.protobuf.Enu"
- "mOptions\"l\n\030EnumValueDescriptorProto\022\014\n\004"
- "name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007options\030\003 "
- "\001(\0132!.google.protobuf.EnumValueOptions\"\220"
- "\001\n\026ServiceDescriptorProto\022\014\n\004name\030\001 \001(\t\022"
- "6\n\006method\030\002 \003(\0132&.google.protobuf.Method"
- "DescriptorProto\0220\n\007options\030\003 \001(\0132\037.googl"
- "e.protobuf.ServiceOptions\"\177\n\025MethodDescr"
- "iptorProto\022\014\n\004name\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.protobuf.MethodOptions\"\325\003\n\013F"
- "ileOptions\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_generate_equa"
- "ls_and_hash\030\024 \001(\010:\005false\022F\n\014optimize_for"
- "\030\t \001(\0162).google.protobuf.FileOptions.Opt"
- "imizeMode:\005SPEED\022\"\n\023cc_generic_services\030"
- "\020 \001(\010:\005false\022$\n\025java_generic_services\030\021 "
- "\001(\010:\005false\022\"\n\023py_generic_services\030\022 \001(\010:"
- "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$."
- "google.protobuf.UninterpretedOption\":\n\014O"
- "ptimizeMode\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\"\270\001\n\016MessageOp"
- "tions\022&\n\027message_set_wire_format\030\001 \001(\010:\005"
- "false\022.\n\037no_standard_descriptor_accessor"
- "\030\002 \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007"
+ "\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\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\"\301\001\n\025MethodDescriptorProto\022\014\n"
+ "\004name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013outpu"
+ "t_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.p"
+ "rotobuf.MethodOptions\022\037\n\020client_streamin"
+ "g\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010"
+ ":\005false\"\347\004\n\013FileOptions\022\024\n\014java_package\030"
+ "\001 \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023j"
+ "ava_multiple_files\030\n \001(\010:\005false\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\014"
+ "optimize_for\030\t \001(\0162).google.protobuf.Fil"
+ "eOptions.OptimizeMode:\005SPEED\022\022\n\ngo_packa"
+ "ge\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005f"
+ "alse\022$\n\025java_generic_services\030\021 \001(\010:\005fal"
+ "se\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031"
+ "\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_a"
+ "renas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030"
+ "$ \001(\t\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.g"
+ "oogle.protobuf.UninterpretedOption\":\n\014Op"
+ "timizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014"
+ "LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOpt"
+ "ions\022&\n\027message_set_wire_format\030\001 \001(\010:\005f"
+ "alse\022.\n\037no_standard_descriptor_accessor\030"
+ "\002 \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022"
+ "\021\n\tmap_entry\030\007 \001(\010\022C\n\024uninterpreted_opti"
+ "on\030\347\007 \003(\0132$.google.protobuf.Uninterprete"
+ "dOption*\t\010\350\007\020\200\200\200\200\002\"\240\002\n\014FieldOptions\022:\n\005c"
+ "type\030\001 \001(\0162#.google.protobuf.FieldOption"
+ "s.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"
+ "\023\n\004weak\030\n \001(\010:\005false\022C\n\024uninterpreted_op"
+ "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre"
+ "tedOption\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001"
+ "\022\020\n\014STRING_PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOp"
+ "tions\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.UninterpretedOpti"
- "on*\t\010\350\007\020\200\200\200\200\002\"\224\002\n\014FieldOptions\022:\n\005ctype\030"
- "\001 \001(\0162#.google.protobuf.FieldOptions.CTy"
- "pe:\006STRING\022\016\n\006packed\030\002 \001(\010\022\031\n\ndeprecated"
- "\030\003 \001(\010:\005false\022\034\n\024experimental_map_key\030\t "
- "\001(\t\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo"
- "gle.protobuf.UninterpretedOption\"/\n\005CTyp"
- "e\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020"
- "\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022C\n\024uninterpr"
- "eted_option\030\347\007 \003(\0132$.google.protobuf.Uni"
- "nterpretedOption*\t\010\350\007\020\200\200\200\200\002\"b\n\020EnumValue"
- "Options\022C\n\024uninterpreted_option\030\347\007 \003(\0132$"
- ".google.protobuf.UninterpretedOption*\t\010\350"
- "\007\020\200\200\200\200\002\"`\n\016ServiceOptions\022C\n\024uninterpret"
+ "on*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndep"
+ "recated\030\001 \001(\010:\005false\022C\n\024uninterpreted_op"
+ "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre"
+ "tedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031"
+ "\n\ndeprecated\030! \001(\010:\005false\022C\n\024uninterpret"
"ed_option\030\347\007 \003(\0132$.google.protobuf.Unint"
- "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"_\n\rMethodOptio"
- "ns\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goog"
- "le.protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200"
- "\200\002\"\236\002\n\023UninterpretedOption\022;\n\004name\030\002 \003(\013"
- "2-.google.protobuf.UninterpretedOption.N"
- "amePart\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022pos"
- "itive_int_value\030\004 \001(\004\022\032\n\022negative_int_va"
- "lue\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014strin"
- "g_value\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323"
- "\n\010NamePart\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_exte"
- "nsion\030\002 \002(\010\"|\n\016SourceCodeInfo\022:\n\010locatio"
- "n\030\001 \003(\0132(.google.protobuf.SourceCodeInfo"
- ".Location\032.\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022"
- "\020\n\004span\030\002 \003(\005B\002\020\001B)\n\023com.google.protobuf"
- "B\020DescriptorProtosH\001", 3940);
+ "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptio"
+ "ns\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024uninter"
+ "preted_option\030\347\007 \003(\0132$.google.protobuf.U"
+ "ninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023Uninte"
+ "rpretedOption\022;\n\004name\030\002 \003(\0132-.google.pro"
+ "tobuf.UninterpretedOption.NamePart\022\030\n\020id"
+ "entifier_value\030\003 \001(\t\022\032\n\022positive_int_val"
+ "ue\030\004 \001(\004\022\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014"
+ "double_value\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014"
+ "\022\027\n\017aggregate_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\"\325"
+ "\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003(\0132(.go"
+ "ogle.protobuf.SourceCodeInfo.Location\032\206\001"
+ "\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\020leading_comments\030\003 \001(\t\022\031\n\021trai"
+ "ling_comments\030\004 \001(\t\022!\n\031leading_detached_"
+ "comments\030\006 \003(\tB)\n\023com.google.protobufB\020D"
+ "escriptorProtosH\001", 4617);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
FileDescriptorSet::default_instance_ = new FileDescriptorSet();
@@ -661,6 +726,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
DescriptorProto::default_instance_ = new DescriptorProto();
DescriptorProto_ExtensionRange::default_instance_ = new DescriptorProto_ExtensionRange();
FieldDescriptorProto::default_instance_ = new FieldDescriptorProto();
+ OneofDescriptorProto::default_instance_ = new OneofDescriptorProto();
EnumDescriptorProto::default_instance_ = new EnumDescriptorProto();
EnumValueDescriptorProto::default_instance_ = new EnumValueDescriptorProto();
ServiceDescriptorProto::default_instance_ = new ServiceDescriptorProto();
@@ -681,6 +747,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
DescriptorProto::default_instance_->InitAsDefaultInstance();
DescriptorProto_ExtensionRange::default_instance_->InitAsDefaultInstance();
FieldDescriptorProto::default_instance_->InitAsDefaultInstance();
+ OneofDescriptorProto::default_instance_->InitAsDefaultInstance();
EnumDescriptorProto::default_instance_->InitAsDefaultInstance();
EnumValueDescriptorProto::default_instance_->InitAsDefaultInstance();
ServiceDescriptorProto::default_instance_->InitAsDefaultInstance();
@@ -706,6 +773,15 @@ struct StaticDescriptorInitializer_google_2fprotobuf_2fdescriptor_2eproto {
}
} static_descriptor_initializer_google_2fprotobuf_2fdescriptor_2eproto_;
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+ GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+} // namespace
+
// ===================================================================
@@ -714,17 +790,20 @@ 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)
}
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)
}
void FileDescriptorSet::SharedCtor() {
@@ -733,6 +812,7 @@ void FileDescriptorSet::SharedCtor() {
}
FileDescriptorSet::~FileDescriptorSet() {
+ // @@protoc_insertion_point(destructor:google.protobuf.FileDescriptorSet)
SharedDtor();
}
@@ -752,47 +832,58 @@ const ::google::protobuf::Descriptor* FileDescriptorSet::descriptor() {
}
const FileDescriptorSet& FileDescriptorSet::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
FileDescriptorSet* FileDescriptorSet::default_instance_ = NULL;
-FileDescriptorSet* FileDescriptorSet::New() const {
- return new FileDescriptorSet;
+FileDescriptorSet* FileDescriptorSet::New(::google::protobuf::Arena* arena) const {
+ FileDescriptorSet* n = new FileDescriptorSet;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.FileDescriptorSet)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// repeated .google.protobuf.FileDescriptorProto file = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
parse_file:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_file()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(10)) goto parse_file;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -800,43 +891,52 @@ bool FileDescriptorSet::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.FileDescriptorSet)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.FileDescriptorSet)
+ return false;
#undef DO_
}
void FileDescriptorSet::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.FileDescriptorSet)
// repeated .google.protobuf.FileDescriptorProto file = 1;
- for (int i = 0; i < this->file_size(); i++) {
+ for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
1, this->file(i), output);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.FileDescriptorSet)
}
::google::protobuf::uint8* FileDescriptorSet::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorSet)
// repeated .google.protobuf.FileDescriptorProto file = 1;
- for (int i = 0; i < this->file_size(); i++) {
+ for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
1, this->file(i), target);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorSet)
return target;
}
int FileDescriptorSet::ByteSize() const {
int total_size = 0;
-
+
// repeated .google.protobuf.FileDescriptorProto file = 1;
total_size += 1 * this->file_size();
for (int i = 0; i < this->file_size(); i++) {
@@ -844,8 +944,8 @@ int FileDescriptorSet::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->file(i));
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -857,7 +957,7 @@ int FileDescriptorSet::ByteSize() const {
}
void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const FileDescriptorSet* source =
::google::protobuf::internal::dynamic_cast_if_available<const FileDescriptorSet*>(
&from);
@@ -869,9 +969,11 @@ void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) {
}
void FileDescriptorSet::MergeFrom(const FileDescriptorSet& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
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) {
@@ -887,20 +989,20 @@ void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) {
}
bool FileDescriptorSet::IsInitialized() const {
-
- for (int i = 0; i < file_size(); i++) {
- if (!this->file(i).IsInitialized()) return false;
- }
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->file())) return false;
return true;
}
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;
+ 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 {
@@ -911,6 +1013,40 @@ void FileDescriptorSet::Swap(FileDescriptorSet* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FileDescriptorSet
+
+// repeated .google.protobuf.FileDescriptorProto file = 1;
+ int FileDescriptorSet::file_size() const {
+ return file_.size();
+}
+ void FileDescriptorSet::clear_file() {
+ file_.Clear();
+}
+ const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorSet.file)
+ return file_.Get(index);
+}
+ ::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorSet.file)
+ return file_.Mutable(index);
+}
+ ::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorSet.file)
+ return file_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+FileDescriptorSet::file() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file)
+ return file_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+FileDescriptorSet::mutable_file() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorSet.file)
+ return &file_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -918,17 +1054,21 @@ void FileDescriptorSet::Swap(FileDescriptorSet* other) {
const int FileDescriptorProto::kNameFieldNumber;
const int FileDescriptorProto::kPackageFieldNumber;
const int FileDescriptorProto::kDependencyFieldNumber;
+const int FileDescriptorProto::kPublicDependencyFieldNumber;
+const int FileDescriptorProto::kWeakDependencyFieldNumber;
const int FileDescriptorProto::kMessageTypeFieldNumber;
const int FileDescriptorProto::kEnumTypeFieldNumber;
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)
}
void FileDescriptorProto::InitAsDefaultInstance() {
@@ -937,31 +1077,33 @@ void FileDescriptorProto::InitAsDefaultInstance() {
}
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)
}
void FileDescriptorProto::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ 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_));
}
FileDescriptorProto::~FileDescriptorProto() {
+ // @@protoc_insertion_point(destructor:google.protobuf.FileDescriptorProto)
SharedDtor();
}
void FileDescriptorProto::SharedDtor() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- delete name_;
- }
- if (package_ != &::google::protobuf::internal::kEmptyString) {
- delete package_;
- }
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ package_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ syntax_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
delete options_;
delete source_code_info_;
@@ -979,195 +1121,258 @@ const ::google::protobuf::Descriptor* FileDescriptorProto::descriptor() {
}
const FileDescriptorProto& FileDescriptorProto::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
FileDescriptorProto* FileDescriptorProto::default_instance_ = NULL;
-FileDescriptorProto* FileDescriptorProto::New() const {
- return new FileDescriptorProto;
+FileDescriptorProto* FileDescriptorProto::New(::google::protobuf::Arena* arena) const {
+ FileDescriptorProto* n = new FileDescriptorProto;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void FileDescriptorProto::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bits_[0 / 32] & 3) {
if (has_name()) {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_package()) {
- if (package_ != &::google::protobuf::internal::kEmptyString) {
- package_->clear();
- }
+ package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
+ }
+ if (_has_bits_[8 / 32] & 3584) {
if (has_options()) {
if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
}
- }
- if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
if (has_source_code_info()) {
if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear();
}
+ if (has_syntax()) {
+ syntax_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
}
dependency_.Clear();
+ public_dependency_.Clear();
+ weak_dependency_.Clear();
message_type_.Clear();
enum_type_.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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.FileDescriptorProto)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string name = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FileDescriptorProto.name");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_package;
break;
}
-
+
// optional string package = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_package:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_package()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->package().data(), this->package().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FileDescriptorProto.package");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(26)) goto parse_dependency;
break;
}
-
+
// repeated string dependency = 3;
case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 26) {
parse_dependency:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->add_dependency()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
- this->dependency(0).data(), this->dependency(0).length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->dependency(this->dependency_size() - 1).data(),
+ this->dependency(this->dependency_size() - 1).length(),
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FileDescriptorProto.dependency");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(26)) goto parse_dependency;
if (input->ExpectTag(34)) goto parse_message_type;
break;
}
-
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
case 4: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 34) {
parse_message_type:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_message_type()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(34)) goto parse_message_type;
if (input->ExpectTag(42)) goto parse_enum_type;
break;
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
case 5: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 42) {
parse_enum_type:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_enum_type()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(42)) goto parse_enum_type;
if (input->ExpectTag(50)) goto parse_service;
break;
}
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
case 6: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 50) {
parse_service:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_service()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(50)) goto parse_service;
if (input->ExpectTag(58)) goto parse_extension;
break;
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
case 7: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 58) {
parse_extension:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_extension()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(58)) goto parse_extension;
if (input->ExpectTag(66)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.FileOptions options = 8;
case 8: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 66) {
parse_options:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, mutable_options()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(74)) goto parse_source_code_info;
break;
}
-
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
case 9: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 74) {
parse_source_code_info:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, mutable_source_code_info()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectTag(80)) goto parse_public_dependency;
break;
}
-
+
+ // repeated int32 public_dependency = 10;
+ case 10: {
+ if (tag == 80) {
+ parse_public_dependency:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ 1, 80, input, this->mutable_public_dependency())));
+ } else if (tag == 82) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, this->mutable_public_dependency())));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(80)) goto parse_public_dependency;
+ if (input->ExpectTag(88)) goto parse_weak_dependency;
+ break;
+ }
+
+ // repeated int32 weak_dependency = 11;
+ case 11: {
+ if (tag == 88) {
+ parse_weak_dependency:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ 1, 88, input, this->mutable_weak_dependency())));
+ } else if (tag == 90) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, this->mutable_weak_dependency())));
+ } else {
+ 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;
+ }
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -1175,195 +1380,262 @@ bool FileDescriptorProto::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.FileDescriptorProto)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.FileDescriptorProto)
+ return false;
#undef DO_
}
void FileDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.FileDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileDescriptorProto.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->name(), output);
}
-
+
// optional string package = 2;
if (has_package()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->package().data(), this->package().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileDescriptorProto.package");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
2, this->package(), output);
}
-
+
// repeated string dependency = 3;
for (int i = 0; i < this->dependency_size(); i++) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->dependency(i).data(), this->dependency(i).length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileDescriptorProto.dependency");
::google::protobuf::internal::WireFormatLite::WriteString(
3, this->dependency(i), output);
}
-
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
- for (int i = 0; i < this->message_type_size(); i++) {
+ for (unsigned int i = 0, n = this->message_type_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
4, this->message_type(i), output);
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
- for (int i = 0; i < this->enum_type_size(); i++) {
+ for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
5, this->enum_type(i), output);
}
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
- for (int i = 0; i < this->service_size(); i++) {
+ for (unsigned int i = 0, n = this->service_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
6, this->service(i), output);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
- for (int i = 0; i < this->extension_size(); i++) {
+ for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
7, this->extension(i), output);
}
-
+
// optional .google.protobuf.FileOptions options = 8;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
- 8, this->options(), output);
+ 8, *this->options_, output);
}
-
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
if (has_source_code_info()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
- 9, this->source_code_info(), output);
+ 9, *this->source_code_info_, output);
+ }
+
+ // repeated int32 public_dependency = 10;
+ for (int i = 0; i < this->public_dependency_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(
+ 10, this->public_dependency(i), output);
+ }
+
+ // repeated int32 weak_dependency = 11;
+ for (int i = 0; i < this->weak_dependency_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(
+ 11, this->weak_dependency(i), output);
+ }
+
+ // 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 (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.FileDescriptorProto)
}
::google::protobuf::uint8* FileDescriptorProto::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileDescriptorProto.name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional string package = 2;
if (has_package()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->package().data(), this->package().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileDescriptorProto.package");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->package(), target);
}
-
+
// repeated string dependency = 3;
for (int i = 0; i < this->dependency_size(); i++) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->dependency(i).data(), this->dependency(i).length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileDescriptorProto.dependency");
target = ::google::protobuf::internal::WireFormatLite::
WriteStringToArray(3, this->dependency(i), target);
}
-
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
- for (int i = 0; i < this->message_type_size(); i++) {
+ for (unsigned int i = 0, n = this->message_type_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
4, this->message_type(i), target);
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
- for (int i = 0; i < this->enum_type_size(); i++) {
+ for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
5, this->enum_type(i), target);
}
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
- for (int i = 0; i < this->service_size(); i++) {
+ for (unsigned int i = 0, n = this->service_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
6, this->service(i), target);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
- for (int i = 0; i < this->extension_size(); i++) {
+ for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
7, this->extension(i), target);
}
-
+
// optional .google.protobuf.FileOptions options = 8;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
- 8, this->options(), target);
+ 8, *this->options_, target);
}
-
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
if (has_source_code_info()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
- 9, this->source_code_info(), target);
+ 9, *this->source_code_info_, target);
}
-
- if (!unknown_fields().empty()) {
+
+ // repeated int32 public_dependency = 10;
+ for (int i = 0; i < this->public_dependency_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteInt32ToArray(10, this->public_dependency(i), target);
+ }
+
+ // repeated int32 weak_dependency = 11;
+ for (int i = 0; i < this->weak_dependency_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteInt32ToArray(11, this->weak_dependency(i), target);
+ }
+
+ // 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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorProto)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional string package = 2;
if (has_package()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->package());
}
-
+
+ }
+ if (_has_bits_[9 / 32] & 3584) {
// optional .google.protobuf.FileOptions options = 8;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
- this->options());
+ *this->options_);
}
-
- }
- if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
if (has_source_code_info()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
- this->source_code_info());
+ *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();
@@ -1371,7 +1643,27 @@ int FileDescriptorProto::ByteSize() const {
total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
this->dependency(i));
}
-
+
+ // repeated int32 public_dependency = 10;
+ {
+ int data_size = 0;
+ for (int i = 0; i < this->public_dependency_size(); i++) {
+ data_size += ::google::protobuf::internal::WireFormatLite::
+ Int32Size(this->public_dependency(i));
+ }
+ total_size += 1 * this->public_dependency_size() + data_size;
+ }
+
+ // repeated int32 weak_dependency = 11;
+ {
+ int data_size = 0;
+ for (int i = 0; i < this->weak_dependency_size(); i++) {
+ data_size += ::google::protobuf::internal::WireFormatLite::
+ Int32Size(this->weak_dependency(i));
+ }
+ total_size += 1 * this->weak_dependency_size() + data_size;
+ }
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
total_size += 1 * this->message_type_size();
for (int i = 0; i < this->message_type_size(); i++) {
@@ -1379,7 +1671,7 @@ int FileDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->message_type(i));
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
total_size += 1 * this->enum_type_size();
for (int i = 0; i < this->enum_type_size(); i++) {
@@ -1387,7 +1679,7 @@ int FileDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->enum_type(i));
}
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
total_size += 1 * this->service_size();
for (int i = 0; i < this->service_size(); i++) {
@@ -1395,7 +1687,7 @@ int FileDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->service(i));
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
total_size += 1 * this->extension_size();
for (int i = 0; i < this->extension_size(); i++) {
@@ -1403,8 +1695,8 @@ int FileDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->extension(i));
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -1416,7 +1708,7 @@ int FileDescriptorProto::ByteSize() const {
}
void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const FileDescriptorProto* source =
::google::protobuf::internal::dynamic_cast_if_available<const FileDescriptorProto*>(
&from);
@@ -1428,29 +1720,39 @@ void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
}
void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
dependency_.MergeFrom(from.dependency_);
+ public_dependency_.MergeFrom(from.public_dependency_);
+ weak_dependency_.MergeFrom(from.weak_dependency_);
message_type_.MergeFrom(from.message_type_);
enum_type_.MergeFrom(from.enum_type_);
service_.MergeFrom(from.service_);
extension_.MergeFrom(from.extension_);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_name()) {
- set_name(from.name());
+ set_has_name();
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
}
if (from.has_package()) {
- set_package(from.package());
+ set_has_package();
+ package_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.package_);
}
+ }
+ if (from._has_bits_[9 / 32] & (0xffu << (9 % 32))) {
if (from.has_options()) {
mutable_options()->::google::protobuf::FileOptions::MergeFrom(from.options());
}
- }
- if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
if (from.has_source_code_info()) {
mutable_source_code_info()->::google::protobuf::SourceCodeInfo::MergeFrom(from.source_code_info());
}
+ if (from.has_syntax()) {
+ set_has_syntax();
+ syntax_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 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) {
@@ -1466,40 +1768,37 @@ void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) {
}
bool FileDescriptorProto::IsInitialized() const {
-
- for (int i = 0; i < message_type_size(); i++) {
- if (!this->message_type(i).IsInitialized()) return false;
- }
- for (int i = 0; i < enum_type_size(); i++) {
- if (!this->enum_type(i).IsInitialized()) return false;
- }
- for (int i = 0; i < service_size(); i++) {
- if (!this->service(i).IsInitialized()) return false;
- }
- for (int i = 0; i < extension_size(); i++) {
- if (!this->extension(i).IsInitialized()) return false;
- }
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->message_type())) return false;
+ if (!::google::protobuf::internal::AllAreInitialized(this->enum_type())) return false;
+ if (!::google::protobuf::internal::AllAreInitialized(this->service())) return false;
+ if (!::google::protobuf::internal::AllAreInitialized(this->extension())) return false;
if (has_options()) {
- if (!this->options().IsInitialized()) return false;
+ if (!this->options_->IsInitialized()) return false;
}
return true;
}
void FileDescriptorProto::Swap(FileDescriptorProto* other) {
- if (other != this) {
- std::swap(name_, other->name_);
- std::swap(package_, other->package_);
- dependency_.Swap(&other->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;
+ 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 {
@@ -1510,6 +1809,489 @@ void FileDescriptorProto::Swap(FileDescriptorProto* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FileDescriptorProto
+
+// optional string name = 1;
+ bool FileDescriptorProto::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void FileDescriptorProto::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void FileDescriptorProto::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void FileDescriptorProto::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& FileDescriptorProto::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.name)
+}
+ void FileDescriptorProto::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.name)
+}
+ void FileDescriptorProto::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.name)
+}
+ ::std::string* FileDescriptorProto::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileDescriptorProto::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.name)
+}
+
+// optional string package = 2;
+ bool FileDescriptorProto::has_package() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void FileDescriptorProto::set_has_package() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void FileDescriptorProto::clear_has_package() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void FileDescriptorProto::clear_package() {
+ package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_package();
+}
+ const ::std::string& FileDescriptorProto::package() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.package)
+ return package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_package(const ::std::string& value) {
+ set_has_package();
+ package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.package)
+}
+ void FileDescriptorProto::set_package(const char* value) {
+ set_has_package();
+ package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.package)
+}
+ void FileDescriptorProto::set_package(const char* value, size_t size) {
+ set_has_package();
+ package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.package)
+}
+ ::std::string* FileDescriptorProto::mutable_package() {
+ set_has_package();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.package)
+ return package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileDescriptorProto::release_package() {
+ clear_has_package();
+ return package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_allocated_package(::std::string* package) {
+ if (package != NULL) {
+ set_has_package();
+ } else {
+ clear_has_package();
+ }
+ package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), package);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.package)
+}
+
+// repeated string dependency = 3;
+ int FileDescriptorProto::dependency_size() const {
+ return dependency_.size();
+}
+ void FileDescriptorProto::clear_dependency() {
+ dependency_.Clear();
+}
+ const ::std::string& FileDescriptorProto::dependency(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.dependency)
+ return dependency_.Get(index);
+}
+ ::std::string* FileDescriptorProto::mutable_dependency(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.dependency)
+ return dependency_.Mutable(index);
+}
+ void FileDescriptorProto::set_dependency(int index, const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.dependency)
+ dependency_.Mutable(index)->assign(value);
+}
+ void FileDescriptorProto::set_dependency(int index, const char* value) {
+ dependency_.Mutable(index)->assign(value);
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.dependency)
+}
+ void FileDescriptorProto::set_dependency(int index, const char* value, size_t size) {
+ dependency_.Mutable(index)->assign(
+ reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency)
+}
+ ::std::string* FileDescriptorProto::add_dependency() {
+ return dependency_.Add();
+}
+ void FileDescriptorProto::add_dependency(const ::std::string& value) {
+ dependency_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.dependency)
+}
+ void FileDescriptorProto::add_dependency(const char* value) {
+ dependency_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add_char:google.protobuf.FileDescriptorProto.dependency)
+}
+ void FileDescriptorProto::add_dependency(const char* value, size_t size) {
+ dependency_.Add()->assign(reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_add_pointer:google.protobuf.FileDescriptorProto.dependency)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FileDescriptorProto::dependency() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.dependency)
+ return dependency_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+FileDescriptorProto::mutable_dependency() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.dependency)
+ return &dependency_;
+}
+
+// repeated int32 public_dependency = 10;
+ int FileDescriptorProto::public_dependency_size() const {
+ return public_dependency_.size();
+}
+ void FileDescriptorProto::clear_public_dependency() {
+ public_dependency_.Clear();
+}
+ ::google::protobuf::int32 FileDescriptorProto::public_dependency(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.public_dependency)
+ return public_dependency_.Get(index);
+}
+ void FileDescriptorProto::set_public_dependency(int index, ::google::protobuf::int32 value) {
+ public_dependency_.Set(index, value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.public_dependency)
+}
+ void FileDescriptorProto::add_public_dependency(::google::protobuf::int32 value) {
+ public_dependency_.Add(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.public_dependency)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+FileDescriptorProto::public_dependency() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.public_dependency)
+ return public_dependency_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+FileDescriptorProto::mutable_public_dependency() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.public_dependency)
+ return &public_dependency_;
+}
+
+// repeated int32 weak_dependency = 11;
+ int FileDescriptorProto::weak_dependency_size() const {
+ return weak_dependency_.size();
+}
+ void FileDescriptorProto::clear_weak_dependency() {
+ weak_dependency_.Clear();
+}
+ ::google::protobuf::int32 FileDescriptorProto::weak_dependency(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.weak_dependency)
+ return weak_dependency_.Get(index);
+}
+ void FileDescriptorProto::set_weak_dependency(int index, ::google::protobuf::int32 value) {
+ weak_dependency_.Set(index, value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+ void FileDescriptorProto::add_weak_dependency(::google::protobuf::int32 value) {
+ weak_dependency_.Add(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+FileDescriptorProto::weak_dependency() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.weak_dependency)
+ return weak_dependency_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+FileDescriptorProto::mutable_weak_dependency() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.weak_dependency)
+ return &weak_dependency_;
+}
+
+// repeated .google.protobuf.DescriptorProto message_type = 4;
+ int FileDescriptorProto::message_type_size() const {
+ return message_type_.size();
+}
+ void FileDescriptorProto::clear_message_type() {
+ message_type_.Clear();
+}
+ const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.message_type)
+ return message_type_.Get(index);
+}
+ ::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.message_type)
+ return message_type_.Mutable(index);
+}
+ ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.message_type)
+ return message_type_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+FileDescriptorProto::message_type() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type)
+ return message_type_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+FileDescriptorProto::mutable_message_type() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.message_type)
+ return &message_type_;
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+ int FileDescriptorProto::enum_type_size() const {
+ return enum_type_.size();
+}
+ void FileDescriptorProto::clear_enum_type() {
+ enum_type_.Clear();
+}
+ const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.enum_type)
+ return enum_type_.Get(index);
+}
+ ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.enum_type)
+ return enum_type_.Mutable(index);
+}
+ ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.enum_type)
+ return enum_type_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+FileDescriptorProto::enum_type() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type)
+ return enum_type_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+FileDescriptorProto::mutable_enum_type() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.enum_type)
+ return &enum_type_;
+}
+
+// repeated .google.protobuf.ServiceDescriptorProto service = 6;
+ int FileDescriptorProto::service_size() const {
+ return service_.size();
+}
+ void FileDescriptorProto::clear_service() {
+ service_.Clear();
+}
+ const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.service)
+ return service_.Get(index);
+}
+ ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.service)
+ return service_.Mutable(index);
+}
+ ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.service)
+ return service_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
+FileDescriptorProto::service() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service)
+ return service_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
+FileDescriptorProto::mutable_service() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.service)
+ return &service_;
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 7;
+ int FileDescriptorProto::extension_size() const {
+ return extension_.size();
+}
+ void FileDescriptorProto::clear_extension() {
+ extension_.Clear();
+}
+ const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.extension)
+ return extension_.Get(index);
+}
+ ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.extension)
+ return extension_.Mutable(index);
+}
+ ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.extension)
+ return extension_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+FileDescriptorProto::extension() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension)
+ return extension_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+FileDescriptorProto::mutable_extension() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.extension)
+ return &extension_;
+}
+
+// optional .google.protobuf.FileOptions options = 8;
+ bool FileDescriptorProto::has_options() const {
+ return (_has_bits_[0] & 0x00000200u) != 0;
+}
+ void FileDescriptorProto::set_has_options() {
+ _has_bits_[0] |= 0x00000200u;
+}
+ void FileDescriptorProto::clear_has_options() {
+ _has_bits_[0] &= ~0x00000200u;
+}
+ void FileDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
+ clear_has_options();
+}
+ const ::google::protobuf::FileOptions& FileDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.options)
+ return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+ ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() {
+ set_has_options();
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::FileOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options)
+ return options_;
+}
+ ::google::protobuf::FileOptions* FileDescriptorProto::release_options() {
+ clear_has_options();
+ ::google::protobuf::FileOptions* temp = options_;
+ options_ = NULL;
+ return temp;
+}
+ void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.options)
+}
+
+// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+ bool FileDescriptorProto::has_source_code_info() const {
+ return (_has_bits_[0] & 0x00000400u) != 0;
+}
+ void FileDescriptorProto::set_has_source_code_info() {
+ _has_bits_[0] |= 0x00000400u;
+}
+ void FileDescriptorProto::clear_has_source_code_info() {
+ _has_bits_[0] &= ~0x00000400u;
+}
+ void FileDescriptorProto::clear_source_code_info() {
+ if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear();
+ clear_has_source_code_info();
+}
+ const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_code_info() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.source_code_info)
+ return source_code_info_ != NULL ? *source_code_info_ : *default_instance_->source_code_info_;
+}
+ ::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;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info)
+ return source_code_info_;
+}
+ ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() {
+ clear_has_source_code_info();
+ ::google::protobuf::SourceCodeInfo* temp = source_code_info_;
+ source_code_info_ = NULL;
+ return temp;
+}
+ void FileDescriptorProto::set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info) {
+ 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_set_allocated:google.protobuf.FileDescriptorProto.source_code_info)
+}
+
+// optional string syntax = 12;
+ bool FileDescriptorProto::has_syntax() const {
+ return (_has_bits_[0] & 0x00000800u) != 0;
+}
+ void FileDescriptorProto::set_has_syntax() {
+ _has_bits_[0] |= 0x00000800u;
+}
+ void FileDescriptorProto::clear_has_syntax() {
+ _has_bits_[0] &= ~0x00000800u;
+}
+ void FileDescriptorProto::clear_syntax() {
+ syntax_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_syntax();
+}
+ const ::std::string& FileDescriptorProto::syntax() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.syntax)
+ return syntax_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_syntax(const ::std::string& value) {
+ set_has_syntax();
+ syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.syntax)
+}
+ void FileDescriptorProto::set_syntax(const char* value) {
+ set_has_syntax();
+ syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.syntax)
+}
+ void FileDescriptorProto::set_syntax(const char* value, size_t size) {
+ set_has_syntax();
+ syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.syntax)
+}
+ ::std::string* FileDescriptorProto::mutable_syntax() {
+ set_has_syntax();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.syntax)
+ return syntax_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileDescriptorProto::release_syntax() {
+ clear_has_syntax();
+ return syntax_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_allocated_syntax(::std::string* syntax) {
+ if (syntax != NULL) {
+ set_has_syntax();
+ } else {
+ clear_has_syntax();
+ }
+ syntax_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), syntax);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.syntax)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -1519,17 +2301,20 @@ 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)
}
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)
}
void DescriptorProto_ExtensionRange::SharedCtor() {
@@ -1540,6 +2325,7 @@ void DescriptorProto_ExtensionRange::SharedCtor() {
}
DescriptorProto_ExtensionRange::~DescriptorProto_ExtensionRange() {
+ // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ExtensionRange)
SharedDtor();
}
@@ -1559,66 +2345,85 @@ const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::descriptor
}
const DescriptorProto_ExtensionRange& DescriptorProto_ExtensionRange::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
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 {
+ DescriptorProto_ExtensionRange* n = new DescriptorProto_ExtensionRange;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void DescriptorProto_ExtensionRange::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
- start_ = 0;
- end_ = 0;
- }
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+ &reinterpret_cast<DescriptorProto_ExtensionRange*>(16)->f)
+
+#define ZR_(first, last) do {\
+ ::memset(&first, 0,\
+ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+ ZR_(start_, end_);
+
+#undef ZR_HELPER_
+#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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto.ExtensionRange)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional int32 start = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 8) {
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
input, &start_)));
set_has_start();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(16)) goto parse_end;
break;
}
-
+
// optional int32 end = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 16) {
parse_end:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
input, &end_)));
set_has_end();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -1626,67 +2431,76 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.DescriptorProto.ExtensionRange)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.DescriptorProto.ExtensionRange)
+ return false;
#undef DO_
}
void DescriptorProto_ExtensionRange::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.DescriptorProto.ExtensionRange)
// optional int32 start = 1;
if (has_start()) {
::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->start(), output);
}
-
+
// optional int32 end = 2;
if (has_end()) {
::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);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ExtensionRange)
}
::google::protobuf::uint8* DescriptorProto_ExtensionRange::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ExtensionRange)
// optional int32 start = 1;
if (has_start()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->start(), target);
}
-
+
// optional int32 end = 2;
if (has_end()) {
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ExtensionRange)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->start());
}
-
+
// optional int32 end = 2;
if (has_end()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->end());
}
-
+
}
- if (!unknown_fields().empty()) {
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -1698,7 +2512,7 @@ int DescriptorProto_ExtensionRange::ByteSize() const {
}
void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const DescriptorProto_ExtensionRange* source =
::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto_ExtensionRange*>(
&from);
@@ -1710,7 +2524,7 @@ void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message
}
void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRange& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_start()) {
set_start(from.start());
@@ -1719,7 +2533,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) {
@@ -1735,18 +2551,20 @@ void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRan
}
bool DescriptorProto_ExtensionRange::IsInitialized() const {
-
+
return true;
}
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;
+ 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 {
@@ -1767,12 +2585,14 @@ const int DescriptorProto::kExtensionFieldNumber;
const int DescriptorProto::kNestedTypeFieldNumber;
const int DescriptorProto::kEnumTypeFieldNumber;
const int DescriptorProto::kExtensionRangeFieldNumber;
+const int DescriptorProto::kOneofDeclFieldNumber;
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)
}
void DescriptorProto::InitAsDefaultInstance() {
@@ -1780,26 +2600,28 @@ void DescriptorProto::InitAsDefaultInstance() {
}
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)
}
void DescriptorProto::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
options_ = NULL;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
DescriptorProto::~DescriptorProto() {
+ // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto)
SharedDtor();
}
void DescriptorProto::SharedDtor() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- delete name_;
- }
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
delete options_;
}
@@ -1816,21 +2638,24 @@ const ::google::protobuf::Descriptor* DescriptorProto::descriptor() {
}
const DescriptorProto& DescriptorProto::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
DescriptorProto* DescriptorProto::default_instance_ = NULL;
-DescriptorProto* DescriptorProto::New() const {
- return new DescriptorProto;
+DescriptorProto* DescriptorProto::New(::google::protobuf::Arena* arena) const {
+ DescriptorProto* n = new DescriptorProto;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void DescriptorProto::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bits_[0 / 32] & 129) {
if (has_name()) {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_options()) {
if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear();
@@ -1841,126 +2666,142 @@ void DescriptorProto::Clear() {
nested_type_.Clear();
enum_type_.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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string name = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.DescriptorProto.name");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_field;
break;
}
-
+
// repeated .google.protobuf.FieldDescriptorProto field = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_field:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_field()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_field;
if (input->ExpectTag(26)) goto parse_nested_type;
break;
}
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 26) {
parse_nested_type:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_nested_type()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(26)) goto parse_nested_type;
if (input->ExpectTag(34)) goto parse_enum_type;
break;
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
case 4: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 34) {
parse_enum_type:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_enum_type()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(34)) goto parse_enum_type;
if (input->ExpectTag(42)) goto parse_extension_range;
break;
}
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
case 5: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 42) {
parse_extension_range:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_extension_range()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(42)) goto parse_extension_range;
if (input->ExpectTag(50)) goto parse_extension;
break;
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
case 6: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 50) {
parse_extension:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_extension()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(50)) goto parse_extension;
if (input->ExpectTag(58)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.MessageOptions options = 7;
case 7: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 58) {
parse_options:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, mutable_options()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(66)) goto parse_oneof_decl;
+ break;
+ }
+
+ // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+ case 8: {
+ if (tag == 66) {
+ parse_oneof_decl:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, add_oneof_decl()));
+ } else {
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectTag(66)) goto parse_oneof_decl;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -1968,142 +2809,166 @@ bool DescriptorProto::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.DescriptorProto)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.DescriptorProto)
+ return false;
#undef DO_
}
void DescriptorProto::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.DescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.DescriptorProto.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->name(), output);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto field = 2;
- for (int i = 0; i < this->field_size(); i++) {
+ for (unsigned int i = 0, n = this->field_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
2, this->field(i), output);
}
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
- for (int i = 0; i < this->nested_type_size(); i++) {
+ for (unsigned int i = 0, n = this->nested_type_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
3, this->nested_type(i), output);
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
- for (int i = 0; i < this->enum_type_size(); i++) {
+ for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
4, this->enum_type(i), output);
}
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
- for (int i = 0; i < this->extension_range_size(); i++) {
+ for (unsigned int i = 0, n = this->extension_range_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
5, this->extension_range(i), output);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
- for (int i = 0; i < this->extension_size(); i++) {
+ for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
6, this->extension(i), output);
}
-
+
// optional .google.protobuf.MessageOptions options = 7;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
- 7, this->options(), output);
+ 7, *this->options_, output);
}
-
- if (!unknown_fields().empty()) {
+
+ // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+ for (unsigned int i = 0, n = this->oneof_decl_size(); i < n; i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 8, this->oneof_decl(i), output);
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto)
}
::google::protobuf::uint8* DescriptorProto::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.DescriptorProto.name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto field = 2;
- for (int i = 0; i < this->field_size(); i++) {
+ for (unsigned int i = 0, n = this->field_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
2, this->field(i), target);
}
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
- for (int i = 0; i < this->nested_type_size(); i++) {
+ for (unsigned int i = 0, n = this->nested_type_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
3, this->nested_type(i), target);
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
- for (int i = 0; i < this->enum_type_size(); i++) {
+ for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
4, this->enum_type(i), target);
}
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
- for (int i = 0; i < this->extension_range_size(); i++) {
+ for (unsigned int i = 0, n = this->extension_range_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
5, this->extension_range(i), target);
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
- for (int i = 0; i < this->extension_size(); i++) {
+ for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
6, this->extension(i), target);
}
-
+
// optional .google.protobuf.MessageOptions options = 7;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
- 7, this->options(), target);
+ 7, *this->options_, target);
+ }
+
+ // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+ for (unsigned int i = 0, n = this->oneof_decl_size(); i < n; i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional .google.protobuf.MessageOptions options = 7;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
- this->options());
+ *this->options_);
}
-
+
}
// repeated .google.protobuf.FieldDescriptorProto field = 2;
total_size += 1 * this->field_size();
@@ -2112,7 +2977,7 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->field(i));
}
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
total_size += 1 * this->extension_size();
for (int i = 0; i < this->extension_size(); i++) {
@@ -2120,7 +2985,7 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->extension(i));
}
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
total_size += 1 * this->nested_type_size();
for (int i = 0; i < this->nested_type_size(); i++) {
@@ -2128,7 +2993,7 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->nested_type(i));
}
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
total_size += 1 * this->enum_type_size();
for (int i = 0; i < this->enum_type_size(); i++) {
@@ -2136,7 +3001,7 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->enum_type(i));
}
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
total_size += 1 * this->extension_range_size();
for (int i = 0; i < this->extension_range_size(); i++) {
@@ -2144,8 +3009,16 @@ int DescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->extension_range(i));
}
-
- if (!unknown_fields().empty()) {
+
+ // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+ total_size += 1 * this->oneof_decl_size();
+ for (int i = 0; i < this->oneof_decl_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->oneof_decl(i));
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -2157,7 +3030,7 @@ int DescriptorProto::ByteSize() const {
}
void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const DescriptorProto* source =
::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto*>(
&from);
@@ -2169,21 +3042,25 @@ void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
}
void DescriptorProto::MergeFrom(const DescriptorProto& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
field_.MergeFrom(from.field_);
extension_.MergeFrom(from.extension_);
nested_type_.MergeFrom(from.nested_type_);
enum_type_.MergeFrom(from.enum_type_);
extension_range_.MergeFrom(from.extension_range_);
+ oneof_decl_.MergeFrom(from.oneof_decl_);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_name()) {
- set_name(from.name());
+ set_has_name();
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
}
if (from.has_options()) {
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) {
@@ -2199,38 +3076,33 @@ void DescriptorProto::CopyFrom(const DescriptorProto& from) {
}
bool DescriptorProto::IsInitialized() const {
-
- for (int i = 0; i < field_size(); i++) {
- if (!this->field(i).IsInitialized()) return false;
- }
- for (int i = 0; i < extension_size(); i++) {
- if (!this->extension(i).IsInitialized()) return false;
- }
- for (int i = 0; i < nested_type_size(); i++) {
- if (!this->nested_type(i).IsInitialized()) return false;
- }
- for (int i = 0; i < enum_type_size(); i++) {
- if (!this->enum_type(i).IsInitialized()) return false;
- }
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->field())) return false;
+ if (!::google::protobuf::internal::AllAreInitialized(this->extension())) return false;
+ if (!::google::protobuf::internal::AllAreInitialized(this->nested_type())) return false;
+ if (!::google::protobuf::internal::AllAreInitialized(this->enum_type())) return false;
if (has_options()) {
- if (!this->options().IsInitialized()) return false;
+ if (!this->options_->IsInitialized()) return false;
}
return true;
}
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_);
- 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;
+ 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 {
@@ -2241,6 +3113,338 @@ void DescriptorProto::Swap(DescriptorProto* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// DescriptorProto_ExtensionRange
+
+// optional int32 start = 1;
+ bool DescriptorProto_ExtensionRange::has_start() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void DescriptorProto_ExtensionRange::set_has_start() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void DescriptorProto_ExtensionRange::clear_has_start() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void DescriptorProto_ExtensionRange::clear_start() {
+ start_ = 0;
+ clear_has_start();
+}
+ ::google::protobuf::int32 DescriptorProto_ExtensionRange::start() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.start)
+ return start_;
+}
+ void DescriptorProto_ExtensionRange::set_start(::google::protobuf::int32 value) {
+ set_has_start();
+ start_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.start)
+}
+
+// optional int32 end = 2;
+ bool DescriptorProto_ExtensionRange::has_end() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void DescriptorProto_ExtensionRange::set_has_end() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void DescriptorProto_ExtensionRange::clear_has_end() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void DescriptorProto_ExtensionRange::clear_end() {
+ end_ = 0;
+ clear_has_end();
+}
+ ::google::protobuf::int32 DescriptorProto_ExtensionRange::end() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.end)
+ return end_;
+}
+ void DescriptorProto_ExtensionRange::set_end(::google::protobuf::int32 value) {
+ set_has_end();
+ end_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.end)
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto
+
+// optional string name = 1;
+ bool DescriptorProto::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void DescriptorProto::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void DescriptorProto::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void DescriptorProto::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& DescriptorProto::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void DescriptorProto::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.name)
+}
+ void DescriptorProto::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.name)
+}
+ void DescriptorProto::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.name)
+}
+ ::std::string* DescriptorProto::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* DescriptorProto::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void DescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.name)
+}
+
+// repeated .google.protobuf.FieldDescriptorProto field = 2;
+ int DescriptorProto::field_size() const {
+ return field_.size();
+}
+ void DescriptorProto::clear_field() {
+ field_.Clear();
+}
+ const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.field)
+ return field_.Get(index);
+}
+ ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.field)
+ return field_.Mutable(index);
+}
+ ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.field)
+ return field_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+DescriptorProto::field() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field)
+ return field_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+DescriptorProto::mutable_field() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.field)
+ return &field_;
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 6;
+ int DescriptorProto::extension_size() const {
+ return extension_.size();
+}
+ void DescriptorProto::clear_extension() {
+ extension_.Clear();
+}
+ const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension)
+ return extension_.Get(index);
+}
+ ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension)
+ return extension_.Mutable(index);
+}
+ ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension)
+ return extension_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+DescriptorProto::extension() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension)
+ return extension_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+DescriptorProto::mutable_extension() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension)
+ return &extension_;
+}
+
+// repeated .google.protobuf.DescriptorProto nested_type = 3;
+ int DescriptorProto::nested_type_size() const {
+ return nested_type_.size();
+}
+ void DescriptorProto::clear_nested_type() {
+ nested_type_.Clear();
+}
+ const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.nested_type)
+ return nested_type_.Get(index);
+}
+ ::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.nested_type)
+ return nested_type_.Mutable(index);
+}
+ ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.nested_type)
+ return nested_type_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+DescriptorProto::nested_type() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type)
+ return nested_type_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+DescriptorProto::mutable_nested_type() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.nested_type)
+ return &nested_type_;
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+ int DescriptorProto::enum_type_size() const {
+ return enum_type_.size();
+}
+ void DescriptorProto::clear_enum_type() {
+ enum_type_.Clear();
+}
+ const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.enum_type)
+ return enum_type_.Get(index);
+}
+ ::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.enum_type)
+ return enum_type_.Mutable(index);
+}
+ ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.enum_type)
+ return enum_type_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+DescriptorProto::enum_type() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type)
+ return enum_type_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+DescriptorProto::mutable_enum_type() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.enum_type)
+ return &enum_type_;
+}
+
+// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+ int DescriptorProto::extension_range_size() const {
+ return extension_range_.size();
+}
+ void DescriptorProto::clear_extension_range() {
+ extension_range_.Clear();
+}
+ const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension_range)
+ return extension_range_.Get(index);
+}
+ ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension_range)
+ return extension_range_.Mutable(index);
+}
+ ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension_range)
+ return extension_range_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
+DescriptorProto::extension_range() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range)
+ return extension_range_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
+DescriptorProto::mutable_extension_range() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension_range)
+ return &extension_range_;
+}
+
+// repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+ int DescriptorProto::oneof_decl_size() const {
+ return oneof_decl_.size();
+}
+ void DescriptorProto::clear_oneof_decl() {
+ oneof_decl_.Clear();
+}
+ const ::google::protobuf::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.oneof_decl)
+ return oneof_decl_.Get(index);
+}
+ ::google::protobuf::OneofDescriptorProto* DescriptorProto::mutable_oneof_decl(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.oneof_decl)
+ return oneof_decl_.Mutable(index);
+}
+ ::google::protobuf::OneofDescriptorProto* DescriptorProto::add_oneof_decl() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.oneof_decl)
+ return oneof_decl_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
+DescriptorProto::oneof_decl() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl)
+ return oneof_decl_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >*
+DescriptorProto::mutable_oneof_decl() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.oneof_decl)
+ return &oneof_decl_;
+}
+
+// optional .google.protobuf.MessageOptions options = 7;
+ bool DescriptorProto::has_options() const {
+ return (_has_bits_[0] & 0x00000080u) != 0;
+}
+ void DescriptorProto::set_has_options() {
+ _has_bits_[0] |= 0x00000080u;
+}
+ void DescriptorProto::clear_has_options() {
+ _has_bits_[0] &= ~0x00000080u;
+}
+ void DescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear();
+ clear_has_options();
+}
+ const ::google::protobuf::MessageOptions& DescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.options)
+ return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+ ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() {
+ set_has_options();
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::MessageOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options)
+ return options_;
+}
+ ::google::protobuf::MessageOptions* DescriptorProto::release_options() {
+ clear_has_options();
+ ::google::protobuf::MessageOptions* temp = options_;
+ options_ = NULL;
+ return temp;
+}
+ void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -2328,12 +3532,14 @@ const int FieldDescriptorProto::kTypeFieldNumber;
const int FieldDescriptorProto::kTypeNameFieldNumber;
const int FieldDescriptorProto::kExtendeeFieldNumber;
const int FieldDescriptorProto::kDefaultValueFieldNumber;
+const int FieldDescriptorProto::kOneofIndexFieldNumber;
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)
}
void FieldDescriptorProto::InitAsDefaultInstance() {
@@ -2341,41 +3547,38 @@ void FieldDescriptorProto::InitAsDefaultInstance() {
}
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)
}
void FieldDescriptorProto::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
number_ = 0;
label_ = 1;
type_ = 1;
- type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ 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_));
}
FieldDescriptorProto::~FieldDescriptorProto() {
+ // @@protoc_insertion_point(destructor:google.protobuf.FieldDescriptorProto)
SharedDtor();
}
void FieldDescriptorProto::SharedDtor() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- delete name_;
- }
- if (type_name_ != &::google::protobuf::internal::kEmptyString) {
- delete type_name_;
- }
- if (extendee_ != &::google::protobuf::internal::kEmptyString) {
- delete extendee_;
- }
- if (default_value_ != &::google::protobuf::internal::kEmptyString) {
- delete default_value_;
- }
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ type_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ extendee_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
delete options_;
}
@@ -2392,107 +3595,109 @@ const ::google::protobuf::Descriptor* FieldDescriptorProto::descriptor() {
}
const FieldDescriptorProto& FieldDescriptorProto::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
FieldDescriptorProto* FieldDescriptorProto::default_instance_ = NULL;
-FieldDescriptorProto* FieldDescriptorProto::New() const {
- return new FieldDescriptorProto;
+FieldDescriptorProto* FieldDescriptorProto::New(::google::protobuf::Arena* arena) const {
+ FieldDescriptorProto* n = new FieldDescriptorProto;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void FieldDescriptorProto::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bits_[0 / 32] & 255) {
if (has_name()) {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
number_ = 0;
label_ = 1;
type_ = 1;
if (has_type_name()) {
- if (type_name_ != &::google::protobuf::internal::kEmptyString) {
- type_name_->clear();
- }
+ type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_extendee()) {
- if (extendee_ != &::google::protobuf::internal::kEmptyString) {
- extendee_->clear();
- }
+ extendee_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_default_value()) {
- if (default_value_ != &::google::protobuf::internal::kEmptyString) {
- default_value_->clear();
- }
- }
- if (has_options()) {
- if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
+ default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
+ oneof_index_ = 0;
+ }
+ if (has_options()) {
+ 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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.FieldDescriptorProto)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string name = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FieldDescriptorProto.name");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_extendee;
break;
}
-
+
// optional string extendee = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_extendee:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_extendee()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->extendee().data(), this->extendee().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FieldDescriptorProto.extendee");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(24)) goto parse_number;
break;
}
-
+
// optional int32 number = 3;
case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 24) {
parse_number:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
input, &number_)));
set_has_number();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(32)) goto parse_label;
break;
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
case 4: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 32) {
parse_label:
int value;
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
@@ -2504,16 +3709,15 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
mutable_unknown_fields()->AddVarint(4, value);
}
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(40)) goto parse_type;
break;
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
case 5: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 40) {
parse_type:
int value;
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
@@ -2525,65 +3729,80 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
mutable_unknown_fields()->AddVarint(5, value);
}
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(50)) goto parse_type_name;
break;
}
-
+
// optional string type_name = 6;
case 6: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 50) {
parse_type_name:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_type_name()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->type_name().data(), this->type_name().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FieldDescriptorProto.type_name");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(58)) goto parse_default_value;
break;
}
-
+
// optional string default_value = 7;
case 7: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 58) {
parse_default_value:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_default_value()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->default_value().data(), this->default_value().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FieldDescriptorProto.default_value");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(66)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.FieldOptions options = 8;
case 8: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 66) {
parse_options:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, mutable_options()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(72)) goto parse_oneof_index;
+ break;
+ }
+
+ // optional int32 oneof_index = 9;
+ case 9: {
+ if (tag == 72) {
+ parse_oneof_index:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &oneof_index_)));
+ set_has_oneof_index();
+ } else {
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -2591,210 +3810,244 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.FieldDescriptorProto)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.FieldDescriptorProto)
+ return false;
#undef DO_
}
void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.FieldDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FieldDescriptorProto.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->name(), output);
}
-
+
// optional string extendee = 2;
if (has_extendee()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->extendee().data(), this->extendee().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FieldDescriptorProto.extendee");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
2, this->extendee(), output);
}
-
+
// optional int32 number = 3;
if (has_number()) {
::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->number(), output);
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
if (has_label()) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
4, this->label(), output);
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
if (has_type()) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
5, this->type(), output);
}
-
+
// optional string type_name = 6;
if (has_type_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->type_name().data(), this->type_name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FieldDescriptorProto.type_name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
6, this->type_name(), output);
}
-
+
// optional string default_value = 7;
if (has_default_value()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->default_value().data(), this->default_value().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FieldDescriptorProto.default_value");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
7, this->default_value(), output);
}
-
+
// optional .google.protobuf.FieldOptions options = 8;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
- 8, this->options(), output);
+ 8, *this->options_, output);
}
-
- if (!unknown_fields().empty()) {
+
+ // optional int32 oneof_index = 9;
+ if (has_oneof_index()) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->oneof_index(), output);
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.FieldDescriptorProto)
}
::google::protobuf::uint8* FieldDescriptorProto::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FieldDescriptorProto.name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional string extendee = 2;
if (has_extendee()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->extendee().data(), this->extendee().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FieldDescriptorProto.extendee");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->extendee(), target);
}
-
+
// optional int32 number = 3;
if (has_number()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->number(), target);
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
if (has_label()) {
target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
4, this->label(), target);
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
if (has_type()) {
target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
5, this->type(), target);
}
-
+
// optional string type_name = 6;
if (has_type_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->type_name().data(), this->type_name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FieldDescriptorProto.type_name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
6, this->type_name(), target);
}
-
+
// optional string default_value = 7;
if (has_default_value()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->default_value().data(), this->default_value().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FieldDescriptorProto.default_value");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
7, this->default_value(), target);
}
-
+
// optional .google.protobuf.FieldOptions options = 8;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
- 8, this->options(), target);
+ 8, *this->options_, target);
+ }
+
+ // optional int32 oneof_index = 9;
+ if (has_oneof_index()) {
+ 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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldDescriptorProto)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional int32 number = 3;
if (has_number()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->number());
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
if (has_label()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::EnumSize(this->label());
}
-
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
if (has_type()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
}
-
+
// optional string type_name = 6;
if (has_type_name()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->type_name());
}
-
+
// optional string extendee = 2;
if (has_extendee()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->extendee());
}
-
+
// optional string default_value = 7;
if (has_default_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->default_value());
}
-
- // optional .google.protobuf.FieldOptions options = 8;
- if (has_options()) {
+
+ // optional int32 oneof_index = 9;
+ if (has_oneof_index()) {
total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
- this->options());
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->oneof_index());
}
-
+
+ }
+ // 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());
@@ -2806,7 +4059,7 @@ int FieldDescriptorProto::ByteSize() const {
}
void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const FieldDescriptorProto* source =
::google::protobuf::internal::dynamic_cast_if_available<const FieldDescriptorProto*>(
&from);
@@ -2818,10 +4071,11 @@ void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
}
void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_name()) {
- set_name(from.name());
+ set_has_name();
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
}
if (from.has_number()) {
set_number(from.number());
@@ -2833,19 +4087,29 @@ void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) {
set_type(from.type());
}
if (from.has_type_name()) {
- set_type_name(from.type_name());
+ set_has_type_name();
+ type_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_name_);
}
if (from.has_extendee()) {
- set_extendee(from.extendee());
+ set_has_extendee();
+ extendee_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.extendee_);
}
if (from.has_default_value()) {
- set_default_value(from.default_value());
+ set_has_default_value();
+ default_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.default_value_);
}
+ if (from.has_oneof_index()) {
+ set_oneof_index(from.oneof_index());
+ }
+ }
+ if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
if (from.has_options()) {
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) {
@@ -2861,27 +4125,30 @@ void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) {
}
bool FieldDescriptorProto::IsInitialized() const {
-
+
if (has_options()) {
- if (!this->options().IsInitialized()) return false;
+ if (!this->options_->IsInitialized()) return false;
}
return true;
}
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(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;
+ 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 {
@@ -2892,6 +4159,669 @@ void FieldDescriptorProto::Swap(FieldDescriptorProto* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FieldDescriptorProto
+
+// optional string name = 1;
+ bool FieldDescriptorProto::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void FieldDescriptorProto::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void FieldDescriptorProto::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void FieldDescriptorProto::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& FieldDescriptorProto::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.name)
+}
+ void FieldDescriptorProto::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.name)
+}
+ void FieldDescriptorProto::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.name)
+}
+ ::std::string* FieldDescriptorProto::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.name)
+}
+
+// optional int32 number = 3;
+ bool FieldDescriptorProto::has_number() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void FieldDescriptorProto::set_has_number() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void FieldDescriptorProto::clear_has_number() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void FieldDescriptorProto::clear_number() {
+ number_ = 0;
+ clear_has_number();
+}
+ ::google::protobuf::int32 FieldDescriptorProto::number() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.number)
+ return number_;
+}
+ void FieldDescriptorProto::set_number(::google::protobuf::int32 value) {
+ set_has_number();
+ number_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.number)
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+ bool FieldDescriptorProto::has_label() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void FieldDescriptorProto::set_has_label() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void FieldDescriptorProto::clear_has_label() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void FieldDescriptorProto::clear_label() {
+ label_ = 1;
+ clear_has_label();
+}
+ ::google::protobuf::FieldDescriptorProto_Label FieldDescriptorProto::label() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.label)
+ return static_cast< ::google::protobuf::FieldDescriptorProto_Label >(label_);
+}
+ void FieldDescriptorProto::set_label(::google::protobuf::FieldDescriptorProto_Label value) {
+ assert(::google::protobuf::FieldDescriptorProto_Label_IsValid(value));
+ set_has_label();
+ label_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.label)
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+ bool FieldDescriptorProto::has_type() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+ void FieldDescriptorProto::set_has_type() {
+ _has_bits_[0] |= 0x00000008u;
+}
+ void FieldDescriptorProto::clear_has_type() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+ void FieldDescriptorProto::clear_type() {
+ type_ = 1;
+ clear_has_type();
+}
+ ::google::protobuf::FieldDescriptorProto_Type FieldDescriptorProto::type() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type)
+ return static_cast< ::google::protobuf::FieldDescriptorProto_Type >(type_);
+}
+ void FieldDescriptorProto::set_type(::google::protobuf::FieldDescriptorProto_Type value) {
+ assert(::google::protobuf::FieldDescriptorProto_Type_IsValid(value));
+ set_has_type();
+ type_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type)
+}
+
+// optional string type_name = 6;
+ bool FieldDescriptorProto::has_type_name() const {
+ return (_has_bits_[0] & 0x00000010u) != 0;
+}
+ void FieldDescriptorProto::set_has_type_name() {
+ _has_bits_[0] |= 0x00000010u;
+}
+ void FieldDescriptorProto::clear_has_type_name() {
+ _has_bits_[0] &= ~0x00000010u;
+}
+ void FieldDescriptorProto::clear_type_name() {
+ type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_type_name();
+}
+ const ::std::string& FieldDescriptorProto::type_name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type_name)
+ return type_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_type_name(const ::std::string& value) {
+ set_has_type_name();
+ type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type_name)
+}
+ void FieldDescriptorProto::set_type_name(const char* value) {
+ set_has_type_name();
+ type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.type_name)
+}
+ void FieldDescriptorProto::set_type_name(const char* value, size_t size) {
+ set_has_type_name();
+ type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.type_name)
+}
+ ::std::string* FieldDescriptorProto::mutable_type_name() {
+ set_has_type_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.type_name)
+ return type_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_type_name() {
+ clear_has_type_name();
+ return type_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_type_name(::std::string* type_name) {
+ if (type_name != NULL) {
+ set_has_type_name();
+ } else {
+ clear_has_type_name();
+ }
+ type_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.type_name)
+}
+
+// optional string extendee = 2;
+ bool FieldDescriptorProto::has_extendee() const {
+ return (_has_bits_[0] & 0x00000020u) != 0;
+}
+ void FieldDescriptorProto::set_has_extendee() {
+ _has_bits_[0] |= 0x00000020u;
+}
+ void FieldDescriptorProto::clear_has_extendee() {
+ _has_bits_[0] &= ~0x00000020u;
+}
+ void FieldDescriptorProto::clear_extendee() {
+ extendee_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_extendee();
+}
+ const ::std::string& FieldDescriptorProto::extendee() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.extendee)
+ return extendee_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_extendee(const ::std::string& value) {
+ set_has_extendee();
+ extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.extendee)
+}
+ void FieldDescriptorProto::set_extendee(const char* value) {
+ set_has_extendee();
+ extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.extendee)
+}
+ void FieldDescriptorProto::set_extendee(const char* value, size_t size) {
+ set_has_extendee();
+ extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.extendee)
+}
+ ::std::string* FieldDescriptorProto::mutable_extendee() {
+ set_has_extendee();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.extendee)
+ return extendee_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_extendee() {
+ clear_has_extendee();
+ return extendee_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_extendee(::std::string* extendee) {
+ if (extendee != NULL) {
+ set_has_extendee();
+ } else {
+ clear_has_extendee();
+ }
+ extendee_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), extendee);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.extendee)
+}
+
+// optional string default_value = 7;
+ bool FieldDescriptorProto::has_default_value() const {
+ return (_has_bits_[0] & 0x00000040u) != 0;
+}
+ void FieldDescriptorProto::set_has_default_value() {
+ _has_bits_[0] |= 0x00000040u;
+}
+ void FieldDescriptorProto::clear_has_default_value() {
+ _has_bits_[0] &= ~0x00000040u;
+}
+ void FieldDescriptorProto::clear_default_value() {
+ default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_default_value();
+}
+ const ::std::string& FieldDescriptorProto::default_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.default_value)
+ return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_default_value(const ::std::string& value) {
+ set_has_default_value();
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.default_value)
+}
+ void FieldDescriptorProto::set_default_value(const char* value) {
+ set_has_default_value();
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.default_value)
+}
+ void FieldDescriptorProto::set_default_value(const char* value, size_t size) {
+ set_has_default_value();
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.default_value)
+}
+ ::std::string* FieldDescriptorProto::mutable_default_value() {
+ set_has_default_value();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.default_value)
+ return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_default_value() {
+ clear_has_default_value();
+ return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_default_value(::std::string* default_value) {
+ if (default_value != NULL) {
+ set_has_default_value();
+ } else {
+ clear_has_default_value();
+ }
+ default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.default_value)
+}
+
+// optional int32 oneof_index = 9;
+ bool FieldDescriptorProto::has_oneof_index() const {
+ return (_has_bits_[0] & 0x00000080u) != 0;
+}
+ void FieldDescriptorProto::set_has_oneof_index() {
+ _has_bits_[0] |= 0x00000080u;
+}
+ void FieldDescriptorProto::clear_has_oneof_index() {
+ _has_bits_[0] &= ~0x00000080u;
+}
+ void FieldDescriptorProto::clear_oneof_index() {
+ oneof_index_ = 0;
+ clear_has_oneof_index();
+}
+ ::google::protobuf::int32 FieldDescriptorProto::oneof_index() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.oneof_index)
+ return oneof_index_;
+}
+ void FieldDescriptorProto::set_oneof_index(::google::protobuf::int32 value) {
+ set_has_oneof_index();
+ oneof_index_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
+}
+
+// optional .google.protobuf.FieldOptions options = 8;
+ bool FieldDescriptorProto::has_options() const {
+ return (_has_bits_[0] & 0x00000100u) != 0;
+}
+ void FieldDescriptorProto::set_has_options() {
+ _has_bits_[0] |= 0x00000100u;
+}
+ void FieldDescriptorProto::clear_has_options() {
+ _has_bits_[0] &= ~0x00000100u;
+}
+ void FieldDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
+ clear_has_options();
+}
+ const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.options)
+ return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+ ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() {
+ set_has_options();
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::FieldOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options)
+ return options_;
+}
+ ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() {
+ clear_has_options();
+ ::google::protobuf::FieldOptions* temp = options_;
+ options_ = NULL;
+ return temp;
+}
+ void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.options)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#ifndef _MSC_VER
+const int OneofDescriptorProto::kNameFieldNumber;
+#endif // !_MSC_VER
+
+OneofDescriptorProto::OneofDescriptorProto()
+ : ::google::protobuf::Message() , _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:google.protobuf.OneofDescriptorProto)
+}
+
+void OneofDescriptorProto::InitAsDefaultInstance() {
+}
+
+OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:google.protobuf.OneofDescriptorProto)
+}
+
+void OneofDescriptorProto::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+OneofDescriptorProto::~OneofDescriptorProto() {
+ // @@protoc_insertion_point(destructor:google.protobuf.OneofDescriptorProto)
+ SharedDtor();
+}
+
+void OneofDescriptorProto::SharedDtor() {
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (this != default_instance_) {
+ }
+}
+
+void OneofDescriptorProto::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* OneofDescriptorProto::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return OneofDescriptorProto_descriptor_;
+}
+
+const OneofDescriptorProto& OneofDescriptorProto::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
+}
+
+OneofDescriptorProto* OneofDescriptorProto::default_instance_ = NULL;
+
+OneofDescriptorProto* OneofDescriptorProto::New(::google::protobuf::Arena* arena) const {
+ OneofDescriptorProto* n = new OneofDescriptorProto;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void OneofDescriptorProto::Clear() {
+ if (has_name()) {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (_internal_metadata_.have_unknown_fields()) {
+ mutable_unknown_fields()->Clear();
+ }
+}
+
+bool OneofDescriptorProto::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:google.protobuf.OneofDescriptorProto)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string name = 1;
+ case 1: {
+ if (tag == 10) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_name()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->name().data(), this->name().length(),
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.OneofDescriptorProto.name");
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.OneofDescriptorProto)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.OneofDescriptorProto)
+ return false;
+#undef DO_
+}
+
+void OneofDescriptorProto::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.OneofDescriptorProto)
+ // optional string name = 1;
+ if (has_name()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->name().data(), this->name().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.OneofDescriptorProto.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 1, this->name(), output);
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+ // @@protoc_insertion_point(serialize_end:google.protobuf.OneofDescriptorProto)
+}
+
+::google::protobuf::uint8* OneofDescriptorProto::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofDescriptorProto)
+ // optional string name = 1;
+ if (has_name()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->name().data(), this->name().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.OneofDescriptorProto.name");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 1, this->name(), target);
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofDescriptorProto)
+ return target;
+}
+
+int OneofDescriptorProto::ByteSize() const {
+ int total_size = 0;
+
+ // optional string name = 1;
+ if (has_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->name());
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void OneofDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const OneofDescriptorProto* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const OneofDescriptorProto*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void OneofDescriptorProto::MergeFrom(const OneofDescriptorProto& from) {
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_name()) {
+ set_has_name();
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+ }
+ }
+ if (from._internal_metadata_.have_unknown_fields()) {
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+ }
+}
+
+void OneofDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void OneofDescriptorProto::CopyFrom(const OneofDescriptorProto& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool OneofDescriptorProto::IsInitialized() const {
+
+ return true;
+}
+
+void OneofDescriptorProto::Swap(OneofDescriptorProto* other) {
+ if (other == this) return;
+ 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();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = OneofDescriptorProto_descriptor_;
+ metadata.reflection = OneofDescriptorProto_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// OneofDescriptorProto
+
+// optional string name = 1;
+ bool OneofDescriptorProto::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void OneofDescriptorProto::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void OneofDescriptorProto::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void OneofDescriptorProto::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& OneofDescriptorProto::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void OneofDescriptorProto::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.OneofDescriptorProto.name)
+}
+ void OneofDescriptorProto::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.OneofDescriptorProto.name)
+}
+ void OneofDescriptorProto::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.OneofDescriptorProto.name)
+}
+ ::std::string* OneofDescriptorProto::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* OneofDescriptorProto::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void OneofDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -2902,8 +4832,9 @@ 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)
}
void EnumDescriptorProto::InitAsDefaultInstance() {
@@ -2911,26 +4842,28 @@ void EnumDescriptorProto::InitAsDefaultInstance() {
}
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)
}
void EnumDescriptorProto::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
options_ = NULL;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
EnumDescriptorProto::~EnumDescriptorProto() {
+ // @@protoc_insertion_point(destructor:google.protobuf.EnumDescriptorProto)
SharedDtor();
}
void EnumDescriptorProto::SharedDtor() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- delete name_;
- }
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
delete options_;
}
@@ -2947,21 +4880,24 @@ const ::google::protobuf::Descriptor* EnumDescriptorProto::descriptor() {
}
const EnumDescriptorProto& EnumDescriptorProto::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
EnumDescriptorProto* EnumDescriptorProto::default_instance_ = NULL;
-EnumDescriptorProto* EnumDescriptorProto::New() const {
- return new EnumDescriptorProto;
+EnumDescriptorProto* EnumDescriptorProto::New(::google::protobuf::Arena* arena) const {
+ EnumDescriptorProto* n = new EnumDescriptorProto;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void EnumDescriptorProto::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bits_[0 / 32] & 5) {
if (has_name()) {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_options()) {
if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear();
@@ -2969,65 +4905,70 @@ 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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.EnumDescriptorProto)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string name = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.EnumDescriptorProto.name");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_value;
break;
}
-
+
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_value:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_value()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_value;
if (input->ExpectTag(26)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.EnumOptions options = 3;
case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 26) {
parse_options:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, mutable_options()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -3035,90 +4976,101 @@ bool EnumDescriptorProto::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.EnumDescriptorProto)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.EnumDescriptorProto)
+ return false;
#undef DO_
}
void EnumDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.EnumDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.EnumDescriptorProto.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->name(), output);
}
-
+
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
- for (int i = 0; i < this->value_size(); i++) {
+ for (unsigned int i = 0, n = this->value_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
2, this->value(i), output);
}
-
+
// optional .google.protobuf.EnumOptions options = 3;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
- 3, this->options(), output);
+ 3, *this->options_, output);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.EnumDescriptorProto)
}
::google::protobuf::uint8* EnumDescriptorProto::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.EnumDescriptorProto.name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
- for (int i = 0; i < this->value_size(); i++) {
+ for (unsigned int i = 0, n = this->value_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
2, this->value(i), target);
}
-
+
// optional .google.protobuf.EnumOptions options = 3;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
- 3, this->options(), target);
+ 3, *this->options_, target);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumDescriptorProto)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional .google.protobuf.EnumOptions options = 3;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
- this->options());
+ *this->options_);
}
-
+
}
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
total_size += 1 * this->value_size();
@@ -3127,8 +5079,8 @@ int EnumDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->value(i));
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -3140,7 +5092,7 @@ int EnumDescriptorProto::ByteSize() const {
}
void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const EnumDescriptorProto* source =
::google::protobuf::internal::dynamic_cast_if_available<const EnumDescriptorProto*>(
&from);
@@ -3152,17 +5104,20 @@ void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
}
void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
value_.MergeFrom(from.value_);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_name()) {
- set_name(from.name());
+ set_has_name();
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
}
if (from.has_options()) {
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) {
@@ -3178,25 +5133,25 @@ void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) {
}
bool EnumDescriptorProto::IsInitialized() const {
-
- for (int i = 0; i < value_size(); i++) {
- if (!this->value(i).IsInitialized()) return false;
- }
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->value())) return false;
if (has_options()) {
- if (!this->options().IsInitialized()) return false;
+ if (!this->options_->IsInitialized()) return false;
}
return true;
}
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;
+ 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 {
@@ -3207,6 +5162,136 @@ void EnumDescriptorProto::Swap(EnumDescriptorProto* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EnumDescriptorProto
+
+// optional string name = 1;
+ bool EnumDescriptorProto::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void EnumDescriptorProto::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void EnumDescriptorProto::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void EnumDescriptorProto::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& EnumDescriptorProto::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumDescriptorProto::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.name)
+}
+ void EnumDescriptorProto::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.EnumDescriptorProto.name)
+}
+ void EnumDescriptorProto::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumDescriptorProto.name)
+}
+ ::std::string* EnumDescriptorProto::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* EnumDescriptorProto::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.name)
+}
+
+// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+ int EnumDescriptorProto::value_size() const {
+ return value_.size();
+}
+ void EnumDescriptorProto::clear_value() {
+ value_.Clear();
+}
+ const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.value)
+ return value_.Get(index);
+}
+ ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.value)
+ return value_.Mutable(index);
+}
+ ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() {
+ // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.value)
+ return value_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
+EnumDescriptorProto::value() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value)
+ return value_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
+EnumDescriptorProto::mutable_value() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.value)
+ return &value_;
+}
+
+// optional .google.protobuf.EnumOptions options = 3;
+ bool EnumDescriptorProto::has_options() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void EnumDescriptorProto::set_has_options() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void EnumDescriptorProto::clear_has_options() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void EnumDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear();
+ clear_has_options();
+}
+ const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.options)
+ return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+ ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() {
+ set_has_options();
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::EnumOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options)
+ return options_;
+}
+ ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() {
+ clear_has_options();
+ ::google::protobuf::EnumOptions* temp = options_;
+ options_ = NULL;
+ return temp;
+}
+ void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.options)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -3217,8 +5302,9 @@ 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)
}
void EnumValueDescriptorProto::InitAsDefaultInstance() {
@@ -3226,27 +5312,29 @@ void EnumValueDescriptorProto::InitAsDefaultInstance() {
}
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)
}
void EnumValueDescriptorProto::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
number_ = 0;
options_ = NULL;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
EnumValueDescriptorProto::~EnumValueDescriptorProto() {
+ // @@protoc_insertion_point(destructor:google.protobuf.EnumValueDescriptorProto)
SharedDtor();
}
void EnumValueDescriptorProto::SharedDtor() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- delete name_;
- }
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
delete options_;
}
@@ -3263,21 +5351,24 @@ const ::google::protobuf::Descriptor* EnumValueDescriptorProto::descriptor() {
}
const EnumValueDescriptorProto& EnumValueDescriptorProto::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
EnumValueDescriptorProto* EnumValueDescriptorProto::default_instance_ = NULL;
-EnumValueDescriptorProto* EnumValueDescriptorProto::New() const {
- return new EnumValueDescriptorProto;
+EnumValueDescriptorProto* EnumValueDescriptorProto::New(::google::protobuf::Arena* arena) const {
+ EnumValueDescriptorProto* n = new EnumValueDescriptorProto;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void EnumValueDescriptorProto::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bits_[0 / 32] & 7) {
if (has_name()) {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
number_ = 0;
if (has_options()) {
@@ -3285,66 +5376,71 @@ 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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.EnumValueDescriptorProto)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string name = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.EnumValueDescriptorProto.name");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(16)) goto parse_number;
break;
}
-
+
// optional int32 number = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 16) {
parse_number:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
input, &number_)));
set_has_number();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(26)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.EnumValueOptions options = 3;
case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 26) {
parse_options:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, mutable_options()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -3352,96 +5448,107 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.EnumValueDescriptorProto)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.EnumValueDescriptorProto)
+ return false;
#undef DO_
}
void EnumValueDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.EnumValueDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.EnumValueDescriptorProto.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->name(), output);
}
-
+
// optional int32 number = 2;
if (has_number()) {
::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->number(), output);
}
-
+
// optional .google.protobuf.EnumValueOptions options = 3;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
- 3, this->options(), output);
+ 3, *this->options_, output);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.EnumValueDescriptorProto)
}
::google::protobuf::uint8* EnumValueDescriptorProto::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.EnumValueDescriptorProto.name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional int32 number = 2;
if (has_number()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->number(), target);
}
-
+
// optional .google.protobuf.EnumValueOptions options = 3;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
- 3, this->options(), target);
+ 3, *this->options_, target);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueDescriptorProto)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional int32 number = 2;
if (has_number()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->number());
}
-
+
// optional .google.protobuf.EnumValueOptions options = 3;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
- this->options());
+ *this->options_);
}
-
+
}
- if (!unknown_fields().empty()) {
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -3453,7 +5560,7 @@ int EnumValueDescriptorProto::ByteSize() const {
}
void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const EnumValueDescriptorProto* source =
::google::protobuf::internal::dynamic_cast_if_available<const EnumValueDescriptorProto*>(
&from);
@@ -3465,10 +5572,11 @@ void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from
}
void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_name()) {
- set_name(from.name());
+ set_has_name();
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
}
if (from.has_number()) {
set_number(from.number());
@@ -3477,7 +5585,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) {
@@ -3493,22 +5603,24 @@ void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) {
}
bool EnumValueDescriptorProto::IsInitialized() const {
-
+
if (has_options()) {
- if (!this->options().IsInitialized()) return false;
+ if (!this->options_->IsInitialized()) return false;
}
return true;
}
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;
+ 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 {
@@ -3519,6 +5631,130 @@ void EnumValueDescriptorProto::Swap(EnumValueDescriptorProto* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EnumValueDescriptorProto
+
+// optional string name = 1;
+ bool EnumValueDescriptorProto::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void EnumValueDescriptorProto::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void EnumValueDescriptorProto::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void EnumValueDescriptorProto::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& EnumValueDescriptorProto::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumValueDescriptorProto::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.name)
+}
+ void EnumValueDescriptorProto::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.EnumValueDescriptorProto.name)
+}
+ void EnumValueDescriptorProto::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumValueDescriptorProto.name)
+}
+ ::std::string* EnumValueDescriptorProto::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* EnumValueDescriptorProto::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumValueDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.name)
+}
+
+// optional int32 number = 2;
+ bool EnumValueDescriptorProto::has_number() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void EnumValueDescriptorProto::set_has_number() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void EnumValueDescriptorProto::clear_has_number() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void EnumValueDescriptorProto::clear_number() {
+ number_ = 0;
+ clear_has_number();
+}
+ ::google::protobuf::int32 EnumValueDescriptorProto::number() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.number)
+ return number_;
+}
+ void EnumValueDescriptorProto::set_number(::google::protobuf::int32 value) {
+ set_has_number();
+ number_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.number)
+}
+
+// optional .google.protobuf.EnumValueOptions options = 3;
+ bool EnumValueDescriptorProto::has_options() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void EnumValueDescriptorProto::set_has_options() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void EnumValueDescriptorProto::clear_has_options() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void EnumValueDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear();
+ clear_has_options();
+}
+ const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.options)
+ return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+ ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() {
+ set_has_options();
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::EnumValueOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options)
+ return options_;
+}
+ ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() {
+ clear_has_options();
+ ::google::protobuf::EnumValueOptions* temp = options_;
+ options_ = NULL;
+ return temp;
+}
+ void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.options)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -3529,8 +5765,9 @@ 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)
}
void ServiceDescriptorProto::InitAsDefaultInstance() {
@@ -3538,26 +5775,28 @@ void ServiceDescriptorProto::InitAsDefaultInstance() {
}
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)
}
void ServiceDescriptorProto::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
options_ = NULL;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
ServiceDescriptorProto::~ServiceDescriptorProto() {
+ // @@protoc_insertion_point(destructor:google.protobuf.ServiceDescriptorProto)
SharedDtor();
}
void ServiceDescriptorProto::SharedDtor() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- delete name_;
- }
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
delete options_;
}
@@ -3574,21 +5813,24 @@ const ::google::protobuf::Descriptor* ServiceDescriptorProto::descriptor() {
}
const ServiceDescriptorProto& ServiceDescriptorProto::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
ServiceDescriptorProto* ServiceDescriptorProto::default_instance_ = NULL;
-ServiceDescriptorProto* ServiceDescriptorProto::New() const {
- return new ServiceDescriptorProto;
+ServiceDescriptorProto* ServiceDescriptorProto::New(::google::protobuf::Arena* arena) const {
+ ServiceDescriptorProto* n = new ServiceDescriptorProto;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void ServiceDescriptorProto::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bits_[0 / 32] & 5) {
if (has_name()) {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_options()) {
if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear();
@@ -3596,65 +5838,70 @@ 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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.ServiceDescriptorProto)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string name = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.ServiceDescriptorProto.name");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_method;
break;
}
-
+
// repeated .google.protobuf.MethodDescriptorProto method = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_method:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_method()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_method;
if (input->ExpectTag(26)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.ServiceOptions options = 3;
case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 26) {
parse_options:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, mutable_options()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -3662,90 +5909,101 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.ServiceDescriptorProto)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.ServiceDescriptorProto)
+ return false;
#undef DO_
}
void ServiceDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.ServiceDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.ServiceDescriptorProto.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->name(), output);
}
-
+
// repeated .google.protobuf.MethodDescriptorProto method = 2;
- for (int i = 0; i < this->method_size(); i++) {
+ for (unsigned int i = 0, n = this->method_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
2, this->method(i), output);
}
-
+
// optional .google.protobuf.ServiceOptions options = 3;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
- 3, this->options(), output);
+ 3, *this->options_, output);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.ServiceDescriptorProto)
}
::google::protobuf::uint8* ServiceDescriptorProto::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.ServiceDescriptorProto.name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// repeated .google.protobuf.MethodDescriptorProto method = 2;
- for (int i = 0; i < this->method_size(); i++) {
+ for (unsigned int i = 0, n = this->method_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
2, this->method(i), target);
}
-
+
// optional .google.protobuf.ServiceOptions options = 3;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
- 3, this->options(), target);
+ 3, *this->options_, target);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceDescriptorProto)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional .google.protobuf.ServiceOptions options = 3;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
- this->options());
+ *this->options_);
}
-
+
}
// repeated .google.protobuf.MethodDescriptorProto method = 2;
total_size += 1 * this->method_size();
@@ -3754,8 +6012,8 @@ int ServiceDescriptorProto::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->method(i));
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -3767,7 +6025,7 @@ int ServiceDescriptorProto::ByteSize() const {
}
void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const ServiceDescriptorProto* source =
::google::protobuf::internal::dynamic_cast_if_available<const ServiceDescriptorProto*>(
&from);
@@ -3779,17 +6037,20 @@ void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from)
}
void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
method_.MergeFrom(from.method_);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_name()) {
- set_name(from.name());
+ set_has_name();
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
}
if (from.has_options()) {
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) {
@@ -3805,25 +6066,25 @@ void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) {
}
bool ServiceDescriptorProto::IsInitialized() const {
-
- for (int i = 0; i < method_size(); i++) {
- if (!this->method(i).IsInitialized()) return false;
- }
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->method())) return false;
if (has_options()) {
- if (!this->options().IsInitialized()) return false;
+ if (!this->options_->IsInitialized()) return false;
}
return true;
}
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;
+ 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 {
@@ -3834,6 +6095,136 @@ void ServiceDescriptorProto::Swap(ServiceDescriptorProto* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ServiceDescriptorProto
+
+// optional string name = 1;
+ bool ServiceDescriptorProto::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void ServiceDescriptorProto::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void ServiceDescriptorProto::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void ServiceDescriptorProto::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& ServiceDescriptorProto::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServiceDescriptorProto::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.ServiceDescriptorProto.name)
+}
+ void ServiceDescriptorProto::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.ServiceDescriptorProto.name)
+}
+ void ServiceDescriptorProto::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.ServiceDescriptorProto.name)
+}
+ ::std::string* ServiceDescriptorProto::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ServiceDescriptorProto::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServiceDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.name)
+}
+
+// repeated .google.protobuf.MethodDescriptorProto method = 2;
+ int ServiceDescriptorProto::method_size() const {
+ return method_.size();
+}
+ void ServiceDescriptorProto::clear_method() {
+ method_.Clear();
+}
+ const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.method)
+ return method_.Get(index);
+}
+ ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.method)
+ return method_.Mutable(index);
+}
+ ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() {
+ // @@protoc_insertion_point(field_add:google.protobuf.ServiceDescriptorProto.method)
+ return method_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
+ServiceDescriptorProto::method() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method)
+ return method_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
+ServiceDescriptorProto::mutable_method() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceDescriptorProto.method)
+ return &method_;
+}
+
+// optional .google.protobuf.ServiceOptions options = 3;
+ bool ServiceDescriptorProto::has_options() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void ServiceDescriptorProto::set_has_options() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void ServiceDescriptorProto::clear_has_options() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void ServiceDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear();
+ clear_has_options();
+}
+ const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.options)
+ return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+ ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() {
+ set_has_options();
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::ServiceOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options)
+ return options_;
+}
+ ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() {
+ clear_has_options();
+ ::google::protobuf::ServiceOptions* temp = options_;
+ options_ = NULL;
+ return temp;
+}
+ void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.options)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -3842,11 +6233,14 @@ const int MethodDescriptorProto::kNameFieldNumber;
const int MethodDescriptorProto::kInputTypeFieldNumber;
const int MethodDescriptorProto::kOutputTypeFieldNumber;
const int MethodDescriptorProto::kOptionsFieldNumber;
+const int MethodDescriptorProto::kClientStreamingFieldNumber;
+const int MethodDescriptorProto::kServerStreamingFieldNumber;
#endif // !_MSC_VER
MethodDescriptorProto::MethodDescriptorProto()
- : ::google::protobuf::Message() {
+ : ::google::protobuf::Message() , _internal_metadata_(NULL) {
SharedCtor();
+ // @@protoc_insertion_point(constructor:google.protobuf.MethodDescriptorProto)
}
void MethodDescriptorProto::InitAsDefaultInstance() {
@@ -3854,34 +6248,34 @@ void MethodDescriptorProto::InitAsDefaultInstance() {
}
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)
}
void MethodDescriptorProto::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ input_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ output_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
options_ = NULL;
+ client_streaming_ = false;
+ server_streaming_ = false;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
MethodDescriptorProto::~MethodDescriptorProto() {
+ // @@protoc_insertion_point(destructor:google.protobuf.MethodDescriptorProto)
SharedDtor();
}
void MethodDescriptorProto::SharedDtor() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- delete name_;
- }
- if (input_type_ != &::google::protobuf::internal::kEmptyString) {
- delete input_type_;
- }
- if (output_type_ != &::google::protobuf::internal::kEmptyString) {
- delete output_type_;
- }
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ input_type_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ output_type_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
delete options_;
}
@@ -3898,115 +6292,163 @@ const ::google::protobuf::Descriptor* MethodDescriptorProto::descriptor() {
}
const MethodDescriptorProto& MethodDescriptorProto::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
MethodDescriptorProto* MethodDescriptorProto::default_instance_ = NULL;
-MethodDescriptorProto* MethodDescriptorProto::New() const {
- return new MethodDescriptorProto;
+MethodDescriptorProto* MethodDescriptorProto::New(::google::protobuf::Arena* arena) const {
+ MethodDescriptorProto* n = new MethodDescriptorProto;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void MethodDescriptorProto::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+ &reinterpret_cast<MethodDescriptorProto*>(16)->f)
+
+#define ZR_(first, last) do {\
+ ::memset(&first, 0,\
+ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+ if (_has_bits_[0 / 32] & 63) {
+ ZR_(client_streaming_, server_streaming_);
if (has_name()) {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_input_type()) {
- if (input_type_ != &::google::protobuf::internal::kEmptyString) {
- input_type_->clear();
- }
+ input_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_output_type()) {
- if (output_type_ != &::google::protobuf::internal::kEmptyString) {
- output_type_->clear();
- }
+ output_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_options()) {
if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear();
}
}
+
+#undef ZR_HELPER_
+#undef ZR_
+
::memset(_has_bits_, 0, sizeof(_has_bits_));
- mutable_unknown_fields()->Clear();
+ if (_internal_metadata_.have_unknown_fields()) {
+ mutable_unknown_fields()->Clear();
+ }
}
bool MethodDescriptorProto::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.MethodDescriptorProto)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string name = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.MethodDescriptorProto.name");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_input_type;
break;
}
-
+
// optional string input_type = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_input_type:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_input_type()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->input_type().data(), this->input_type().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.MethodDescriptorProto.input_type");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(26)) goto parse_output_type;
break;
}
-
+
// optional string output_type = 3;
case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 26) {
parse_output_type:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_output_type()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->output_type().data(), this->output_type().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.MethodDescriptorProto.output_type");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(34)) goto parse_options;
break;
}
-
+
// optional .google.protobuf.MethodOptions options = 4;
case 4: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 34) {
parse_options:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, mutable_options()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(40)) goto parse_client_streaming;
+ break;
+ }
+
+ // optional bool client_streaming = 5 [default = false];
+ case 5: {
+ if (tag == 40) {
+ parse_client_streaming:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &client_streaming_)));
+ set_has_client_streaming();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(48)) goto parse_server_streaming;
+ break;
+ }
+
+ // optional bool server_streaming = 6 [default = false];
+ case 6: {
+ if (tag == 48) {
+ parse_server_streaming:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &server_streaming_)));
+ set_has_server_streaming();
+ } else {
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -4014,131 +6456,176 @@ bool MethodDescriptorProto::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.MethodDescriptorProto)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.MethodDescriptorProto)
+ return false;
#undef DO_
}
void MethodDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.MethodDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.MethodDescriptorProto.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->name(), output);
}
-
+
// optional string input_type = 2;
if (has_input_type()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->input_type().data(), this->input_type().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.MethodDescriptorProto.input_type");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
2, this->input_type(), output);
}
-
+
// optional string output_type = 3;
if (has_output_type()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->output_type().data(), this->output_type().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.MethodDescriptorProto.output_type");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
3, this->output_type(), output);
}
-
+
// optional .google.protobuf.MethodOptions options = 4;
if (has_options()) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
- 4, this->options(), output);
+ 4, *this->options_, output);
+ }
+
+ // optional bool client_streaming = 5 [default = false];
+ if (has_client_streaming()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->client_streaming(), output);
}
-
- if (!unknown_fields().empty()) {
+
+ // optional bool server_streaming = 6 [default = false];
+ if (has_server_streaming()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(6, this->server_streaming(), output);
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.MethodDescriptorProto)
}
::google::protobuf::uint8* MethodDescriptorProto::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodDescriptorProto)
// optional string name = 1;
if (has_name()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.MethodDescriptorProto.name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name(), target);
}
-
+
// optional string input_type = 2;
if (has_input_type()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->input_type().data(), this->input_type().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.MethodDescriptorProto.input_type");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->input_type(), target);
}
-
+
// optional string output_type = 3;
if (has_output_type()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->output_type().data(), this->output_type().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.MethodDescriptorProto.output_type");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
3, this->output_type(), target);
}
-
+
// optional .google.protobuf.MethodOptions options = 4;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
- 4, this->options(), target);
+ 4, *this->options_, target);
+ }
+
+ // optional bool client_streaming = 5 [default = false];
+ if (has_client_streaming()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->client_streaming(), target);
+ }
+
+ // optional bool server_streaming = 6 [default = false];
+ if (has_server_streaming()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(6, this->server_streaming(), target);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodDescriptorProto)
return target;
}
int MethodDescriptorProto::ByteSize() const {
int total_size = 0;
-
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+
+ if (_has_bits_[0 / 32] & 63) {
// optional string name = 1;
if (has_name()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
-
+
// optional string input_type = 2;
if (has_input_type()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->input_type());
}
-
+
// optional string output_type = 3;
if (has_output_type()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->output_type());
}
-
+
// optional .google.protobuf.MethodOptions options = 4;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
- this->options());
+ *this->options_);
+ }
+
+ // optional bool client_streaming = 5 [default = false];
+ if (has_client_streaming()) {
+ total_size += 1 + 1;
}
-
+
+ // optional bool server_streaming = 6 [default = false];
+ if (has_server_streaming()) {
+ total_size += 1 + 1;
+ }
+
}
- if (!unknown_fields().empty()) {
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -4150,7 +6637,7 @@ int MethodDescriptorProto::ByteSize() const {
}
void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const MethodDescriptorProto* source =
::google::protobuf::internal::dynamic_cast_if_available<const MethodDescriptorProto*>(
&from);
@@ -4162,22 +6649,33 @@ void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
}
void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_name()) {
- set_name(from.name());
+ set_has_name();
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
}
if (from.has_input_type()) {
- set_input_type(from.input_type());
+ set_has_input_type();
+ input_type_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.input_type_);
}
if (from.has_output_type()) {
- set_output_type(from.output_type());
+ set_has_output_type();
+ output_type_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.output_type_);
}
if (from.has_options()) {
mutable_options()->::google::protobuf::MethodOptions::MergeFrom(from.options());
}
+ if (from.has_client_streaming()) {
+ set_client_streaming(from.client_streaming());
+ }
+ if (from.has_server_streaming()) {
+ set_server_streaming(from.server_streaming());
+ }
+ }
+ if (from._internal_metadata_.have_unknown_fields()) {
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}
- mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}
void MethodDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
@@ -4193,23 +6691,27 @@ void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) {
}
bool MethodDescriptorProto::IsInitialized() const {
-
+
if (has_options()) {
- if (!this->options().IsInitialized()) return false;
+ if (!this->options_->IsInitialized()) return false;
}
return true;
}
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;
+ 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(client_streaming_, other->client_streaming_);
+ std::swap(server_streaming_, other->server_streaming_);
+ 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 {
@@ -4220,6 +6722,260 @@ void MethodDescriptorProto::Swap(MethodDescriptorProto* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MethodDescriptorProto
+
+// optional string name = 1;
+ bool MethodDescriptorProto::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void MethodDescriptorProto::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void MethodDescriptorProto::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void MethodDescriptorProto::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+ const ::std::string& MethodDescriptorProto::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.name)
+}
+ void MethodDescriptorProto::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.name)
+}
+ void MethodDescriptorProto::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.name)
+}
+ ::std::string* MethodDescriptorProto::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* MethodDescriptorProto::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.name)
+}
+
+// optional string input_type = 2;
+ bool MethodDescriptorProto::has_input_type() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void MethodDescriptorProto::set_has_input_type() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void MethodDescriptorProto::clear_has_input_type() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void MethodDescriptorProto::clear_input_type() {
+ input_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_input_type();
+}
+ const ::std::string& MethodDescriptorProto::input_type() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.input_type)
+ return input_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_input_type(const ::std::string& value) {
+ set_has_input_type();
+ input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.input_type)
+}
+ void MethodDescriptorProto::set_input_type(const char* value) {
+ set_has_input_type();
+ input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.input_type)
+}
+ void MethodDescriptorProto::set_input_type(const char* value, size_t size) {
+ set_has_input_type();
+ input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.input_type)
+}
+ ::std::string* MethodDescriptorProto::mutable_input_type() {
+ set_has_input_type();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.input_type)
+ return input_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* MethodDescriptorProto::release_input_type() {
+ clear_has_input_type();
+ return input_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_allocated_input_type(::std::string* input_type) {
+ if (input_type != NULL) {
+ set_has_input_type();
+ } else {
+ clear_has_input_type();
+ }
+ input_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), input_type);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.input_type)
+}
+
+// optional string output_type = 3;
+ bool MethodDescriptorProto::has_output_type() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void MethodDescriptorProto::set_has_output_type() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void MethodDescriptorProto::clear_has_output_type() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void MethodDescriptorProto::clear_output_type() {
+ output_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_output_type();
+}
+ const ::std::string& MethodDescriptorProto::output_type() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.output_type)
+ return output_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_output_type(const ::std::string& value) {
+ set_has_output_type();
+ output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.output_type)
+}
+ void MethodDescriptorProto::set_output_type(const char* value) {
+ set_has_output_type();
+ output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.output_type)
+}
+ void MethodDescriptorProto::set_output_type(const char* value, size_t size) {
+ set_has_output_type();
+ output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.output_type)
+}
+ ::std::string* MethodDescriptorProto::mutable_output_type() {
+ set_has_output_type();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.output_type)
+ return output_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* MethodDescriptorProto::release_output_type() {
+ clear_has_output_type();
+ return output_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_allocated_output_type(::std::string* output_type) {
+ if (output_type != NULL) {
+ set_has_output_type();
+ } else {
+ clear_has_output_type();
+ }
+ output_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), output_type);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.output_type)
+}
+
+// optional .google.protobuf.MethodOptions options = 4;
+ bool MethodDescriptorProto::has_options() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+ void MethodDescriptorProto::set_has_options() {
+ _has_bits_[0] |= 0x00000008u;
+}
+ void MethodDescriptorProto::clear_has_options() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+ void MethodDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear();
+ clear_has_options();
+}
+ const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.options)
+ return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+ ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() {
+ set_has_options();
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::MethodOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options)
+ return options_;
+}
+ ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() {
+ clear_has_options();
+ ::google::protobuf::MethodOptions* temp = options_;
+ options_ = NULL;
+ return temp;
+}
+ void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.options)
+}
+
+// optional bool client_streaming = 5 [default = false];
+ bool MethodDescriptorProto::has_client_streaming() const {
+ return (_has_bits_[0] & 0x00000010u) != 0;
+}
+ void MethodDescriptorProto::set_has_client_streaming() {
+ _has_bits_[0] |= 0x00000010u;
+}
+ void MethodDescriptorProto::clear_has_client_streaming() {
+ _has_bits_[0] &= ~0x00000010u;
+}
+ void MethodDescriptorProto::clear_client_streaming() {
+ client_streaming_ = false;
+ clear_has_client_streaming();
+}
+ bool MethodDescriptorProto::client_streaming() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.client_streaming)
+ return client_streaming_;
+}
+ void MethodDescriptorProto::set_client_streaming(bool value) {
+ set_has_client_streaming();
+ client_streaming_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.client_streaming)
+}
+
+// optional bool server_streaming = 6 [default = false];
+ bool MethodDescriptorProto::has_server_streaming() const {
+ return (_has_bits_[0] & 0x00000020u) != 0;
+}
+ void MethodDescriptorProto::set_has_server_streaming() {
+ _has_bits_[0] |= 0x00000020u;
+}
+ void MethodDescriptorProto::clear_has_server_streaming() {
+ _has_bits_[0] &= ~0x00000020u;
+}
+ void MethodDescriptorProto::clear_server_streaming() {
+ server_streaming_ = false;
+ clear_has_server_streaming();
+}
+ bool MethodDescriptorProto::server_streaming() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.server_streaming)
+ return server_streaming_;
+}
+ void MethodDescriptorProto::set_server_streaming(bool value) {
+ set_has_server_streaming();
+ server_streaming_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.server_streaming)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -4251,51 +7007,64 @@ const int FileOptions::kJavaPackageFieldNumber;
const int FileOptions::kJavaOuterClassnameFieldNumber;
const int FileOptions::kJavaMultipleFilesFieldNumber;
const int FileOptions::kJavaGenerateEqualsAndHashFieldNumber;
+const int FileOptions::kJavaStringCheckUtf8FieldNumber;
const int FileOptions::kOptimizeForFieldNumber;
+const int FileOptions::kGoPackageFieldNumber;
const int FileOptions::kCcGenericServicesFieldNumber;
const int FileOptions::kJavaGenericServicesFieldNumber;
const int FileOptions::kPyGenericServicesFieldNumber;
+const int FileOptions::kDeprecatedFieldNumber;
+const int FileOptions::kCcEnableArenasFieldNumber;
+const int FileOptions::kObjcClassPrefixFieldNumber;
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)
}
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)
}
void FileOptions::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ 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_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
cc_generic_services_ = false;
java_generic_services_ = false;
py_generic_services_ = false;
+ deprecated_ = false;
+ cc_enable_arenas_ = false;
+ objc_class_prefix_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
FileOptions::~FileOptions() {
+ // @@protoc_insertion_point(destructor:google.protobuf.FileOptions)
SharedDtor();
}
void FileOptions::SharedDtor() {
- if (java_package_ != &::google::protobuf::internal::kEmptyString) {
- delete java_package_;
- }
- if (java_outer_classname_ != &::google::protobuf::internal::kEmptyString) {
- delete java_outer_classname_;
- }
+ java_package_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ java_outer_classname_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ go_package_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ objc_class_prefix_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
}
}
@@ -4311,83 +7080,106 @@ const ::google::protobuf::Descriptor* FileOptions::descriptor() {
}
const FileOptions& FileOptions::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
FileOptions* FileOptions::default_instance_ = NULL;
-FileOptions* FileOptions::New() const {
- return new FileOptions;
+FileOptions* FileOptions::New(::google::protobuf::Arena* arena) const {
+ FileOptions* n = new FileOptions;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void FileOptions::Clear() {
_extensions_.Clear();
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+ &reinterpret_cast<FileOptions*>(16)->f)
+
+#define ZR_(first, last) do {\
+ ::memset(&first, 0,\
+ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+ if (_has_bits_[0 / 32] & 255) {
+ ZR_(java_multiple_files_, cc_generic_services_);
if (has_java_package()) {
- if (java_package_ != &::google::protobuf::internal::kEmptyString) {
- java_package_->clear();
- }
+ java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_java_outer_classname()) {
- if (java_outer_classname_ != &::google::protobuf::internal::kEmptyString) {
- java_outer_classname_->clear();
- }
+ java_outer_classname_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
- java_multiple_files_ = false;
- java_generate_equals_and_hash_ = false;
optimize_for_ = 1;
- cc_generic_services_ = false;
- java_generic_services_ = false;
- py_generic_services_ = false;
+ if (has_go_package()) {
+ go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ }
+ if (_has_bits_[8 / 32] & 7936) {
+ ZR_(java_generic_services_, cc_enable_arenas_);
+ if (has_objc_class_prefix()) {
+ objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
}
+
+#undef ZR_HELPER_
+#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 FileOptions::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.FileOptions)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional string java_package = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_java_package()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->java_package().data(), this->java_package().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FileOptions.java_package");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(66)) goto parse_java_outer_classname;
break;
}
-
+
// optional string java_outer_classname = 8;
case 8: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 66) {
parse_java_outer_classname:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_java_outer_classname()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->java_outer_classname().data(), this->java_outer_classname().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FileOptions.java_outer_classname");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(72)) goto parse_optimize_for;
break;
}
-
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
case 9: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 72) {
parse_optimize_for:
int value;
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
@@ -4399,112 +7191,186 @@ bool FileOptions::MergePartialFromCodedStream(
mutable_unknown_fields()->AddVarint(9, value);
}
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(80)) goto parse_java_multiple_files;
break;
}
-
+
// optional bool java_multiple_files = 10 [default = false];
case 10: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 80) {
parse_java_multiple_files:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &java_multiple_files_)));
set_has_java_multiple_files();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(90)) goto parse_go_package;
+ break;
+ }
+
+ // optional string go_package = 11;
+ case 11: {
+ if (tag == 90) {
+ parse_go_package:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_go_package()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->go_package().data(), this->go_package().length(),
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FileOptions.go_package");
+ } else {
+ goto handle_unusual;
}
if (input->ExpectTag(128)) goto parse_cc_generic_services;
break;
}
-
+
// optional bool cc_generic_services = 16 [default = false];
case 16: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 128) {
parse_cc_generic_services:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &cc_generic_services_)));
set_has_cc_generic_services();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(136)) goto parse_java_generic_services;
break;
}
-
+
// optional bool java_generic_services = 17 [default = false];
case 17: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 136) {
parse_java_generic_services:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &java_generic_services_)));
set_has_java_generic_services();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(144)) goto parse_py_generic_services;
break;
}
-
+
// optional bool py_generic_services = 18 [default = false];
case 18: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 144) {
parse_py_generic_services:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &py_generic_services_)));
set_has_py_generic_services();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(160)) goto parse_java_generate_equals_and_hash;
break;
}
-
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
case 20: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 160) {
parse_java_generate_equals_and_hash:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &java_generate_equals_and_hash_)));
set_has_java_generate_equals_and_hash();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(184)) goto parse_deprecated;
+ break;
+ }
+
+ // optional bool deprecated = 23 [default = false];
+ case 23: {
+ if (tag == 184) {
+ parse_deprecated:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &deprecated_)));
+ set_has_deprecated();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(216)) goto parse_java_string_check_utf8;
+ break;
+ }
+
+ // optional bool java_string_check_utf8 = 27 [default = false];
+ case 27: {
+ if (tag == 216) {
+ parse_java_string_check_utf8:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &java_string_check_utf8_)));
+ set_has_java_string_check_utf8();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(248)) goto parse_cc_enable_arenas;
+ break;
+ }
+
+ // optional bool cc_enable_arenas = 31 [default = false];
+ case 31: {
+ if (tag == 248) {
+ parse_cc_enable_arenas:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &cc_enable_arenas_)));
+ set_has_cc_enable_arenas();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(290)) goto parse_objc_class_prefix;
+ break;
+ }
+
+ // optional string objc_class_prefix = 36;
+ case 36: {
+ if (tag == 290) {
+ parse_objc_class_prefix:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_objc_class_prefix()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->objc_class_prefix().data(), this->objc_class_prefix().length(),
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.FileOptions.objc_class_prefix");
+ } else {
+ goto handle_unusual;
}
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
break;
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 7994) {
parse_uninterpreted_option:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_uninterpreted_option()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
if ((8000u <= tag)) {
DO_(_extensions_.ParseField(tag, input, default_instance_,
@@ -4517,197 +7383,313 @@ bool FileOptions::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.FileOptions)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.FileOptions)
+ return false;
#undef DO_
}
void FileOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.FileOptions)
// optional string java_package = 1;
if (has_java_package()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->java_package().data(), this->java_package().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileOptions.java_package");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->java_package(), output);
}
-
+
// optional string java_outer_classname = 8;
if (has_java_outer_classname()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->java_outer_classname().data(), this->java_outer_classname().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileOptions.java_outer_classname");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
8, this->java_outer_classname(), output);
}
-
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
if (has_optimize_for()) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
9, this->optimize_for(), output);
}
-
+
// optional bool java_multiple_files = 10 [default = false];
if (has_java_multiple_files()) {
::google::protobuf::internal::WireFormatLite::WriteBool(10, this->java_multiple_files(), output);
}
-
+
+ // optional string go_package = 11;
+ if (has_go_package()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->go_package().data(), this->go_package().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileOptions.go_package");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 11, this->go_package(), output);
+ }
+
// optional bool cc_generic_services = 16 [default = false];
if (has_cc_generic_services()) {
::google::protobuf::internal::WireFormatLite::WriteBool(16, this->cc_generic_services(), output);
}
-
+
// optional bool java_generic_services = 17 [default = false];
if (has_java_generic_services()) {
::google::protobuf::internal::WireFormatLite::WriteBool(17, this->java_generic_services(), output);
}
-
+
// optional bool py_generic_services = 18 [default = false];
if (has_py_generic_services()) {
::google::protobuf::internal::WireFormatLite::WriteBool(18, this->py_generic_services(), output);
}
-
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
if (has_java_generate_equals_and_hash()) {
::google::protobuf::internal::WireFormatLite::WriteBool(20, this->java_generate_equals_and_hash(), output);
}
-
+
+ // optional bool deprecated = 23 [default = false];
+ if (has_deprecated()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(23, this->deprecated(), output);
+ }
+
+ // optional bool java_string_check_utf8 = 27 [default = false];
+ if (has_java_string_check_utf8()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(27, this->java_string_check_utf8(), output);
+ }
+
+ // optional bool cc_enable_arenas = 31 [default = false];
+ if (has_cc_enable_arenas()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(31, this->cc_enable_arenas(), output);
+ }
+
+ // optional string objc_class_prefix = 36;
+ if (has_objc_class_prefix()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->objc_class_prefix().data(), this->objc_class_prefix().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileOptions.objc_class_prefix");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 36, this->objc_class_prefix(), output);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.FileOptions)
}
::google::protobuf::uint8* FileOptions::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileOptions)
// optional string java_package = 1;
if (has_java_package()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->java_package().data(), this->java_package().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileOptions.java_package");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->java_package(), target);
}
-
+
// optional string java_outer_classname = 8;
if (has_java_outer_classname()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->java_outer_classname().data(), this->java_outer_classname().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileOptions.java_outer_classname");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
8, this->java_outer_classname(), target);
}
-
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
if (has_optimize_for()) {
target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
9, this->optimize_for(), target);
}
-
+
// optional bool java_multiple_files = 10 [default = false];
if (has_java_multiple_files()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->java_multiple_files(), target);
}
-
+
+ // optional string go_package = 11;
+ if (has_go_package()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->go_package().data(), this->go_package().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileOptions.go_package");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 11, this->go_package(), target);
+ }
+
// optional bool cc_generic_services = 16 [default = false];
if (has_cc_generic_services()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(16, this->cc_generic_services(), target);
}
-
+
// optional bool java_generic_services = 17 [default = false];
if (has_java_generic_services()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(17, this->java_generic_services(), target);
}
-
+
// optional bool py_generic_services = 18 [default = false];
if (has_py_generic_services()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(18, this->py_generic_services(), target);
}
-
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
if (has_java_generate_equals_and_hash()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(20, this->java_generate_equals_and_hash(), target);
}
-
+
+ // optional bool deprecated = 23 [default = false];
+ if (has_deprecated()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(23, this->deprecated(), target);
+ }
+
+ // optional bool java_string_check_utf8 = 27 [default = false];
+ if (has_java_string_check_utf8()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(27, this->java_string_check_utf8(), target);
+ }
+
+ // optional bool cc_enable_arenas = 31 [default = false];
+ if (has_cc_enable_arenas()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(31, this->cc_enable_arenas(), target);
+ }
+
+ // optional string objc_class_prefix = 36;
+ if (has_objc_class_prefix()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->objc_class_prefix().data(), this->objc_class_prefix().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.FileOptions.objc_class_prefix");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 36, this->objc_class_prefix(), target);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileOptions)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->java_package());
}
-
+
// optional string java_outer_classname = 8;
if (has_java_outer_classname()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->java_outer_classname());
}
-
+
// optional bool java_multiple_files = 10 [default = false];
if (has_java_multiple_files()) {
total_size += 1 + 1;
}
-
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
if (has_java_generate_equals_and_hash()) {
total_size += 2 + 1;
}
-
+
+ // optional bool java_string_check_utf8 = 27 [default = false];
+ if (has_java_string_check_utf8()) {
+ total_size += 2 + 1;
+ }
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
if (has_optimize_for()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::EnumSize(this->optimize_for());
}
-
+
+ // optional string go_package = 11;
+ if (has_go_package()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->go_package());
+ }
+
// optional bool cc_generic_services = 16 [default = false];
if (has_cc_generic_services()) {
total_size += 2 + 1;
}
-
+
+ }
+ if (_has_bits_[8 / 32] & 7936) {
// optional bool java_generic_services = 17 [default = false];
if (has_java_generic_services()) {
total_size += 2 + 1;
}
-
+
// optional bool py_generic_services = 18 [default = false];
if (has_py_generic_services()) {
total_size += 2 + 1;
}
-
+
+ // optional bool deprecated = 23 [default = false];
+ if (has_deprecated()) {
+ total_size += 2 + 1;
+ }
+
+ // optional bool cc_enable_arenas = 31 [default = false];
+ if (has_cc_enable_arenas()) {
+ total_size += 2 + 1;
+ }
+
+ // optional string objc_class_prefix = 36;
+ if (has_objc_class_prefix()) {
+ total_size += 2 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->objc_class_prefix());
+ }
+
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
total_size += 2 * this->uninterpreted_option_size();
@@ -4716,10 +7698,10 @@ int FileOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -4731,7 +7713,7 @@ int FileOptions::ByteSize() const {
}
void FileOptions::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const FileOptions* source =
::google::protobuf::internal::dynamic_cast_if_available<const FileOptions*>(
&from);
@@ -4743,14 +7725,16 @@ void FileOptions::MergeFrom(const ::google::protobuf::Message& from) {
}
void FileOptions::MergeFrom(const FileOptions& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_java_package()) {
- set_java_package(from.java_package());
+ set_has_java_package();
+ java_package_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.java_package_);
}
if (from.has_java_outer_classname()) {
- set_java_outer_classname(from.java_outer_classname());
+ set_has_java_outer_classname();
+ java_outer_classname_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.java_outer_classname_);
}
if (from.has_java_multiple_files()) {
set_java_multiple_files(from.java_multiple_files());
@@ -4758,21 +7742,42 @@ void FileOptions::MergeFrom(const FileOptions& from) {
if (from.has_java_generate_equals_and_hash()) {
set_java_generate_equals_and_hash(from.java_generate_equals_and_hash());
}
+ if (from.has_java_string_check_utf8()) {
+ set_java_string_check_utf8(from.java_string_check_utf8());
+ }
if (from.has_optimize_for()) {
set_optimize_for(from.optimize_for());
}
+ if (from.has_go_package()) {
+ set_has_go_package();
+ go_package_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.go_package_);
+ }
if (from.has_cc_generic_services()) {
set_cc_generic_services(from.cc_generic_services());
}
+ }
+ if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
if (from.has_java_generic_services()) {
set_java_generic_services(from.java_generic_services());
}
if (from.has_py_generic_services()) {
set_py_generic_services(from.py_generic_services());
}
+ if (from.has_deprecated()) {
+ set_deprecated(from.deprecated());
+ }
+ if (from.has_cc_enable_arenas()) {
+ set_cc_enable_arenas(from.cc_enable_arenas());
+ }
+ if (from.has_objc_class_prefix()) {
+ set_has_objc_class_prefix();
+ objc_class_prefix_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.objc_class_prefix_);
+ }
}
_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) {
@@ -4788,30 +7793,35 @@ void FileOptions::CopyFrom(const FileOptions& from) {
}
bool FileOptions::IsInitialized() const {
-
- for (int i = 0; i < uninterpreted_option_size(); i++) {
- if (!this->uninterpreted_option(i).IsInitialized()) return false;
- }
-
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->uninterpreted_option())) return false;
+
if (!_extensions_.IsInitialized()) return false; return true;
}
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(optimize_for_, other->optimize_for_);
- 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_);
- 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;
+ 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_);
+ std::swap(cc_enable_arenas_, other->cc_enable_arenas_);
+ objc_class_prefix_.Swap(&other->objc_class_prefix_);
+ 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 {
@@ -4822,37 +7832,508 @@ void FileOptions::Swap(FileOptions* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FileOptions
+
+// optional string java_package = 1;
+ bool FileOptions::has_java_package() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void FileOptions::set_has_java_package() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void FileOptions::clear_has_java_package() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void FileOptions::clear_java_package() {
+ java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_java_package();
+}
+ const ::std::string& FileOptions::java_package() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_package)
+ return java_package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_java_package(const ::std::string& value) {
+ set_has_java_package();
+ java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_package)
+}
+ void FileOptions::set_java_package(const char* value) {
+ set_has_java_package();
+ java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.java_package)
+}
+ void FileOptions::set_java_package(const char* value, size_t size) {
+ set_has_java_package();
+ java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.java_package)
+}
+ ::std::string* FileOptions::mutable_java_package() {
+ set_has_java_package();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_package)
+ return java_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileOptions::release_java_package() {
+ clear_has_java_package();
+ return java_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_allocated_java_package(::std::string* java_package) {
+ if (java_package != NULL) {
+ set_has_java_package();
+ } else {
+ clear_has_java_package();
+ }
+ java_package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_package);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_package)
+}
+
+// optional string java_outer_classname = 8;
+ bool FileOptions::has_java_outer_classname() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void FileOptions::set_has_java_outer_classname() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void FileOptions::clear_has_java_outer_classname() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void FileOptions::clear_java_outer_classname() {
+ java_outer_classname_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_java_outer_classname();
+}
+ const ::std::string& FileOptions::java_outer_classname() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_outer_classname)
+ return java_outer_classname_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_java_outer_classname(const ::std::string& value) {
+ set_has_java_outer_classname();
+ java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_outer_classname)
+}
+ void FileOptions::set_java_outer_classname(const char* value) {
+ set_has_java_outer_classname();
+ java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.java_outer_classname)
+}
+ void FileOptions::set_java_outer_classname(const char* value, size_t size) {
+ set_has_java_outer_classname();
+ java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.java_outer_classname)
+}
+ ::std::string* FileOptions::mutable_java_outer_classname() {
+ set_has_java_outer_classname();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_outer_classname)
+ return java_outer_classname_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileOptions::release_java_outer_classname() {
+ clear_has_java_outer_classname();
+ return java_outer_classname_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_allocated_java_outer_classname(::std::string* java_outer_classname) {
+ if (java_outer_classname != NULL) {
+ set_has_java_outer_classname();
+ } else {
+ clear_has_java_outer_classname();
+ }
+ java_outer_classname_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_outer_classname);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_outer_classname)
+}
+
+// optional bool java_multiple_files = 10 [default = false];
+ bool FileOptions::has_java_multiple_files() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void FileOptions::set_has_java_multiple_files() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void FileOptions::clear_has_java_multiple_files() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void FileOptions::clear_java_multiple_files() {
+ java_multiple_files_ = false;
+ clear_has_java_multiple_files();
+}
+ bool FileOptions::java_multiple_files() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_multiple_files)
+ return java_multiple_files_;
+}
+ void FileOptions::set_java_multiple_files(bool value) {
+ set_has_java_multiple_files();
+ java_multiple_files_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_multiple_files)
+}
+
+// optional bool java_generate_equals_and_hash = 20 [default = false];
+ bool FileOptions::has_java_generate_equals_and_hash() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+ void FileOptions::set_has_java_generate_equals_and_hash() {
+ _has_bits_[0] |= 0x00000008u;
+}
+ void FileOptions::clear_has_java_generate_equals_and_hash() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+ void FileOptions::clear_java_generate_equals_and_hash() {
+ java_generate_equals_and_hash_ = false;
+ clear_has_java_generate_equals_and_hash();
+}
+ bool FileOptions::java_generate_equals_and_hash() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generate_equals_and_hash)
+ return java_generate_equals_and_hash_;
+}
+ void FileOptions::set_java_generate_equals_and_hash(bool value) {
+ set_has_java_generate_equals_and_hash();
+ java_generate_equals_and_hash_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generate_equals_and_hash)
+}
+
+// optional bool java_string_check_utf8 = 27 [default = false];
+ bool FileOptions::has_java_string_check_utf8() const {
+ return (_has_bits_[0] & 0x00000010u) != 0;
+}
+ void FileOptions::set_has_java_string_check_utf8() {
+ _has_bits_[0] |= 0x00000010u;
+}
+ void FileOptions::clear_has_java_string_check_utf8() {
+ _has_bits_[0] &= ~0x00000010u;
+}
+ void FileOptions::clear_java_string_check_utf8() {
+ java_string_check_utf8_ = false;
+ clear_has_java_string_check_utf8();
+}
+ bool FileOptions::java_string_check_utf8() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_string_check_utf8)
+ return java_string_check_utf8_;
+}
+ void FileOptions::set_java_string_check_utf8(bool value) {
+ set_has_java_string_check_utf8();
+ java_string_check_utf8_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_string_check_utf8)
+}
+
+// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+ bool FileOptions::has_optimize_for() const {
+ return (_has_bits_[0] & 0x00000020u) != 0;
+}
+ void FileOptions::set_has_optimize_for() {
+ _has_bits_[0] |= 0x00000020u;
+}
+ void FileOptions::clear_has_optimize_for() {
+ _has_bits_[0] &= ~0x00000020u;
+}
+ void FileOptions::clear_optimize_for() {
+ optimize_for_ = 1;
+ clear_has_optimize_for();
+}
+ ::google::protobuf::FileOptions_OptimizeMode FileOptions::optimize_for() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.optimize_for)
+ return static_cast< ::google::protobuf::FileOptions_OptimizeMode >(optimize_for_);
+}
+ void FileOptions::set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value) {
+ assert(::google::protobuf::FileOptions_OptimizeMode_IsValid(value));
+ set_has_optimize_for();
+ optimize_for_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.optimize_for)
+}
+
+// optional string go_package = 11;
+ bool FileOptions::has_go_package() const {
+ return (_has_bits_[0] & 0x00000040u) != 0;
+}
+ void FileOptions::set_has_go_package() {
+ _has_bits_[0] |= 0x00000040u;
+}
+ void FileOptions::clear_has_go_package() {
+ _has_bits_[0] &= ~0x00000040u;
+}
+ void FileOptions::clear_go_package() {
+ go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_go_package();
+}
+ const ::std::string& FileOptions::go_package() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.go_package)
+ return go_package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_go_package(const ::std::string& value) {
+ set_has_go_package();
+ go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.go_package)
+}
+ void FileOptions::set_go_package(const char* value) {
+ set_has_go_package();
+ go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.go_package)
+}
+ void FileOptions::set_go_package(const char* value, size_t size) {
+ set_has_go_package();
+ go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.go_package)
+}
+ ::std::string* FileOptions::mutable_go_package() {
+ set_has_go_package();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.go_package)
+ return go_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileOptions::release_go_package() {
+ clear_has_go_package();
+ return go_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_allocated_go_package(::std::string* go_package) {
+ if (go_package != NULL) {
+ set_has_go_package();
+ } else {
+ clear_has_go_package();
+ }
+ go_package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), go_package);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.go_package)
+}
+
+// optional bool cc_generic_services = 16 [default = false];
+ bool FileOptions::has_cc_generic_services() const {
+ return (_has_bits_[0] & 0x00000080u) != 0;
+}
+ void FileOptions::set_has_cc_generic_services() {
+ _has_bits_[0] |= 0x00000080u;
+}
+ void FileOptions::clear_has_cc_generic_services() {
+ _has_bits_[0] &= ~0x00000080u;
+}
+ void FileOptions::clear_cc_generic_services() {
+ cc_generic_services_ = false;
+ clear_has_cc_generic_services();
+}
+ bool FileOptions::cc_generic_services() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_generic_services)
+ return cc_generic_services_;
+}
+ void FileOptions::set_cc_generic_services(bool value) {
+ set_has_cc_generic_services();
+ cc_generic_services_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_generic_services)
+}
+
+// optional bool java_generic_services = 17 [default = false];
+ bool FileOptions::has_java_generic_services() const {
+ return (_has_bits_[0] & 0x00000100u) != 0;
+}
+ void FileOptions::set_has_java_generic_services() {
+ _has_bits_[0] |= 0x00000100u;
+}
+ void FileOptions::clear_has_java_generic_services() {
+ _has_bits_[0] &= ~0x00000100u;
+}
+ void FileOptions::clear_java_generic_services() {
+ java_generic_services_ = false;
+ clear_has_java_generic_services();
+}
+ bool FileOptions::java_generic_services() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generic_services)
+ return java_generic_services_;
+}
+ void FileOptions::set_java_generic_services(bool value) {
+ set_has_java_generic_services();
+ java_generic_services_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generic_services)
+}
+
+// optional bool py_generic_services = 18 [default = false];
+ bool FileOptions::has_py_generic_services() const {
+ return (_has_bits_[0] & 0x00000200u) != 0;
+}
+ void FileOptions::set_has_py_generic_services() {
+ _has_bits_[0] |= 0x00000200u;
+}
+ void FileOptions::clear_has_py_generic_services() {
+ _has_bits_[0] &= ~0x00000200u;
+}
+ void FileOptions::clear_py_generic_services() {
+ py_generic_services_ = false;
+ clear_has_py_generic_services();
+}
+ bool FileOptions::py_generic_services() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.py_generic_services)
+ return py_generic_services_;
+}
+ void FileOptions::set_py_generic_services(bool value) {
+ set_has_py_generic_services();
+ py_generic_services_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.py_generic_services)
+}
+
+// optional bool deprecated = 23 [default = false];
+ bool FileOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000400u) != 0;
+}
+ void FileOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000400u;
+}
+ void FileOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000400u;
+}
+ void FileOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+ bool FileOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.deprecated)
+ return deprecated_;
+}
+ void FileOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.deprecated)
+}
+
+// optional bool cc_enable_arenas = 31 [default = false];
+ bool FileOptions::has_cc_enable_arenas() const {
+ return (_has_bits_[0] & 0x00000800u) != 0;
+}
+ void FileOptions::set_has_cc_enable_arenas() {
+ _has_bits_[0] |= 0x00000800u;
+}
+ void FileOptions::clear_has_cc_enable_arenas() {
+ _has_bits_[0] &= ~0x00000800u;
+}
+ void FileOptions::clear_cc_enable_arenas() {
+ cc_enable_arenas_ = false;
+ clear_has_cc_enable_arenas();
+}
+ bool FileOptions::cc_enable_arenas() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_enable_arenas)
+ return cc_enable_arenas_;
+}
+ void FileOptions::set_cc_enable_arenas(bool value) {
+ set_has_cc_enable_arenas();
+ cc_enable_arenas_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_enable_arenas)
+}
+
+// optional string objc_class_prefix = 36;
+ bool FileOptions::has_objc_class_prefix() const {
+ return (_has_bits_[0] & 0x00001000u) != 0;
+}
+ void FileOptions::set_has_objc_class_prefix() {
+ _has_bits_[0] |= 0x00001000u;
+}
+ void FileOptions::clear_has_objc_class_prefix() {
+ _has_bits_[0] &= ~0x00001000u;
+}
+ void FileOptions::clear_objc_class_prefix() {
+ objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_objc_class_prefix();
+}
+ const ::std::string& FileOptions::objc_class_prefix() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.objc_class_prefix)
+ return objc_class_prefix_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_objc_class_prefix(const ::std::string& value) {
+ set_has_objc_class_prefix();
+ objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.objc_class_prefix)
+}
+ void FileOptions::set_objc_class_prefix(const char* value) {
+ set_has_objc_class_prefix();
+ objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.objc_class_prefix)
+}
+ void FileOptions::set_objc_class_prefix(const char* value, size_t size) {
+ set_has_objc_class_prefix();
+ objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.objc_class_prefix)
+}
+ ::std::string* FileOptions::mutable_objc_class_prefix() {
+ set_has_objc_class_prefix();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.objc_class_prefix)
+ return objc_class_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileOptions::release_objc_class_prefix() {
+ clear_has_objc_class_prefix();
+ return objc_class_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_allocated_objc_class_prefix(::std::string* objc_class_prefix) {
+ if (objc_class_prefix != NULL) {
+ set_has_objc_class_prefix();
+ } else {
+ clear_has_objc_class_prefix();
+ }
+ objc_class_prefix_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), objc_class_prefix);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.objc_class_prefix)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ int FileOptions::uninterpreted_option_size() const {
+ return uninterpreted_option_.size();
+}
+ void FileOptions::clear_uninterpreted_option() {
+ uninterpreted_option_.Clear();
+}
+ const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.uninterpreted_option)
+ return uninterpreted_option_.Get(index);
+}
+ ::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.uninterpreted_option)
+ return uninterpreted_option_.Mutable(index);
+}
+ ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileOptions.uninterpreted_option)
+ return uninterpreted_option_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+FileOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option)
+ return uninterpreted_option_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+FileOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileOptions.uninterpreted_option)
+ return &uninterpreted_option_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
#ifndef _MSC_VER
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)
}
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)
}
void MessageOptions::SharedCtor() {
_cached_size_ = 0;
message_set_wire_format_ = false;
no_standard_descriptor_accessor_ = false;
+ deprecated_ = false;
+ map_entry_ = false;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
MessageOptions::~MessageOptions() {
+ // @@protoc_insertion_point(destructor:google.protobuf.MessageOptions)
SharedDtor();
}
@@ -4872,83 +8353,131 @@ const ::google::protobuf::Descriptor* MessageOptions::descriptor() {
}
const MessageOptions& MessageOptions::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
MessageOptions* MessageOptions::default_instance_ = NULL;
-MessageOptions* MessageOptions::New() const {
- return new MessageOptions;
+MessageOptions* MessageOptions::New(::google::protobuf::Arena* arena) const {
+ MessageOptions* n = new MessageOptions;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void MessageOptions::Clear() {
_extensions_.Clear();
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
- message_set_wire_format_ = false;
- no_standard_descriptor_accessor_ = false;
- }
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+ &reinterpret_cast<MessageOptions*>(16)->f)
+
+#define ZR_(first, last) do {\
+ ::memset(&first, 0,\
+ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+ ZR_(message_set_wire_format_, map_entry_);
+
+#undef ZR_HELPER_
+#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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.MessageOptions)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional bool message_set_wire_format = 1 [default = false];
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 8) {
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &message_set_wire_format_)));
set_has_message_set_wire_format();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(16)) goto parse_no_standard_descriptor_accessor;
break;
}
-
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 16) {
parse_no_standard_descriptor_accessor:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &no_standard_descriptor_accessor_)));
set_has_no_standard_descriptor_accessor();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(24)) goto parse_deprecated;
+ break;
+ }
+
+ // optional bool deprecated = 3 [default = false];
+ case 3: {
+ if (tag == 24) {
+ parse_deprecated:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &deprecated_)));
+ set_has_deprecated();
+ } 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;
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 7994) {
parse_uninterpreted_option:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_uninterpreted_option()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
if ((8000u <= tag)) {
DO_(_extensions_.ParseField(tag, input, default_instance_,
@@ -4961,82 +8490,121 @@ bool MessageOptions::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.MessageOptions)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.MessageOptions)
+ return false;
#undef DO_
}
void MessageOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.MessageOptions)
// optional bool message_set_wire_format = 1 [default = false];
if (has_message_set_wire_format()) {
::google::protobuf::internal::WireFormatLite::WriteBool(1, this->message_set_wire_format(), output);
}
-
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
if (has_no_standard_descriptor_accessor()) {
::google::protobuf::internal::WireFormatLite::WriteBool(2, this->no_standard_descriptor_accessor(), output);
}
-
+
+ // optional bool deprecated = 3 [default = false];
+ if (has_deprecated()) {
+ ::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++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.MessageOptions)
}
::google::protobuf::uint8* MessageOptions::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MessageOptions)
// optional bool message_set_wire_format = 1 [default = false];
if (has_message_set_wire_format()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(1, this->message_set_wire_format(), target);
}
-
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
if (has_no_standard_descriptor_accessor()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->no_standard_descriptor_accessor(), target);
}
-
+
+ // optional bool deprecated = 3 [default = false];
+ if (has_deprecated()) {
+ 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++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MessageOptions)
return target;
}
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;
}
-
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
if (has_no_standard_descriptor_accessor()) {
total_size += 1 + 1;
}
-
+
+ // optional bool deprecated = 3 [default = false];
+ if (has_deprecated()) {
+ 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();
@@ -5045,10 +8613,10 @@ int MessageOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -5060,7 +8628,7 @@ int MessageOptions::ByteSize() const {
}
void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const MessageOptions* source =
::google::protobuf::internal::dynamic_cast_if_available<const MessageOptions*>(
&from);
@@ -5072,7 +8640,7 @@ void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) {
}
void MessageOptions::MergeFrom(const MessageOptions& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_message_set_wire_format()) {
@@ -5081,9 +8649,17 @@ void MessageOptions::MergeFrom(const MessageOptions& from) {
if (from.has_no_standard_descriptor_accessor()) {
set_no_standard_descriptor_accessor(from.no_standard_descriptor_accessor());
}
+ 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) {
@@ -5099,24 +8675,26 @@ void MessageOptions::CopyFrom(const MessageOptions& from) {
}
bool MessageOptions::IsInitialized() const {
-
- for (int i = 0; i < uninterpreted_option_size(); i++) {
- if (!this->uninterpreted_option(i).IsInitialized()) return false;
- }
-
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->uninterpreted_option())) return false;
+
if (!_extensions_.IsInitialized()) return false; return true;
}
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_);
- 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;
+ 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 {
@@ -5127,6 +8705,136 @@ void MessageOptions::Swap(MessageOptions* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MessageOptions
+
+// optional bool message_set_wire_format = 1 [default = false];
+ bool MessageOptions::has_message_set_wire_format() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void MessageOptions::set_has_message_set_wire_format() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void MessageOptions::clear_has_message_set_wire_format() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void MessageOptions::clear_message_set_wire_format() {
+ message_set_wire_format_ = false;
+ clear_has_message_set_wire_format();
+}
+ bool MessageOptions::message_set_wire_format() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.message_set_wire_format)
+ return message_set_wire_format_;
+}
+ void MessageOptions::set_message_set_wire_format(bool value) {
+ set_has_message_set_wire_format();
+ message_set_wire_format_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.message_set_wire_format)
+}
+
+// optional bool no_standard_descriptor_accessor = 2 [default = false];
+ bool MessageOptions::has_no_standard_descriptor_accessor() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void MessageOptions::set_has_no_standard_descriptor_accessor() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void MessageOptions::clear_has_no_standard_descriptor_accessor() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void MessageOptions::clear_no_standard_descriptor_accessor() {
+ no_standard_descriptor_accessor_ = false;
+ clear_has_no_standard_descriptor_accessor();
+}
+ bool MessageOptions::no_standard_descriptor_accessor() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
+ return no_standard_descriptor_accessor_;
+}
+ void MessageOptions::set_no_standard_descriptor_accessor(bool value) {
+ set_has_no_standard_descriptor_accessor();
+ no_standard_descriptor_accessor_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
+}
+
+// optional bool deprecated = 3 [default = false];
+ bool MessageOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void MessageOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void MessageOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void MessageOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+ bool MessageOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.deprecated)
+ return deprecated_;
+}
+ void MessageOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.deprecated)
+}
+
+// optional bool map_entry = 7;
+ bool MessageOptions::has_map_entry() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+ void MessageOptions::set_has_map_entry() {
+ _has_bits_[0] |= 0x00000008u;
+}
+ void MessageOptions::clear_has_map_entry() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+ void MessageOptions::clear_map_entry() {
+ map_entry_ = false;
+ clear_has_map_entry();
+}
+ bool MessageOptions::map_entry() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.map_entry)
+ return map_entry_;
+}
+ 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;
+ int MessageOptions::uninterpreted_option_size() const {
+ return uninterpreted_option_.size();
+}
+ void MessageOptions::clear_uninterpreted_option() {
+ uninterpreted_option_.Clear();
+}
+ const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.uninterpreted_option)
+ return uninterpreted_option_.Get(index);
+}
+ ::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MessageOptions.uninterpreted_option)
+ return uninterpreted_option_.Mutable(index);
+}
+ ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.MessageOptions.uninterpreted_option)
+ return uninterpreted_option_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+MessageOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option)
+ return uninterpreted_option_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+MessageOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.MessageOptions.uninterpreted_option)
+ return &uninterpreted_option_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -5156,42 +8864,45 @@ const int FieldOptions::CType_ARRAYSIZE;
#ifndef _MSC_VER
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)
}
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() {
_cached_size_ = 0;
ctype_ = 0;
packed_ = false;
+ lazy_ = false;
deprecated_ = false;
- experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ weak_ = false;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
FieldOptions::~FieldOptions() {
+ // @@protoc_insertion_point(destructor:google.protobuf.FieldOptions)
SharedDtor();
}
void FieldOptions::SharedDtor() {
- if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) {
- delete experimental_map_key_;
- }
if (this != default_instance_) {
}
}
@@ -5207,42 +8918,57 @@ const ::google::protobuf::Descriptor* FieldOptions::descriptor() {
}
const FieldOptions& FieldOptions::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
FieldOptions* FieldOptions::default_instance_ = NULL;
-FieldOptions* FieldOptions::New() const {
- return new FieldOptions;
+FieldOptions* FieldOptions::New(::google::protobuf::Arena* arena) const {
+ FieldOptions* n = new FieldOptions;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void FieldOptions::Clear() {
_extensions_.Clear();
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
- ctype_ = 0;
- packed_ = false;
- deprecated_ = false;
- if (has_experimental_map_key()) {
- if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) {
- experimental_map_key_->clear();
- }
- }
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+ &reinterpret_cast<FieldOptions*>(16)->f)
+
+#define ZR_(first, last) do {\
+ ::memset(&first, 0,\
+ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+ if (_has_bits_[0 / 32] & 31) {
+ ZR_(ctype_, weak_);
}
+
+#undef ZR_HELPER_
+#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 FieldOptions::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.FieldOptions)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 8) {
int value;
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
@@ -5253,81 +8979,92 @@ bool FieldOptions::MergePartialFromCodedStream(
mutable_unknown_fields()->AddVarint(1, value);
}
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(16)) goto parse_packed;
break;
}
-
+
// optional bool packed = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 16) {
parse_packed:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &packed_)));
set_has_packed();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(24)) goto parse_deprecated;
break;
}
-
+
// optional bool deprecated = 3 [default = false];
case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 24) {
parse_deprecated:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &deprecated_)));
set_has_deprecated();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectTag(74)) goto parse_experimental_map_key;
+ if (input->ExpectTag(40)) goto parse_lazy;
break;
}
-
- // optional string experimental_map_key = 9;
- case 9: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
- parse_experimental_map_key:
- DO_(::google::protobuf::internal::WireFormatLite::ReadString(
- input, this->mutable_experimental_map_key()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
- this->experimental_map_key().data(), this->experimental_map_key().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+
+ // optional bool lazy = 5 [default = false];
+ case 5: {
+ if (tag == 40) {
+ parse_lazy:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &lazy_)));
+ set_has_lazy();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(80)) goto parse_weak;
+ break;
+ }
+
+ // optional bool weak = 10 [default = false];
+ case 10: {
+ if (tag == 80) {
+ parse_weak:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &weak_)));
+ set_has_weak();
+ } else {
+ goto handle_unusual;
}
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
break;
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 7994) {
parse_uninterpreted_option:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_uninterpreted_option()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
if ((8000u <= tag)) {
DO_(_extensions_.ParseField(tag, input, default_instance_,
@@ -5340,126 +9077,139 @@ bool FieldOptions::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.FieldOptions)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.FieldOptions)
+ return false;
#undef DO_
}
void FieldOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.FieldOptions)
// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
if (has_ctype()) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
1, this->ctype(), output);
}
-
+
// optional bool packed = 2;
if (has_packed()) {
::google::protobuf::internal::WireFormatLite::WriteBool(2, this->packed(), output);
}
-
+
// optional bool deprecated = 3 [default = false];
if (has_deprecated()) {
::google::protobuf::internal::WireFormatLite::WriteBool(3, this->deprecated(), output);
}
-
- // optional string experimental_map_key = 9;
- if (has_experimental_map_key()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
- this->experimental_map_key().data(), this->experimental_map_key().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
- 9, this->experimental_map_key(), output);
+
+ // optional bool lazy = 5 [default = false];
+ if (has_lazy()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->lazy(), output);
+ }
+
+ // optional bool weak = 10 [default = false];
+ if (has_weak()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->weak(), output);
}
-
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.FieldOptions)
}
::google::protobuf::uint8* FieldOptions::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldOptions)
// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
if (has_ctype()) {
target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
1, this->ctype(), target);
}
-
+
// optional bool packed = 2;
if (has_packed()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->packed(), target);
}
-
+
// optional bool deprecated = 3 [default = false];
if (has_deprecated()) {
target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->deprecated(), target);
}
-
- // optional string experimental_map_key = 9;
- if (has_experimental_map_key()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
- this->experimental_map_key().data(), this->experimental_map_key().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- target =
- ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
- 9, this->experimental_map_key(), target);
+
+ // optional bool lazy = 5 [default = false];
+ if (has_lazy()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->lazy(), target);
}
-
+
+ // optional bool weak = 10 [default = false];
+ if (has_weak()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->weak(), target);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldOptions)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::EnumSize(this->ctype());
}
-
+
// optional bool packed = 2;
if (has_packed()) {
total_size += 1 + 1;
}
-
+
+ // optional bool lazy = 5 [default = false];
+ if (has_lazy()) {
+ total_size += 1 + 1;
+ }
+
// optional bool deprecated = 3 [default = false];
if (has_deprecated()) {
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;
}
-
+
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
total_size += 2 * this->uninterpreted_option_size();
@@ -5468,10 +9218,10 @@ int FieldOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -5483,7 +9233,7 @@ int FieldOptions::ByteSize() const {
}
void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const FieldOptions* source =
::google::protobuf::internal::dynamic_cast_if_available<const FieldOptions*>(
&from);
@@ -5495,7 +9245,7 @@ void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) {
}
void FieldOptions::MergeFrom(const FieldOptions& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_ctype()) {
@@ -5504,15 +9254,20 @@ void FieldOptions::MergeFrom(const FieldOptions& from) {
if (from.has_packed()) {
set_packed(from.packed());
}
+ if (from.has_lazy()) {
+ set_lazy(from.lazy());
+ }
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) {
@@ -5528,26 +9283,27 @@ void FieldOptions::CopyFrom(const FieldOptions& from) {
}
bool FieldOptions::IsInitialized() const {
-
- for (int i = 0; i < uninterpreted_option_size(); i++) {
- if (!this->uninterpreted_option(i).IsInitialized()) return false;
- }
-
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->uninterpreted_option())) return false;
+
if (!_extensions_.IsInitialized()) return false; return true;
}
void FieldOptions::Swap(FieldOptions* other) {
- if (other != this) {
- std::swap(ctype_, other->ctype_);
- std::swap(packed_, other->packed_);
- std::swap(deprecated_, other->deprecated_);
- std::swap(experimental_map_key_, other->experimental_map_key_);
- 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;
+ 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 {
@@ -5558,33 +9314,196 @@ void FieldOptions::Swap(FieldOptions* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FieldOptions
+
+// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+ bool FieldOptions::has_ctype() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void FieldOptions::set_has_ctype() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void FieldOptions::clear_has_ctype() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void FieldOptions::clear_ctype() {
+ ctype_ = 0;
+ clear_has_ctype();
+}
+ ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.ctype)
+ return static_cast< ::google::protobuf::FieldOptions_CType >(ctype_);
+}
+ void FieldOptions::set_ctype(::google::protobuf::FieldOptions_CType value) {
+ assert(::google::protobuf::FieldOptions_CType_IsValid(value));
+ set_has_ctype();
+ ctype_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.ctype)
+}
+
+// optional bool packed = 2;
+ bool FieldOptions::has_packed() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void FieldOptions::set_has_packed() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void FieldOptions::clear_has_packed() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void FieldOptions::clear_packed() {
+ packed_ = false;
+ clear_has_packed();
+}
+ bool FieldOptions::packed() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.packed)
+ return packed_;
+}
+ void FieldOptions::set_packed(bool value) {
+ set_has_packed();
+ packed_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed)
+}
+
+// optional bool lazy = 5 [default = false];
+ bool FieldOptions::has_lazy() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void FieldOptions::set_has_lazy() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void FieldOptions::clear_has_lazy() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void FieldOptions::clear_lazy() {
+ lazy_ = false;
+ clear_has_lazy();
+}
+ bool FieldOptions::lazy() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.lazy)
+ return lazy_;
+}
+ void FieldOptions::set_lazy(bool value) {
+ set_has_lazy();
+ lazy_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.lazy)
+}
+
+// optional bool deprecated = 3 [default = false];
+ bool FieldOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+ void FieldOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000008u;
+}
+ void FieldOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+ void FieldOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+ bool FieldOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.deprecated)
+ return deprecated_;
+}
+ void FieldOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.deprecated)
+}
+
+// optional bool weak = 10 [default = false];
+ bool FieldOptions::has_weak() const {
+ return (_has_bits_[0] & 0x00000010u) != 0;
+}
+ void FieldOptions::set_has_weak() {
+ _has_bits_[0] |= 0x00000010u;
+}
+ void FieldOptions::clear_has_weak() {
+ _has_bits_[0] &= ~0x00000010u;
+}
+ void FieldOptions::clear_weak() {
+ weak_ = false;
+ clear_has_weak();
+}
+ bool FieldOptions::weak() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.weak)
+ return weak_;
+}
+ void FieldOptions::set_weak(bool value) {
+ set_has_weak();
+ weak_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.weak)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ int FieldOptions::uninterpreted_option_size() const {
+ return uninterpreted_option_.size();
+}
+ void FieldOptions::clear_uninterpreted_option() {
+ uninterpreted_option_.Clear();
+}
+ const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.uninterpreted_option)
+ return uninterpreted_option_.Get(index);
+}
+ ::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldOptions.uninterpreted_option)
+ return uninterpreted_option_.Mutable(index);
+}
+ ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FieldOptions.uninterpreted_option)
+ return uninterpreted_option_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+FieldOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option)
+ return uninterpreted_option_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+FieldOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldOptions.uninterpreted_option)
+ return &uninterpreted_option_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
#ifndef _MSC_VER
+const int EnumOptions::kAllowAliasFieldNumber;
+const int EnumOptions::kDeprecatedFieldNumber;
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)
}
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)
}
void EnumOptions::SharedCtor() {
_cached_size_ = 0;
+ allow_alias_ = false;
+ deprecated_ = false;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
EnumOptions::~EnumOptions() {
+ // @@protoc_insertion_point(destructor:google.protobuf.EnumOptions)
SharedDtor();
}
@@ -5604,48 +9523,101 @@ const ::google::protobuf::Descriptor* EnumOptions::descriptor() {
}
const EnumOptions& EnumOptions::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
EnumOptions* EnumOptions::default_instance_ = NULL;
-EnumOptions* EnumOptions::New() const {
- return new EnumOptions;
+EnumOptions* EnumOptions::New(::google::protobuf::Arena* arena) const {
+ EnumOptions* n = new EnumOptions;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void EnumOptions::Clear() {
_extensions_.Clear();
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+ &reinterpret_cast<EnumOptions*>(16)->f)
+
+#define ZR_(first, last) do {\
+ ::memset(&first, 0,\
+ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+ ZR_(allow_alias_, deprecated_);
+
+#undef ZR_HELPER_
+#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 EnumOptions::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.EnumOptions)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional bool allow_alias = 2;
+ case 2: {
+ if (tag == 16) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &allow_alias_)));
+ set_has_allow_alias();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(24)) goto parse_deprecated;
+ break;
+ }
+
+ // optional bool deprecated = 3 [default = false];
+ case 3: {
+ if (tag == 24) {
+ parse_deprecated:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &deprecated_)));
+ set_has_deprecated();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+ break;
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 7994) {
parse_uninterpreted_option:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_uninterpreted_option()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
if ((8000u <= tag)) {
DO_(_extensions_.ParseField(tag, input, default_instance_,
@@ -5658,51 +9630,92 @@ bool EnumOptions::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.EnumOptions)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.EnumOptions)
+ return false;
#undef DO_
}
void EnumOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.EnumOptions)
+ // optional bool allow_alias = 2;
+ if (has_allow_alias()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->allow_alias(), output);
+ }
+
+ // optional bool deprecated = 3 [default = false];
+ if (has_deprecated()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->deprecated(), output);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.EnumOptions)
}
::google::protobuf::uint8* EnumOptions::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumOptions)
+ // optional bool allow_alias = 2;
+ if (has_allow_alias()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->allow_alias(), target);
+ }
+
+ // optional bool deprecated = 3 [default = false];
+ if (has_deprecated()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->deprecated(), target);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumOptions)
return target;
}
int EnumOptions::ByteSize() const {
int total_size = 0;
-
+
+ if (_has_bits_[0 / 32] & 3) {
+ // optional bool allow_alias = 2;
+ if (has_allow_alias()) {
+ total_size += 1 + 1;
+ }
+
+ // optional bool deprecated = 3 [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++) {
@@ -5710,10 +9723,10 @@ int EnumOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -5725,7 +9738,7 @@ int EnumOptions::ByteSize() const {
}
void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const EnumOptions* source =
::google::protobuf::internal::dynamic_cast_if_available<const EnumOptions*>(
&from);
@@ -5737,10 +9750,20 @@ void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) {
}
void EnumOptions::MergeFrom(const EnumOptions& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_allow_alias()) {
+ set_allow_alias(from.allow_alias());
+ }
+ if (from.has_deprecated()) {
+ set_deprecated(from.deprecated());
+ }
+ }
_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) {
@@ -5756,22 +9779,24 @@ void EnumOptions::CopyFrom(const EnumOptions& from) {
}
bool EnumOptions::IsInitialized() const {
-
- for (int i = 0; i < uninterpreted_option_size(); i++) {
- if (!this->uninterpreted_option(i).IsInitialized()) return false;
- }
-
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->uninterpreted_option())) return false;
+
if (!_extensions_.IsInitialized()) return false; return true;
}
void EnumOptions::Swap(EnumOptions* other) {
- if (other != this) {
- 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;
+ 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 {
@@ -5782,33 +9807,121 @@ void EnumOptions::Swap(EnumOptions* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EnumOptions
+
+// optional bool allow_alias = 2;
+ bool EnumOptions::has_allow_alias() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void EnumOptions::set_has_allow_alias() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void EnumOptions::clear_has_allow_alias() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void EnumOptions::clear_allow_alias() {
+ allow_alias_ = false;
+ clear_has_allow_alias();
+}
+ bool EnumOptions::allow_alias() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.allow_alias)
+ return allow_alias_;
+}
+ void EnumOptions::set_allow_alias(bool value) {
+ set_has_allow_alias();
+ allow_alias_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.allow_alias)
+}
+
+// optional bool deprecated = 3 [default = false];
+ bool EnumOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void EnumOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void EnumOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void EnumOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+ bool EnumOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.deprecated)
+ return deprecated_;
+}
+ void EnumOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ int EnumOptions::uninterpreted_option_size() const {
+ return uninterpreted_option_.size();
+}
+ void EnumOptions::clear_uninterpreted_option() {
+ uninterpreted_option_.Clear();
+}
+ const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.uninterpreted_option)
+ return uninterpreted_option_.Get(index);
+}
+ ::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumOptions.uninterpreted_option)
+ return uninterpreted_option_.Mutable(index);
+}
+ ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.EnumOptions.uninterpreted_option)
+ return uninterpreted_option_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+EnumOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option)
+ return uninterpreted_option_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+EnumOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumOptions.uninterpreted_option)
+ return &uninterpreted_option_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
#ifndef _MSC_VER
+const int EnumValueOptions::kDeprecatedFieldNumber;
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)
}
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)
}
void EnumValueOptions::SharedCtor() {
_cached_size_ = 0;
+ deprecated_ = false;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
EnumValueOptions::~EnumValueOptions() {
+ // @@protoc_insertion_point(destructor:google.protobuf.EnumValueOptions)
SharedDtor();
}
@@ -5828,48 +9941,74 @@ const ::google::protobuf::Descriptor* EnumValueOptions::descriptor() {
}
const EnumValueOptions& EnumValueOptions::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
EnumValueOptions* EnumValueOptions::default_instance_ = NULL;
-EnumValueOptions* EnumValueOptions::New() const {
- return new EnumValueOptions;
+EnumValueOptions* EnumValueOptions::New(::google::protobuf::Arena* arena) const {
+ EnumValueOptions* n = new EnumValueOptions;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void EnumValueOptions::Clear() {
_extensions_.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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.EnumValueOptions)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional bool deprecated = 1 [default = false];
+ case 1: {
+ if (tag == 8) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &deprecated_)));
+ set_has_deprecated();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+ break;
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 7994) {
parse_uninterpreted_option:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_uninterpreted_option()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
if ((8000u <= tag)) {
DO_(_extensions_.ParseField(tag, input, default_instance_,
@@ -5882,51 +10021,75 @@ bool EnumValueOptions::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.EnumValueOptions)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.EnumValueOptions)
+ return false;
#undef DO_
}
void EnumValueOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.EnumValueOptions)
+ // optional bool deprecated = 1 [default = false];
+ if (has_deprecated()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->deprecated(), output);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.EnumValueOptions)
}
::google::protobuf::uint8* EnumValueOptions::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueOptions)
+ // optional bool deprecated = 1 [default = false];
+ if (has_deprecated()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(1, this->deprecated(), target);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueOptions)
return target;
}
int EnumValueOptions::ByteSize() const {
int total_size = 0;
-
+
+ // 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++) {
@@ -5934,10 +10097,10 @@ int EnumValueOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -5949,7 +10112,7 @@ int EnumValueOptions::ByteSize() const {
}
void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const EnumValueOptions* source =
::google::protobuf::internal::dynamic_cast_if_available<const EnumValueOptions*>(
&from);
@@ -5961,10 +10124,17 @@ void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) {
}
void EnumValueOptions::MergeFrom(const EnumValueOptions& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_deprecated()) {
+ set_deprecated(from.deprecated());
+ }
+ }
_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) {
@@ -5980,22 +10150,23 @@ void EnumValueOptions::CopyFrom(const EnumValueOptions& from) {
}
bool EnumValueOptions::IsInitialized() const {
-
- for (int i = 0; i < uninterpreted_option_size(); i++) {
- if (!this->uninterpreted_option(i).IsInitialized()) return false;
- }
-
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->uninterpreted_option())) return false;
+
if (!_extensions_.IsInitialized()) return false; return true;
}
void EnumValueOptions::Swap(EnumValueOptions* other) {
- if (other != this) {
- 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;
+ 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 {
@@ -6006,33 +10177,97 @@ void EnumValueOptions::Swap(EnumValueOptions* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EnumValueOptions
+
+// optional bool deprecated = 1 [default = false];
+ bool EnumValueOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void EnumValueOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void EnumValueOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void EnumValueOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+ bool EnumValueOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.deprecated)
+ return deprecated_;
+}
+ void EnumValueOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumValueOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ int EnumValueOptions::uninterpreted_option_size() const {
+ return uninterpreted_option_.size();
+}
+ void EnumValueOptions::clear_uninterpreted_option() {
+ uninterpreted_option_.Clear();
+}
+ const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.uninterpreted_option)
+ return uninterpreted_option_.Get(index);
+}
+ ::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueOptions.uninterpreted_option)
+ return uninterpreted_option_.Mutable(index);
+}
+ ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.EnumValueOptions.uninterpreted_option)
+ return uninterpreted_option_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+EnumValueOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option)
+ return uninterpreted_option_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+EnumValueOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValueOptions.uninterpreted_option)
+ return &uninterpreted_option_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
#ifndef _MSC_VER
+const int ServiceOptions::kDeprecatedFieldNumber;
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)
}
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)
}
void ServiceOptions::SharedCtor() {
_cached_size_ = 0;
+ deprecated_ = false;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
ServiceOptions::~ServiceOptions() {
+ // @@protoc_insertion_point(destructor:google.protobuf.ServiceOptions)
SharedDtor();
}
@@ -6052,48 +10287,74 @@ const ::google::protobuf::Descriptor* ServiceOptions::descriptor() {
}
const ServiceOptions& ServiceOptions::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
ServiceOptions* ServiceOptions::default_instance_ = NULL;
-ServiceOptions* ServiceOptions::New() const {
- return new ServiceOptions;
+ServiceOptions* ServiceOptions::New(::google::protobuf::Arena* arena) const {
+ ServiceOptions* n = new ServiceOptions;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void ServiceOptions::Clear() {
_extensions_.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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.ServiceOptions)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional bool deprecated = 33 [default = false];
+ case 33: {
+ if (tag == 264) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &deprecated_)));
+ set_has_deprecated();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+ break;
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 7994) {
parse_uninterpreted_option:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_uninterpreted_option()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
if ((8000u <= tag)) {
DO_(_extensions_.ParseField(tag, input, default_instance_,
@@ -6106,51 +10367,75 @@ bool ServiceOptions::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.ServiceOptions)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.ServiceOptions)
+ return false;
#undef DO_
}
void ServiceOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.ServiceOptions)
+ // optional bool deprecated = 33 [default = false];
+ if (has_deprecated()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(33, this->deprecated(), output);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.ServiceOptions)
}
::google::protobuf::uint8* ServiceOptions::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceOptions)
+ // optional bool deprecated = 33 [default = false];
+ if (has_deprecated()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(33, this->deprecated(), target);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceOptions)
return target;
}
int ServiceOptions::ByteSize() const {
int total_size = 0;
-
+
+ // 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++) {
@@ -6158,10 +10443,10 @@ int ServiceOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -6173,7 +10458,7 @@ int ServiceOptions::ByteSize() const {
}
void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const ServiceOptions* source =
::google::protobuf::internal::dynamic_cast_if_available<const ServiceOptions*>(
&from);
@@ -6185,10 +10470,17 @@ void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) {
}
void ServiceOptions::MergeFrom(const ServiceOptions& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_deprecated()) {
+ set_deprecated(from.deprecated());
+ }
+ }
_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) {
@@ -6204,22 +10496,23 @@ void ServiceOptions::CopyFrom(const ServiceOptions& from) {
}
bool ServiceOptions::IsInitialized() const {
-
- for (int i = 0; i < uninterpreted_option_size(); i++) {
- if (!this->uninterpreted_option(i).IsInitialized()) return false;
- }
-
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->uninterpreted_option())) return false;
+
if (!_extensions_.IsInitialized()) return false; return true;
}
void ServiceOptions::Swap(ServiceOptions* other) {
- if (other != this) {
- 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;
+ 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 {
@@ -6230,33 +10523,97 @@ void ServiceOptions::Swap(ServiceOptions* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ServiceOptions
+
+// optional bool deprecated = 33 [default = false];
+ bool ServiceOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void ServiceOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void ServiceOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void ServiceOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+ bool ServiceOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.deprecated)
+ return deprecated_;
+}
+ void ServiceOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.ServiceOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ int ServiceOptions::uninterpreted_option_size() const {
+ return uninterpreted_option_.size();
+}
+ void ServiceOptions::clear_uninterpreted_option() {
+ uninterpreted_option_.Clear();
+}
+ const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.uninterpreted_option)
+ return uninterpreted_option_.Get(index);
+}
+ ::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceOptions.uninterpreted_option)
+ return uninterpreted_option_.Mutable(index);
+}
+ ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.ServiceOptions.uninterpreted_option)
+ return uninterpreted_option_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ServiceOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option)
+ return uninterpreted_option_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ServiceOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceOptions.uninterpreted_option)
+ return &uninterpreted_option_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
#ifndef _MSC_VER
+const int MethodOptions::kDeprecatedFieldNumber;
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)
}
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)
}
void MethodOptions::SharedCtor() {
_cached_size_ = 0;
+ deprecated_ = false;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
MethodOptions::~MethodOptions() {
+ // @@protoc_insertion_point(destructor:google.protobuf.MethodOptions)
SharedDtor();
}
@@ -6276,48 +10633,74 @@ const ::google::protobuf::Descriptor* MethodOptions::descriptor() {
}
const MethodOptions& MethodOptions::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
MethodOptions* MethodOptions::default_instance_ = NULL;
-MethodOptions* MethodOptions::New() const {
- return new MethodOptions;
+MethodOptions* MethodOptions::New(::google::protobuf::Arena* arena) const {
+ MethodOptions* n = new MethodOptions;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void MethodOptions::Clear() {
_extensions_.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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.MethodOptions)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional bool deprecated = 33 [default = false];
+ case 33: {
+ if (tag == 264) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &deprecated_)));
+ set_has_deprecated();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+ break;
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
case 999: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 7994) {
parse_uninterpreted_option:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_uninterpreted_option()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
if ((8000u <= tag)) {
DO_(_extensions_.ParseField(tag, input, default_instance_,
@@ -6330,51 +10713,75 @@ bool MethodOptions::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.MethodOptions)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.MethodOptions)
+ return false;
#undef DO_
}
void MethodOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.MethodOptions)
+ // optional bool deprecated = 33 [default = false];
+ if (has_deprecated()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(33, this->deprecated(), output);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
999, this->uninterpreted_option(i), output);
}
-
+
// Extension range [1000, 536870912)
_extensions_.SerializeWithCachedSizes(
1000, 536870912, output);
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.MethodOptions)
}
::google::protobuf::uint8* MethodOptions::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodOptions)
+ // optional bool deprecated = 33 [default = false];
+ if (has_deprecated()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(33, this->deprecated(), target);
+ }
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
999, this->uninterpreted_option(i), target);
}
-
+
// Extension range [1000, 536870912)
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodOptions)
return target;
}
int MethodOptions::ByteSize() const {
int total_size = 0;
-
+
+ // 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++) {
@@ -6382,10 +10789,10 @@ int MethodOptions::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->uninterpreted_option(i));
}
-
+
total_size += _extensions_.ByteSize();
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -6397,7 +10804,7 @@ int MethodOptions::ByteSize() const {
}
void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const MethodOptions* source =
::google::protobuf::internal::dynamic_cast_if_available<const MethodOptions*>(
&from);
@@ -6409,10 +10816,17 @@ void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) {
}
void MethodOptions::MergeFrom(const MethodOptions& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_deprecated()) {
+ set_deprecated(from.deprecated());
+ }
+ }
_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) {
@@ -6428,22 +10842,23 @@ void MethodOptions::CopyFrom(const MethodOptions& from) {
}
bool MethodOptions::IsInitialized() const {
-
- for (int i = 0; i < uninterpreted_option_size(); i++) {
- if (!this->uninterpreted_option(i).IsInitialized()) return false;
- }
-
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->uninterpreted_option())) return false;
+
if (!_extensions_.IsInitialized()) return false; return true;
}
void MethodOptions::Swap(MethodOptions* other) {
- if (other != this) {
- 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;
+ 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 {
@@ -6454,6 +10869,64 @@ void MethodOptions::Swap(MethodOptions* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MethodOptions
+
+// optional bool deprecated = 33 [default = false];
+ bool MethodOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void MethodOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void MethodOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void MethodOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+ bool MethodOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.deprecated)
+ return deprecated_;
+}
+ void MethodOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MethodOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ int MethodOptions::uninterpreted_option_size() const {
+ return uninterpreted_option_.size();
+}
+ void MethodOptions::clear_uninterpreted_option() {
+ uninterpreted_option_.Clear();
+}
+ const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.uninterpreted_option)
+ return uninterpreted_option_.Get(index);
+}
+ ::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodOptions.uninterpreted_option)
+ return uninterpreted_option_.Mutable(index);
+}
+ ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.MethodOptions.uninterpreted_option)
+ return uninterpreted_option_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+MethodOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option)
+ return uninterpreted_option_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+MethodOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.MethodOptions.uninterpreted_option)
+ return &uninterpreted_option_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -6463,34 +10936,37 @@ 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)
}
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)
}
void UninterpretedOption_NamePart::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ name_part_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
is_extension_ = false;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
UninterpretedOption_NamePart::~UninterpretedOption_NamePart() {
+ // @@protoc_insertion_point(destructor:google.protobuf.UninterpretedOption.NamePart)
SharedDtor();
}
void UninterpretedOption_NamePart::SharedDtor() {
- if (name_part_ != &::google::protobuf::internal::kEmptyString) {
- delete name_part_;
- }
+ name_part_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
}
}
@@ -6506,71 +10982,80 @@ const ::google::protobuf::Descriptor* UninterpretedOption_NamePart::descriptor()
}
const UninterpretedOption_NamePart& UninterpretedOption_NamePart::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
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 {
+ UninterpretedOption_NamePart* n = new UninterpretedOption_NamePart;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void UninterpretedOption_NamePart::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bits_[0 / 32] & 3) {
if (has_name_part()) {
- if (name_part_ != &::google::protobuf::internal::kEmptyString) {
- name_part_->clear();
- }
+ name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.UninterpretedOption.NamePart)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// required string name_part = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name_part()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name_part().data(), this->name_part().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.UninterpretedOption.NamePart.name_part");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(16)) goto parse_is_extension;
break;
}
-
+
// required bool is_extension = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 16) {
parse_is_extension:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
input, &is_extension_)));
set_has_is_extension();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -6578,74 +11063,100 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.UninterpretedOption.NamePart)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.UninterpretedOption.NamePart)
+ return false;
#undef DO_
}
void UninterpretedOption_NamePart::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.UninterpretedOption.NamePart)
// required string name_part = 1;
if (has_name_part()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name_part().data(), this->name_part().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.UninterpretedOption.NamePart.name_part");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->name_part(), output);
}
-
+
// required bool is_extension = 2;
if (has_is_extension()) {
::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);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.UninterpretedOption.NamePart)
}
::google::protobuf::uint8* UninterpretedOption_NamePart::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption.NamePart)
// required string name_part = 1;
if (has_name_part()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name_part().data(), this->name_part().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.UninterpretedOption.NamePart.name_part");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->name_part(), target);
}
-
+
// required bool is_extension = 2;
if (has_is_extension()) {
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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption.NamePart)
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());
@@ -6657,7 +11168,7 @@ int UninterpretedOption_NamePart::ByteSize() const {
}
void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const UninterpretedOption_NamePart* source =
::google::protobuf::internal::dynamic_cast_if_available<const UninterpretedOption_NamePart*>(
&from);
@@ -6669,16 +11180,19 @@ void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message&
}
void UninterpretedOption_NamePart::MergeFrom(const UninterpretedOption_NamePart& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_name_part()) {
- set_name_part(from.name_part());
+ set_has_name_part();
+ name_part_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_part_);
}
if (from.has_is_extension()) {
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) {
@@ -6695,18 +11209,20 @@ void UninterpretedOption_NamePart::CopyFrom(const UninterpretedOption_NamePart&
bool UninterpretedOption_NamePart::IsInitialized() const {
if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false;
-
+
return true;
}
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;
+ 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 {
@@ -6731,44 +11247,43 @@ 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)
}
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)
}
void UninterpretedOption::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
- identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ 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::kEmptyString);
- aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ aggregate_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
UninterpretedOption::~UninterpretedOption() {
+ // @@protoc_insertion_point(destructor:google.protobuf.UninterpretedOption)
SharedDtor();
}
void UninterpretedOption::SharedDtor() {
- if (identifier_value_ != &::google::protobuf::internal::kEmptyString) {
- delete identifier_value_;
- }
- if (string_value_ != &::google::protobuf::internal::kEmptyString) {
- delete string_value_;
- }
- if (aggregate_value_ != &::google::protobuf::internal::kEmptyString) {
- delete aggregate_value_;
- }
+ identifier_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ string_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ aggregate_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
}
}
@@ -6784,163 +11299,174 @@ const ::google::protobuf::Descriptor* UninterpretedOption::descriptor() {
}
const UninterpretedOption& UninterpretedOption::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
UninterpretedOption* UninterpretedOption::default_instance_ = NULL;
-UninterpretedOption* UninterpretedOption::New() const {
- return new UninterpretedOption;
+UninterpretedOption* UninterpretedOption::New(::google::protobuf::Arena* arena) const {
+ UninterpretedOption* n = new UninterpretedOption;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void UninterpretedOption::Clear() {
- if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+ &reinterpret_cast<UninterpretedOption*>(16)->f)
+
+#define ZR_(first, last) do {\
+ ::memset(&first, 0,\
+ ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+ if (_has_bits_[0 / 32] & 126) {
+ ZR_(positive_int_value_, double_value_);
if (has_identifier_value()) {
- if (identifier_value_ != &::google::protobuf::internal::kEmptyString) {
- identifier_value_->clear();
- }
+ identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
- positive_int_value_ = GOOGLE_ULONGLONG(0);
- negative_int_value_ = GOOGLE_LONGLONG(0);
- double_value_ = 0;
if (has_string_value()) {
- if (string_value_ != &::google::protobuf::internal::kEmptyString) {
- string_value_->clear();
- }
+ string_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_aggregate_value()) {
- if (aggregate_value_ != &::google::protobuf::internal::kEmptyString) {
- aggregate_value_->clear();
- }
+ aggregate_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
}
+
+#undef ZR_HELPER_
+#undef ZR_
+
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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.UninterpretedOption)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_name:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_name()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_name;
if (input->ExpectTag(26)) goto parse_identifier_value;
break;
}
-
+
// optional string identifier_value = 3;
case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 26) {
parse_identifier_value:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_identifier_value()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->identifier_value().data(), this->identifier_value().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.UninterpretedOption.identifier_value");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(32)) goto parse_positive_int_value;
break;
}
-
+
// optional uint64 positive_int_value = 4;
case 4: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 32) {
parse_positive_int_value:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
input, &positive_int_value_)));
set_has_positive_int_value();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(40)) goto parse_negative_int_value;
break;
}
-
+
// optional int64 negative_int_value = 5;
case 5: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ if (tag == 40) {
parse_negative_int_value:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
input, &negative_int_value_)));
set_has_negative_int_value();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(49)) goto parse_double_value;
break;
}
-
+
// optional double double_value = 6;
case 6: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED64) {
+ if (tag == 49) {
parse_double_value:
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
input, &double_value_)));
set_has_double_value();
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(58)) goto parse_string_value;
break;
}
-
+
// optional bytes string_value = 7;
case 7: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 58) {
parse_string_value:
DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
input, this->mutable_string_value()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(66)) goto parse_aggregate_value;
break;
}
-
+
// optional string aggregate_value = 8;
case 8: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 66) {
parse_aggregate_value:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_aggregate_value()));
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->aggregate_value().data(), this->aggregate_value().length(),
- ::google::protobuf::internal::WireFormat::PARSE);
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.UninterpretedOption.aggregate_value");
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -6948,165 +11474,178 @@ bool UninterpretedOption::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.UninterpretedOption)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.UninterpretedOption)
+ return false;
#undef DO_
}
void UninterpretedOption::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.UninterpretedOption)
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
- for (int i = 0; i < this->name_size(); i++) {
+ for (unsigned int i = 0, n = this->name_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
2, this->name(i), output);
}
-
+
// optional string identifier_value = 3;
if (has_identifier_value()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->identifier_value().data(), this->identifier_value().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.UninterpretedOption.identifier_value");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
3, this->identifier_value(), output);
}
-
+
// optional uint64 positive_int_value = 4;
if (has_positive_int_value()) {
::google::protobuf::internal::WireFormatLite::WriteUInt64(4, this->positive_int_value(), output);
}
-
+
// optional int64 negative_int_value = 5;
if (has_negative_int_value()) {
::google::protobuf::internal::WireFormatLite::WriteInt64(5, this->negative_int_value(), output);
}
-
+
// optional double double_value = 6;
if (has_double_value()) {
::google::protobuf::internal::WireFormatLite::WriteDouble(6, this->double_value(), output);
}
-
+
// optional bytes string_value = 7;
if (has_string_value()) {
- ::google::protobuf::internal::WireFormatLite::WriteBytes(
+ ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
7, this->string_value(), output);
}
-
+
// optional string aggregate_value = 8;
if (has_aggregate_value()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->aggregate_value().data(), this->aggregate_value().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
- ::google::protobuf::internal::WireFormatLite::WriteString(
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "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);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.UninterpretedOption)
}
::google::protobuf::uint8* UninterpretedOption::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption)
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
- for (int i = 0; i < this->name_size(); i++) {
+ for (unsigned int i = 0, n = this->name_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
2, this->name(i), target);
}
-
+
// optional string identifier_value = 3;
if (has_identifier_value()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->identifier_value().data(), this->identifier_value().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.UninterpretedOption.identifier_value");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
3, this->identifier_value(), target);
}
-
+
// optional uint64 positive_int_value = 4;
if (has_positive_int_value()) {
target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(4, this->positive_int_value(), target);
}
-
+
// optional int64 negative_int_value = 5;
if (has_negative_int_value()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(5, this->negative_int_value(), target);
}
-
+
// optional double double_value = 6;
if (has_double_value()) {
target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(6, this->double_value(), target);
}
-
+
// optional bytes string_value = 7;
if (has_string_value()) {
target =
::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
7, this->string_value(), target);
}
-
+
// optional string aggregate_value = 8;
if (has_aggregate_value()) {
- ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->aggregate_value().data(), this->aggregate_value().length(),
- ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "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);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption)
return target;
}
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 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->identifier_value());
}
-
+
// optional uint64 positive_int_value = 4;
if (has_positive_int_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::UInt64Size(
this->positive_int_value());
}
-
+
// optional int64 negative_int_value = 5;
if (has_negative_int_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int64Size(
this->negative_int_value());
}
-
+
// optional double double_value = 6;
if (has_double_value()) {
total_size += 1 + 8;
}
-
+
// optional bytes string_value = 7;
if (has_string_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::BytesSize(
this->string_value());
}
-
+
// optional string aggregate_value = 8;
if (has_aggregate_value()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->aggregate_value());
}
-
+
}
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
total_size += 1 * this->name_size();
@@ -7115,8 +11654,8 @@ int UninterpretedOption::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->name(i));
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -7128,7 +11667,7 @@ int UninterpretedOption::ByteSize() const {
}
void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const UninterpretedOption* source =
::google::protobuf::internal::dynamic_cast_if_available<const UninterpretedOption*>(
&from);
@@ -7140,11 +11679,12 @@ void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) {
}
void UninterpretedOption::MergeFrom(const UninterpretedOption& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
name_.MergeFrom(from.name_);
if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
if (from.has_identifier_value()) {
- set_identifier_value(from.identifier_value());
+ set_has_identifier_value();
+ identifier_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.identifier_value_);
}
if (from.has_positive_int_value()) {
set_positive_int_value(from.positive_int_value());
@@ -7156,13 +11696,17 @@ void UninterpretedOption::MergeFrom(const UninterpretedOption& from) {
set_double_value(from.double_value());
}
if (from.has_string_value()) {
- set_string_value(from.string_value());
+ set_has_string_value();
+ string_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.string_value_);
}
if (from.has_aggregate_value()) {
- set_aggregate_value(from.aggregate_value());
+ set_has_aggregate_value();
+ aggregate_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 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) {
@@ -7178,26 +11722,26 @@ void UninterpretedOption::CopyFrom(const UninterpretedOption& from) {
}
bool UninterpretedOption::IsInitialized() const {
-
- for (int i = 0; i < name_size(); i++) {
- if (!this->name(i).IsInitialized()) return false;
- }
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->name())) return false;
return true;
}
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;
+ 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 {
@@ -7208,38 +11752,396 @@ void UninterpretedOption::Swap(UninterpretedOption* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// UninterpretedOption_NamePart
+
+// required string name_part = 1;
+ bool UninterpretedOption_NamePart::has_name_part() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void UninterpretedOption_NamePart::set_has_name_part() {
+ _has_bits_[0] |= 0x00000001u;
+}
+ void UninterpretedOption_NamePart::clear_has_name_part() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+ void UninterpretedOption_NamePart::clear_name_part() {
+ name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name_part();
+}
+ const ::std::string& UninterpretedOption_NamePart::name_part() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.name_part)
+ return name_part_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption_NamePart::set_name_part(const ::std::string& value) {
+ set_has_name_part();
+ name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+ void UninterpretedOption_NamePart::set_name_part(const char* value) {
+ set_has_name_part();
+ name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+ void UninterpretedOption_NamePart::set_name_part(const char* value, size_t size) {
+ set_has_name_part();
+ name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+ ::std::string* UninterpretedOption_NamePart::mutable_name_part() {
+ set_has_name_part();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.NamePart.name_part)
+ return name_part_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* UninterpretedOption_NamePart::release_name_part() {
+ clear_has_name_part();
+ return name_part_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption_NamePart::set_allocated_name_part(::std::string* name_part) {
+ if (name_part != NULL) {
+ set_has_name_part();
+ } else {
+ clear_has_name_part();
+ }
+ name_part_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name_part);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+
+// required bool is_extension = 2;
+ bool UninterpretedOption_NamePart::has_is_extension() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void UninterpretedOption_NamePart::set_has_is_extension() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void UninterpretedOption_NamePart::clear_has_is_extension() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void UninterpretedOption_NamePart::clear_is_extension() {
+ is_extension_ = false;
+ clear_has_is_extension();
+}
+ bool UninterpretedOption_NamePart::is_extension() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.is_extension)
+ return is_extension_;
+}
+ void UninterpretedOption_NamePart::set_is_extension(bool value) {
+ set_has_is_extension();
+ is_extension_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.is_extension)
+}
+
+// -------------------------------------------------------------------
+
+// UninterpretedOption
+
+// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+ int UninterpretedOption::name_size() const {
+ return name_.size();
+}
+ void UninterpretedOption::clear_name() {
+ name_.Clear();
+}
+ const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.name)
+ return name_.Get(index);
+}
+ ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mutable_name(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.name)
+ return name_.Mutable(index);
+}
+ ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() {
+ // @@protoc_insertion_point(field_add:google.protobuf.UninterpretedOption.name)
+ return name_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
+UninterpretedOption::name() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name)
+ return name_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
+UninterpretedOption::mutable_name() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.UninterpretedOption.name)
+ return &name_;
+}
+
+// optional string identifier_value = 3;
+ bool UninterpretedOption::has_identifier_value() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void UninterpretedOption::set_has_identifier_value() {
+ _has_bits_[0] |= 0x00000002u;
+}
+ void UninterpretedOption::clear_has_identifier_value() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+ void UninterpretedOption::clear_identifier_value() {
+ identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_identifier_value();
+}
+ const ::std::string& UninterpretedOption::identifier_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.identifier_value)
+ return identifier_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_identifier_value(const ::std::string& value) {
+ set_has_identifier_value();
+ identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.identifier_value)
+}
+ void UninterpretedOption::set_identifier_value(const char* value) {
+ set_has_identifier_value();
+ identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.identifier_value)
+}
+ void UninterpretedOption::set_identifier_value(const char* value, size_t size) {
+ set_has_identifier_value();
+ identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.identifier_value)
+}
+ ::std::string* UninterpretedOption::mutable_identifier_value() {
+ set_has_identifier_value();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.identifier_value)
+ return identifier_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* UninterpretedOption::release_identifier_value() {
+ clear_has_identifier_value();
+ return identifier_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_allocated_identifier_value(::std::string* identifier_value) {
+ if (identifier_value != NULL) {
+ set_has_identifier_value();
+ } else {
+ clear_has_identifier_value();
+ }
+ identifier_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), identifier_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.identifier_value)
+}
+
+// optional uint64 positive_int_value = 4;
+ bool UninterpretedOption::has_positive_int_value() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void UninterpretedOption::set_has_positive_int_value() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void UninterpretedOption::clear_has_positive_int_value() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void UninterpretedOption::clear_positive_int_value() {
+ positive_int_value_ = GOOGLE_ULONGLONG(0);
+ clear_has_positive_int_value();
+}
+ ::google::protobuf::uint64 UninterpretedOption::positive_int_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.positive_int_value)
+ return positive_int_value_;
+}
+ void UninterpretedOption::set_positive_int_value(::google::protobuf::uint64 value) {
+ set_has_positive_int_value();
+ positive_int_value_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.positive_int_value)
+}
+
+// optional int64 negative_int_value = 5;
+ bool UninterpretedOption::has_negative_int_value() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+ void UninterpretedOption::set_has_negative_int_value() {
+ _has_bits_[0] |= 0x00000008u;
+}
+ void UninterpretedOption::clear_has_negative_int_value() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+ void UninterpretedOption::clear_negative_int_value() {
+ negative_int_value_ = GOOGLE_LONGLONG(0);
+ clear_has_negative_int_value();
+}
+ ::google::protobuf::int64 UninterpretedOption::negative_int_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.negative_int_value)
+ return negative_int_value_;
+}
+ void UninterpretedOption::set_negative_int_value(::google::protobuf::int64 value) {
+ set_has_negative_int_value();
+ negative_int_value_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.negative_int_value)
+}
+
+// optional double double_value = 6;
+ bool UninterpretedOption::has_double_value() const {
+ return (_has_bits_[0] & 0x00000010u) != 0;
+}
+ void UninterpretedOption::set_has_double_value() {
+ _has_bits_[0] |= 0x00000010u;
+}
+ void UninterpretedOption::clear_has_double_value() {
+ _has_bits_[0] &= ~0x00000010u;
+}
+ void UninterpretedOption::clear_double_value() {
+ double_value_ = 0;
+ clear_has_double_value();
+}
+ double UninterpretedOption::double_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.double_value)
+ return double_value_;
+}
+ void UninterpretedOption::set_double_value(double value) {
+ set_has_double_value();
+ double_value_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.double_value)
+}
+
+// optional bytes string_value = 7;
+ bool UninterpretedOption::has_string_value() const {
+ return (_has_bits_[0] & 0x00000020u) != 0;
+}
+ void UninterpretedOption::set_has_string_value() {
+ _has_bits_[0] |= 0x00000020u;
+}
+ void UninterpretedOption::clear_has_string_value() {
+ _has_bits_[0] &= ~0x00000020u;
+}
+ void UninterpretedOption::clear_string_value() {
+ string_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_string_value();
+}
+ const ::std::string& UninterpretedOption::string_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.string_value)
+ return string_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_string_value(const ::std::string& value) {
+ set_has_string_value();
+ string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.string_value)
+}
+ void UninterpretedOption::set_string_value(const char* value) {
+ set_has_string_value();
+ string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.string_value)
+}
+ void UninterpretedOption::set_string_value(const void* value, size_t size) {
+ set_has_string_value();
+ string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.string_value)
+}
+ ::std::string* UninterpretedOption::mutable_string_value() {
+ set_has_string_value();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.string_value)
+ return string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* UninterpretedOption::release_string_value() {
+ clear_has_string_value();
+ return string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_allocated_string_value(::std::string* string_value) {
+ if (string_value != NULL) {
+ set_has_string_value();
+ } else {
+ clear_has_string_value();
+ }
+ string_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), string_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.string_value)
+}
+
+// optional string aggregate_value = 8;
+ bool UninterpretedOption::has_aggregate_value() const {
+ return (_has_bits_[0] & 0x00000040u) != 0;
+}
+ void UninterpretedOption::set_has_aggregate_value() {
+ _has_bits_[0] |= 0x00000040u;
+}
+ void UninterpretedOption::clear_has_aggregate_value() {
+ _has_bits_[0] &= ~0x00000040u;
+}
+ void UninterpretedOption::clear_aggregate_value() {
+ aggregate_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_aggregate_value();
+}
+ const ::std::string& UninterpretedOption::aggregate_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.aggregate_value)
+ return aggregate_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_aggregate_value(const ::std::string& value) {
+ set_has_aggregate_value();
+ aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.aggregate_value)
+}
+ void UninterpretedOption::set_aggregate_value(const char* value) {
+ set_has_aggregate_value();
+ aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.aggregate_value)
+}
+ void UninterpretedOption::set_aggregate_value(const char* value, size_t size) {
+ set_has_aggregate_value();
+ aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.aggregate_value)
+}
+ ::std::string* UninterpretedOption::mutable_aggregate_value() {
+ set_has_aggregate_value();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.aggregate_value)
+ return aggregate_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* UninterpretedOption::release_aggregate_value() {
+ clear_has_aggregate_value();
+ return aggregate_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_allocated_aggregate_value(::std::string* aggregate_value) {
+ if (aggregate_value != NULL) {
+ set_has_aggregate_value();
+ } else {
+ clear_has_aggregate_value();
+ }
+ aggregate_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), aggregate_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.aggregate_value)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
#ifndef _MSC_VER
const int SourceCodeInfo_Location::kPathFieldNumber;
const int SourceCodeInfo_Location::kSpanFieldNumber;
+const int SourceCodeInfo_Location::kLeadingCommentsFieldNumber;
+const int SourceCodeInfo_Location::kTrailingCommentsFieldNumber;
+const int SourceCodeInfo_Location::kLeadingDetachedCommentsFieldNumber;
#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)
}
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)
}
void SourceCodeInfo_Location::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
+ leading_comments_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ trailing_comments_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
SourceCodeInfo_Location::~SourceCodeInfo_Location() {
+ // @@protoc_insertion_point(destructor:google.protobuf.SourceCodeInfo.Location)
SharedDtor();
}
void SourceCodeInfo_Location::SharedDtor() {
+ leading_comments_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ trailing_comments_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
}
}
@@ -7255,74 +12157,142 @@ const ::google::protobuf::Descriptor* SourceCodeInfo_Location::descriptor() {
}
const SourceCodeInfo_Location& SourceCodeInfo_Location::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *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 {
+ SourceCodeInfo_Location* n = new SourceCodeInfo_Location;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
void SourceCodeInfo_Location::Clear() {
+ if (_has_bits_[0 / 32] & 12) {
+ if (has_leading_comments()) {
+ leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ if (has_trailing_comments()) {
+ trailing_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ }
path_.Clear();
span_.Clear();
+ leading_detached_comments_.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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.SourceCodeInfo.Location)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// repeated int32 path = 1 [packed = true];
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
input, this->mutable_path())));
- } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)
- == ::google::protobuf::internal::WireFormatLite::
- WIRETYPE_VARINT) {
+ } else if (tag == 8) {
DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
1, 10, input, this->mutable_path())));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_span;
break;
}
-
+
// repeated int32 span = 2 [packed = true];
case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 18) {
parse_span:
DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
input, this->mutable_span())));
- } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)
- == ::google::protobuf::internal::WireFormatLite::
- WIRETYPE_VARINT) {
+ } else if (tag == 16) {
DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
1, 18, input, this->mutable_span())));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectTag(26)) goto parse_leading_comments;
break;
}
-
+
+ // optional string leading_comments = 3;
+ case 3: {
+ if (tag == 26) {
+ parse_leading_comments:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_leading_comments()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->leading_comments().data(), this->leading_comments().length(),
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.SourceCodeInfo.Location.leading_comments");
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(34)) goto parse_trailing_comments;
+ break;
+ }
+
+ // optional string trailing_comments = 4;
+ case 4: {
+ if (tag == 34) {
+ parse_trailing_comments:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_trailing_comments()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->trailing_comments().data(), this->trailing_comments().length(),
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.SourceCodeInfo.Location.trailing_comments");
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(50)) goto parse_leading_detached_comments;
+ break;
+ }
+
+ // repeated string leading_detached_comments = 6;
+ case 6: {
+ if (tag == 50) {
+ parse_leading_detached_comments:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->add_leading_detached_comments()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->leading_detached_comments(this->leading_detached_comments_size() - 1).data(),
+ this->leading_detached_comments(this->leading_detached_comments_size() - 1).length(),
+ ::google::protobuf::internal::WireFormat::PARSE,
+ "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(50)) goto parse_leading_detached_comments;
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -7330,12 +12300,18 @@ bool SourceCodeInfo_Location::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.SourceCodeInfo.Location)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.SourceCodeInfo.Location)
+ return false;
#undef DO_
}
void SourceCodeInfo_Location::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.SourceCodeInfo.Location)
// repeated int32 path = 1 [packed = true];
if (this->path_size() > 0) {
::google::protobuf::internal::WireFormatLite::WriteTag(1, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
@@ -7345,7 +12321,7 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
this->path(i), output);
}
-
+
// repeated int32 span = 2 [packed = true];
if (this->span_size() > 0) {
::google::protobuf::internal::WireFormatLite::WriteTag(2, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
@@ -7355,15 +12331,47 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
this->span(i), output);
}
-
- if (!unknown_fields().empty()) {
+
+ // optional string leading_comments = 3;
+ if (has_leading_comments()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->leading_comments().data(), this->leading_comments().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.SourceCodeInfo.Location.leading_comments");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 3, this->leading_comments(), output);
+ }
+
+ // optional string trailing_comments = 4;
+ if (has_trailing_comments()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->trailing_comments().data(), this->trailing_comments().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.SourceCodeInfo.Location.trailing_comments");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 4, this->trailing_comments(), output);
+ }
+
+ // repeated string leading_detached_comments = 6;
+ for (int i = 0; i < this->leading_detached_comments_size(); i++) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->leading_detached_comments(i).data(), this->leading_detached_comments(i).length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 6, this->leading_detached_comments(i), output);
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.SourceCodeInfo.Location)
}
::google::protobuf::uint8* SourceCodeInfo_Location::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo.Location)
// repeated int32 path = 1 [packed = true];
if (this->path_size() > 0) {
target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
@@ -7377,7 +12385,7 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
target = ::google::protobuf::internal::WireFormatLite::
WriteInt32NoTagToArray(this->path(i), target);
}
-
+
// repeated int32 span = 2 [packed = true];
if (this->span_size() > 0) {
target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
@@ -7391,17 +12399,66 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
target = ::google::protobuf::internal::WireFormatLite::
WriteInt32NoTagToArray(this->span(i), target);
}
-
- if (!unknown_fields().empty()) {
+
+ // optional string leading_comments = 3;
+ if (has_leading_comments()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->leading_comments().data(), this->leading_comments().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.SourceCodeInfo.Location.leading_comments");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 3, this->leading_comments(), target);
+ }
+
+ // optional string trailing_comments = 4;
+ if (has_trailing_comments()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->trailing_comments().data(), this->trailing_comments().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.SourceCodeInfo.Location.trailing_comments");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 4, this->trailing_comments(), target);
+ }
+
+ // repeated string leading_detached_comments = 6;
+ for (int i = 0; i < this->leading_detached_comments_size(); i++) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+ this->leading_detached_comments(i).data(), this->leading_detached_comments(i).length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE,
+ "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteStringToArray(6, this->leading_detached_comments(i), target);
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo.Location)
return target;
}
int SourceCodeInfo_Location::ByteSize() const {
int total_size = 0;
-
+
+ if (_has_bits_[2 / 32] & 12) {
+ // optional string leading_comments = 3;
+ if (has_leading_comments()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->leading_comments());
+ }
+
+ // optional string trailing_comments = 4;
+ if (has_trailing_comments()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->trailing_comments());
+ }
+
+ }
// repeated int32 path = 1 [packed = true];
{
int data_size = 0;
@@ -7413,10 +12470,12 @@ int SourceCodeInfo_Location::ByteSize() const {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
}
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_path_cached_byte_size_ = data_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
total_size += data_size;
}
-
+
// repeated int32 span = 2 [packed = true];
{
int data_size = 0;
@@ -7428,11 +12487,20 @@ int SourceCodeInfo_Location::ByteSize() const {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
}
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_span_cached_byte_size_ = data_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
total_size += data_size;
}
-
- if (!unknown_fields().empty()) {
+
+ // repeated string leading_detached_comments = 6;
+ total_size += 1 * this->leading_detached_comments_size();
+ for (int i = 0; i < this->leading_detached_comments_size(); i++) {
+ total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->leading_detached_comments(i));
+ }
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -7444,7 +12512,7 @@ int SourceCodeInfo_Location::ByteSize() const {
}
void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const SourceCodeInfo_Location* source =
::google::protobuf::internal::dynamic_cast_if_available<const SourceCodeInfo_Location*>(
&from);
@@ -7456,10 +12524,23 @@ void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from)
}
void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
path_.MergeFrom(from.path_);
span_.MergeFrom(from.span_);
- mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+ leading_detached_comments_.MergeFrom(from.leading_detached_comments_);
+ if (from._has_bits_[2 / 32] & (0xffu << (2 % 32))) {
+ if (from.has_leading_comments()) {
+ set_has_leading_comments();
+ leading_comments_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.leading_comments_);
+ }
+ if (from.has_trailing_comments()) {
+ set_has_trailing_comments();
+ trailing_comments_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.trailing_comments_);
+ }
+ }
+ if (from._internal_metadata_.have_unknown_fields()) {
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+ }
}
void SourceCodeInfo_Location::CopyFrom(const ::google::protobuf::Message& from) {
@@ -7475,18 +12556,23 @@ void SourceCodeInfo_Location::CopyFrom(const SourceCodeInfo_Location& from) {
}
bool SourceCodeInfo_Location::IsInitialized() const {
-
+
return true;
}
void SourceCodeInfo_Location::Swap(SourceCodeInfo_Location* other) {
- if (other != this) {
- path_.Swap(&other->path_);
- span_.Swap(&other->span_);
- 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;
+ 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_);
+ leading_detached_comments_.UnsafeArenaSwap(&other->leading_detached_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 {
@@ -7505,17 +12591,20 @@ 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)
}
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)
}
void SourceCodeInfo::SharedCtor() {
@@ -7524,6 +12613,7 @@ void SourceCodeInfo::SharedCtor() {
}
SourceCodeInfo::~SourceCodeInfo() {
+ // @@protoc_insertion_point(destructor:google.protobuf.SourceCodeInfo)
SharedDtor();
}
@@ -7543,47 +12633,58 @@ const ::google::protobuf::Descriptor* SourceCodeInfo::descriptor() {
}
const SourceCodeInfo& SourceCodeInfo::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_;
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
}
SourceCodeInfo* SourceCodeInfo::default_instance_ = NULL;
-SourceCodeInfo* SourceCodeInfo::New() const {
- return new SourceCodeInfo;
+SourceCodeInfo* SourceCodeInfo::New(::google::protobuf::Arena* arena) const {
+ SourceCodeInfo* n = new SourceCodeInfo;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
}
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(
::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
+ // @@protoc_insertion_point(parse_start:google.protobuf.SourceCodeInfo)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ if (tag == 10) {
parse_location:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_location()));
} else {
- goto handle_uninterpreted;
+ goto handle_unusual;
}
if (input->ExpectTag(10)) goto parse_location;
- if (input->ExpectAtEnd()) return true;
+ if (input->ExpectAtEnd()) goto success;
break;
}
-
+
default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
+ goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
@@ -7591,43 +12692,52 @@ bool SourceCodeInfo::MergePartialFromCodedStream(
}
}
}
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.SourceCodeInfo)
return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.SourceCodeInfo)
+ return false;
#undef DO_
}
void SourceCodeInfo::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.SourceCodeInfo)
// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
- for (int i = 0; i < this->location_size(); i++) {
+ for (unsigned int i = 0, n = this->location_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
1, this->location(i), output);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
+ // @@protoc_insertion_point(serialize_end:google.protobuf.SourceCodeInfo)
}
::google::protobuf::uint8* SourceCodeInfo::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo)
// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
- for (int i = 0; i < this->location_size(); i++) {
+ for (unsigned int i = 0, n = this->location_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
1, this->location(i), target);
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo)
return target;
}
int SourceCodeInfo::ByteSize() const {
int total_size = 0;
-
+
// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
total_size += 1 * this->location_size();
for (int i = 0; i < this->location_size(); i++) {
@@ -7635,8 +12745,8 @@ int SourceCodeInfo::ByteSize() const {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->location(i));
}
-
- if (!unknown_fields().empty()) {
+
+ if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
@@ -7648,7 +12758,7 @@ int SourceCodeInfo::ByteSize() const {
}
void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
const SourceCodeInfo* source =
::google::protobuf::internal::dynamic_cast_if_available<const SourceCodeInfo*>(
&from);
@@ -7660,9 +12770,11 @@ void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) {
}
void SourceCodeInfo::MergeFrom(const SourceCodeInfo& from) {
- GOOGLE_CHECK_NE(&from, this);
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
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) {
@@ -7678,17 +12790,19 @@ void SourceCodeInfo::CopyFrom(const SourceCodeInfo& from) {
}
bool SourceCodeInfo::IsInitialized() const {
-
+
return true;
}
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;
+ 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 {
@@ -7699,6 +12813,264 @@ void SourceCodeInfo::Swap(SourceCodeInfo* other) {
return metadata;
}
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// SourceCodeInfo_Location
+
+// repeated int32 path = 1 [packed = true];
+ int SourceCodeInfo_Location::path_size() const {
+ return path_.size();
+}
+ void SourceCodeInfo_Location::clear_path() {
+ path_.Clear();
+}
+ ::google::protobuf::int32 SourceCodeInfo_Location::path(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.path)
+ return path_.Get(index);
+}
+ void SourceCodeInfo_Location::set_path(int index, ::google::protobuf::int32 value) {
+ path_.Set(index, value);
+ // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.path)
+}
+ void SourceCodeInfo_Location::add_path(::google::protobuf::int32 value) {
+ path_.Add(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.path)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+SourceCodeInfo_Location::path() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.path)
+ return path_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+SourceCodeInfo_Location::mutable_path() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.path)
+ return &path_;
+}
+
+// repeated int32 span = 2 [packed = true];
+ int SourceCodeInfo_Location::span_size() const {
+ return span_.size();
+}
+ void SourceCodeInfo_Location::clear_span() {
+ span_.Clear();
+}
+ ::google::protobuf::int32 SourceCodeInfo_Location::span(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.span)
+ return span_.Get(index);
+}
+ void SourceCodeInfo_Location::set_span(int index, ::google::protobuf::int32 value) {
+ span_.Set(index, value);
+ // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.span)
+}
+ void SourceCodeInfo_Location::add_span(::google::protobuf::int32 value) {
+ span_.Add(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.span)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+SourceCodeInfo_Location::span() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.span)
+ return span_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+SourceCodeInfo_Location::mutable_span() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.span)
+ return &span_;
+}
+
+// optional string leading_comments = 3;
+ bool SourceCodeInfo_Location::has_leading_comments() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void SourceCodeInfo_Location::set_has_leading_comments() {
+ _has_bits_[0] |= 0x00000004u;
+}
+ void SourceCodeInfo_Location::clear_has_leading_comments() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+ void SourceCodeInfo_Location::clear_leading_comments() {
+ leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_leading_comments();
+}
+ const ::std::string& SourceCodeInfo_Location::leading_comments() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_comments)
+ return leading_comments_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceCodeInfo_Location::set_leading_comments(const ::std::string& value) {
+ set_has_leading_comments();
+ leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+ void SourceCodeInfo_Location::set_leading_comments(const char* value) {
+ set_has_leading_comments();
+ leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+ void SourceCodeInfo_Location::set_leading_comments(const char* value, size_t size) {
+ set_has_leading_comments();
+ leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+ ::std::string* SourceCodeInfo_Location::mutable_leading_comments() {
+ set_has_leading_comments();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_comments)
+ return leading_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* SourceCodeInfo_Location::release_leading_comments() {
+ clear_has_leading_comments();
+ return leading_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceCodeInfo_Location::set_allocated_leading_comments(::std::string* leading_comments) {
+ if (leading_comments != NULL) {
+ set_has_leading_comments();
+ } else {
+ clear_has_leading_comments();
+ }
+ leading_comments_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), leading_comments);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+
+// optional string trailing_comments = 4;
+ bool SourceCodeInfo_Location::has_trailing_comments() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+ void SourceCodeInfo_Location::set_has_trailing_comments() {
+ _has_bits_[0] |= 0x00000008u;
+}
+ void SourceCodeInfo_Location::clear_has_trailing_comments() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+ void SourceCodeInfo_Location::clear_trailing_comments() {
+ trailing_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_trailing_comments();
+}
+ const ::std::string& SourceCodeInfo_Location::trailing_comments() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+ return trailing_comments_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceCodeInfo_Location::set_trailing_comments(const ::std::string& value) {
+ set_has_trailing_comments();
+ trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+ void SourceCodeInfo_Location::set_trailing_comments(const char* value) {
+ set_has_trailing_comments();
+ trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+ void SourceCodeInfo_Location::set_trailing_comments(const char* value, size_t size) {
+ set_has_trailing_comments();
+ trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+ ::std::string* SourceCodeInfo_Location::mutable_trailing_comments() {
+ set_has_trailing_comments();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+ return trailing_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* SourceCodeInfo_Location::release_trailing_comments() {
+ clear_has_trailing_comments();
+ return trailing_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceCodeInfo_Location::set_allocated_trailing_comments(::std::string* trailing_comments) {
+ if (trailing_comments != NULL) {
+ set_has_trailing_comments();
+ } else {
+ clear_has_trailing_comments();
+ }
+ trailing_comments_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), trailing_comments);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+
+// repeated string leading_detached_comments = 6;
+ int SourceCodeInfo_Location::leading_detached_comments_size() const {
+ return leading_detached_comments_.size();
+}
+ void SourceCodeInfo_Location::clear_leading_detached_comments() {
+ leading_detached_comments_.Clear();
+}
+ const ::std::string& SourceCodeInfo_Location::leading_detached_comments(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ return leading_detached_comments_.Get(index);
+}
+ ::std::string* SourceCodeInfo_Location::mutable_leading_detached_comments(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ return leading_detached_comments_.Mutable(index);
+}
+ void SourceCodeInfo_Location::set_leading_detached_comments(int index, const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ leading_detached_comments_.Mutable(index)->assign(value);
+}
+ void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value) {
+ leading_detached_comments_.Mutable(index)->assign(value);
+ // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value, size_t size) {
+ leading_detached_comments_.Mutable(index)->assign(
+ reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ ::std::string* SourceCodeInfo_Location::add_leading_detached_comments() {
+ return leading_detached_comments_.Add();
+}
+ void SourceCodeInfo_Location::add_leading_detached_comments(const ::std::string& value) {
+ leading_detached_comments_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ void SourceCodeInfo_Location::add_leading_detached_comments(const char* value) {
+ leading_detached_comments_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ void SourceCodeInfo_Location::add_leading_detached_comments(const char* value, size_t size) {
+ leading_detached_comments_.Add()->assign(reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_add_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+SourceCodeInfo_Location::leading_detached_comments() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ return leading_detached_comments_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+SourceCodeInfo_Location::mutable_leading_detached_comments() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ return &leading_detached_comments_;
+}
+
+// -------------------------------------------------------------------
+
+// SourceCodeInfo
+
+// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+ int SourceCodeInfo::location_size() const {
+ return location_.size();
+}
+ void SourceCodeInfo::clear_location() {
+ location_.Clear();
+}
+ const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.location)
+ return location_.Get(index);
+}
+ ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::mutable_location(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.location)
+ return location_.Mutable(index);
+}
+ ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::add_location() {
+ // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.location)
+ return location_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
+SourceCodeInfo::location() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location)
+ return location_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
+SourceCodeInfo::mutable_location() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.location)
+ return &location_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 95febb81..d8cba659 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -8,21 +8,26 @@
#include <google/protobuf/stubs/common.h>
-#if GOOGLE_PROTOBUF_VERSION < 2004000
+#if GOOGLE_PROTOBUF_VERSION < 3000000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 2004001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
-#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
// @@protoc_insertion_point(includes)
namespace google {
@@ -38,6 +43,7 @@ class FileDescriptorProto;
class DescriptorProto;
class DescriptorProto_ExtensionRange;
class FieldDescriptorProto;
+class OneofDescriptorProto;
class EnumDescriptorProto;
class EnumValueDescriptorProto;
class ServiceDescriptorProto;
@@ -155,37 +161,39 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
public:
FileDescriptorSet();
virtual ~FileDescriptorSet();
-
+
FileDescriptorSet(const FileDescriptorSet& from);
-
+
inline FileDescriptorSet& operator=(const FileDescriptorSet& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FileDescriptorSet& default_instance();
-
+
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);
void MergeFrom(const FileDescriptorSet& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -197,40 +205,45 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(FileDescriptorSet* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// repeated .google.protobuf.FileDescriptorProto file = 1;
- inline int file_size() const;
- inline void clear_file();
+ int file_size() const;
+ void clear_file();
static const int kFileFieldNumber = 1;
- inline const ::google::protobuf::FileDescriptorProto& file(int index) const;
- inline ::google::protobuf::FileDescriptorProto* mutable_file(int index);
- inline ::google::protobuf::FileDescriptorProto* add_file();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+ const ::google::protobuf::FileDescriptorProto& file(int index) const;
+ ::google::protobuf::FileDescriptorProto* mutable_file(int index);
+ ::google::protobuf::FileDescriptorProto* add_file();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
file() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
mutable_file();
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet)
private:
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > file_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > file_;
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();
-
+
void InitAsDefaultInstance();
static FileDescriptorSet* default_instance_;
};
@@ -240,37 +253,39 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
public:
FileDescriptorProto();
virtual ~FileDescriptorProto();
-
+
FileDescriptorProto(const FileDescriptorProto& from);
-
+
inline FileDescriptorProto& operator=(const FileDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FileDescriptorProto& default_instance();
-
+
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);
void MergeFrom(const FileDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -282,116 +297,164 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(FileDescriptorProto* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
- inline bool has_name() const;
- inline void clear_name();
+ bool has_name() const;
+ void clear_name();
static const int kNameFieldNumber = 1;
- inline const ::std::string& name() const;
- inline void set_name(const ::std::string& value);
- inline void set_name(const char* value);
- inline void set_name(const char* value, size_t size);
- inline ::std::string* mutable_name();
- inline ::std::string* release_name();
-
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void set_allocated_name(::std::string* name);
+
// optional string package = 2;
- inline bool has_package() const;
- inline void clear_package();
+ bool has_package() const;
+ void clear_package();
static const int kPackageFieldNumber = 2;
- inline const ::std::string& package() const;
- inline void set_package(const ::std::string& value);
- inline void set_package(const char* value);
- inline void set_package(const char* value, size_t size);
- inline ::std::string* mutable_package();
- inline ::std::string* release_package();
-
+ const ::std::string& package() const;
+ void set_package(const ::std::string& value);
+ void set_package(const char* value);
+ void set_package(const char* value, size_t size);
+ ::std::string* mutable_package();
+ ::std::string* release_package();
+ void set_allocated_package(::std::string* package);
+
// repeated string dependency = 3;
- inline int dependency_size() const;
- inline void clear_dependency();
+ int dependency_size() const;
+ void clear_dependency();
static const int kDependencyFieldNumber = 3;
- inline const ::std::string& dependency(int index) const;
- inline ::std::string* mutable_dependency(int index);
- inline void set_dependency(int index, const ::std::string& value);
- inline void set_dependency(int index, const char* value);
- inline void set_dependency(int index, const char* value, size_t size);
- inline ::std::string* add_dependency();
- inline void add_dependency(const ::std::string& value);
- inline void add_dependency(const char* value);
- inline void add_dependency(const char* value, size_t size);
- inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const;
- inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency();
-
+ const ::std::string& dependency(int index) const;
+ ::std::string* mutable_dependency(int index);
+ void set_dependency(int index, const ::std::string& value);
+ void set_dependency(int index, const char* value);
+ void set_dependency(int index, const char* value, size_t size);
+ ::std::string* add_dependency();
+ void add_dependency(const ::std::string& value);
+ void add_dependency(const char* value);
+ void add_dependency(const char* value, size_t size);
+ const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const;
+ ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency();
+
+ // repeated int32 public_dependency = 10;
+ int public_dependency_size() const;
+ void clear_public_dependency();
+ static const int kPublicDependencyFieldNumber = 10;
+ ::google::protobuf::int32 public_dependency(int index) const;
+ void set_public_dependency(int index, ::google::protobuf::int32 value);
+ void add_public_dependency(::google::protobuf::int32 value);
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+ public_dependency() const;
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+ mutable_public_dependency();
+
+ // repeated int32 weak_dependency = 11;
+ int weak_dependency_size() const;
+ void clear_weak_dependency();
+ static const int kWeakDependencyFieldNumber = 11;
+ ::google::protobuf::int32 weak_dependency(int index) const;
+ void set_weak_dependency(int index, ::google::protobuf::int32 value);
+ void add_weak_dependency(::google::protobuf::int32 value);
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+ weak_dependency() const;
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+ mutable_weak_dependency();
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
- inline int message_type_size() const;
- inline void clear_message_type();
+ int message_type_size() const;
+ void clear_message_type();
static const int kMessageTypeFieldNumber = 4;
- inline const ::google::protobuf::DescriptorProto& message_type(int index) const;
- inline ::google::protobuf::DescriptorProto* mutable_message_type(int index);
- inline ::google::protobuf::DescriptorProto* add_message_type();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+ const ::google::protobuf::DescriptorProto& message_type(int index) const;
+ ::google::protobuf::DescriptorProto* mutable_message_type(int index);
+ ::google::protobuf::DescriptorProto* add_message_type();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
message_type() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
mutable_message_type();
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
- inline int enum_type_size() const;
- inline void clear_enum_type();
+ int enum_type_size() const;
+ void clear_enum_type();
static const int kEnumTypeFieldNumber = 5;
- inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
- inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
- inline ::google::protobuf::EnumDescriptorProto* add_enum_type();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+ const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
+ ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
+ ::google::protobuf::EnumDescriptorProto* add_enum_type();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
enum_type() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
mutable_enum_type();
-
+
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
- inline int service_size() const;
- inline void clear_service();
+ int service_size() const;
+ void clear_service();
static const int kServiceFieldNumber = 6;
- inline const ::google::protobuf::ServiceDescriptorProto& service(int index) const;
- inline ::google::protobuf::ServiceDescriptorProto* mutable_service(int index);
- inline ::google::protobuf::ServiceDescriptorProto* add_service();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
+ const ::google::protobuf::ServiceDescriptorProto& service(int index) const;
+ ::google::protobuf::ServiceDescriptorProto* mutable_service(int index);
+ ::google::protobuf::ServiceDescriptorProto* add_service();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
service() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
mutable_service();
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
- inline int extension_size() const;
- inline void clear_extension();
+ int extension_size() const;
+ void clear_extension();
static const int kExtensionFieldNumber = 7;
- inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
- inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
- inline ::google::protobuf::FieldDescriptorProto* add_extension();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+ const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
+ ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
+ ::google::protobuf::FieldDescriptorProto* add_extension();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
extension() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
mutable_extension();
-
+
// optional .google.protobuf.FileOptions options = 8;
- inline bool has_options() const;
- inline void clear_options();
+ bool has_options() const;
+ void clear_options();
static const int kOptionsFieldNumber = 8;
- inline const ::google::protobuf::FileOptions& options() const;
- inline ::google::protobuf::FileOptions* mutable_options();
- inline ::google::protobuf::FileOptions* release_options();
-
+ const ::google::protobuf::FileOptions& options() const;
+ ::google::protobuf::FileOptions* mutable_options();
+ ::google::protobuf::FileOptions* release_options();
+ void set_allocated_options(::google::protobuf::FileOptions* options);
+
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
- inline bool has_source_code_info() const;
- inline void clear_source_code_info();
+ bool has_source_code_info() const;
+ void clear_source_code_info();
static const int kSourceCodeInfoFieldNumber = 9;
- inline const ::google::protobuf::SourceCodeInfo& source_code_info() const;
- inline ::google::protobuf::SourceCodeInfo* mutable_source_code_info();
- inline ::google::protobuf::SourceCodeInfo* release_source_code_info();
-
+ const ::google::protobuf::SourceCodeInfo& source_code_info() const;
+ ::google::protobuf::SourceCodeInfo* mutable_source_code_info();
+ ::google::protobuf::SourceCodeInfo* release_source_code_info();
+ void set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info);
+
+ // optional string syntax = 12;
+ bool has_syntax() const;
+ void clear_syntax();
+ static const int kSyntaxFieldNumber = 12;
+ const ::std::string& syntax() const;
+ void set_syntax(const ::std::string& value);
+ void set_syntax(const char* value);
+ void set_syntax(const char* value, size_t size);
+ ::std::string* mutable_syntax();
+ ::std::string* release_syntax();
+ void set_allocated_syntax(::std::string* syntax);
+
// @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto)
private:
inline void set_has_name();
@@ -402,26 +465,28 @@ 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();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* name_;
- ::std::string* package_;
+ inline void set_has_syntax();
+ inline void clear_has_syntax();
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::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_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > message_type_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto > service_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_;
::google::protobuf::FileOptions* options_;
::google::protobuf::SourceCodeInfo* source_code_info_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(9 + 31) / 32];
-
+ ::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();
-
+
void InitAsDefaultInstance();
static FileDescriptorProto* default_instance_;
};
@@ -431,37 +496,39 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
public:
DescriptorProto_ExtensionRange();
virtual ~DescriptorProto_ExtensionRange();
-
+
DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from);
-
+
inline DescriptorProto_ExtensionRange& operator=(const DescriptorProto_ExtensionRange& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const DescriptorProto_ExtensionRange& default_instance();
-
+
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);
void MergeFrom(const DescriptorProto_ExtensionRange& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -473,47 +540,52 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(DescriptorProto_ExtensionRange* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional int32 start = 1;
- inline bool has_start() const;
- inline void clear_start();
+ bool has_start() const;
+ void clear_start();
static const int kStartFieldNumber = 1;
- inline ::google::protobuf::int32 start() const;
- inline void set_start(::google::protobuf::int32 value);
-
+ ::google::protobuf::int32 start() const;
+ void set_start(::google::protobuf::int32 value);
+
// optional int32 end = 2;
- inline bool has_end() const;
- inline void clear_end();
+ bool has_end() const;
+ void clear_end();
static const int kEndFieldNumber = 2;
- inline ::google::protobuf::int32 end() const;
- inline void set_end(::google::protobuf::int32 value);
-
+ ::google::protobuf::int32 end() const;
+ void set_end(::google::protobuf::int32 value);
+
// @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange)
private:
inline void set_has_start();
inline void clear_has_start();
inline void set_has_end();
inline void clear_has_end();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
::google::protobuf::int32 start_;
::google::protobuf::int32 end_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
-
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();
-
+
void InitAsDefaultInstance();
static DescriptorProto_ExtensionRange* default_instance_;
};
@@ -523,37 +595,39 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
public:
DescriptorProto();
virtual ~DescriptorProto();
-
+
DescriptorProto(const DescriptorProto& from);
-
+
inline DescriptorProto& operator=(const DescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const DescriptorProto& default_instance();
-
+
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);
void MergeFrom(const DescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -565,119 +639,139 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(DescriptorProto* other);
+ 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 ----------------------------------------------------
-
+
typedef DescriptorProto_ExtensionRange ExtensionRange;
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
- inline bool has_name() const;
- inline void clear_name();
+ bool has_name() const;
+ void clear_name();
static const int kNameFieldNumber = 1;
- inline const ::std::string& name() const;
- inline void set_name(const ::std::string& value);
- inline void set_name(const char* value);
- inline void set_name(const char* value, size_t size);
- inline ::std::string* mutable_name();
- inline ::std::string* release_name();
-
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void set_allocated_name(::std::string* name);
+
// repeated .google.protobuf.FieldDescriptorProto field = 2;
- inline int field_size() const;
- inline void clear_field();
+ int field_size() const;
+ void clear_field();
static const int kFieldFieldNumber = 2;
- inline const ::google::protobuf::FieldDescriptorProto& field(int index) const;
- inline ::google::protobuf::FieldDescriptorProto* mutable_field(int index);
- inline ::google::protobuf::FieldDescriptorProto* add_field();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+ const ::google::protobuf::FieldDescriptorProto& field(int index) const;
+ ::google::protobuf::FieldDescriptorProto* mutable_field(int index);
+ ::google::protobuf::FieldDescriptorProto* add_field();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
field() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
mutable_field();
-
+
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
- inline int extension_size() const;
- inline void clear_extension();
+ int extension_size() const;
+ void clear_extension();
static const int kExtensionFieldNumber = 6;
- inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
- inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
- inline ::google::protobuf::FieldDescriptorProto* add_extension();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+ const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
+ ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
+ ::google::protobuf::FieldDescriptorProto* add_extension();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
extension() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
mutable_extension();
-
+
// repeated .google.protobuf.DescriptorProto nested_type = 3;
- inline int nested_type_size() const;
- inline void clear_nested_type();
+ int nested_type_size() const;
+ void clear_nested_type();
static const int kNestedTypeFieldNumber = 3;
- inline const ::google::protobuf::DescriptorProto& nested_type(int index) const;
- inline ::google::protobuf::DescriptorProto* mutable_nested_type(int index);
- inline ::google::protobuf::DescriptorProto* add_nested_type();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+ const ::google::protobuf::DescriptorProto& nested_type(int index) const;
+ ::google::protobuf::DescriptorProto* mutable_nested_type(int index);
+ ::google::protobuf::DescriptorProto* add_nested_type();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
nested_type() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
mutable_nested_type();
-
+
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
- inline int enum_type_size() const;
- inline void clear_enum_type();
+ int enum_type_size() const;
+ void clear_enum_type();
static const int kEnumTypeFieldNumber = 4;
- inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
- inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
- inline ::google::protobuf::EnumDescriptorProto* add_enum_type();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+ const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
+ ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
+ ::google::protobuf::EnumDescriptorProto* add_enum_type();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
enum_type() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
mutable_enum_type();
-
+
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
- inline int extension_range_size() const;
- inline void clear_extension_range();
+ int extension_range_size() const;
+ void clear_extension_range();
static const int kExtensionRangeFieldNumber = 5;
- inline const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const;
- inline ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index);
- inline ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
+ const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const;
+ ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index);
+ ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
extension_range() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
mutable_extension_range();
-
+
+ // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+ int oneof_decl_size() const;
+ void clear_oneof_decl();
+ static const int kOneofDeclFieldNumber = 8;
+ const ::google::protobuf::OneofDescriptorProto& oneof_decl(int index) const;
+ ::google::protobuf::OneofDescriptorProto* mutable_oneof_decl(int index);
+ ::google::protobuf::OneofDescriptorProto* add_oneof_decl();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
+ oneof_decl() const;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >*
+ mutable_oneof_decl();
+
// optional .google.protobuf.MessageOptions options = 7;
- inline bool has_options() const;
- inline void clear_options();
+ bool has_options() const;
+ void clear_options();
static const int kOptionsFieldNumber = 7;
- inline const ::google::protobuf::MessageOptions& options() const;
- inline ::google::protobuf::MessageOptions* mutable_options();
- inline ::google::protobuf::MessageOptions* release_options();
-
+ const ::google::protobuf::MessageOptions& options() const;
+ ::google::protobuf::MessageOptions* mutable_options();
+ ::google::protobuf::MessageOptions* release_options();
+ void set_allocated_options(::google::protobuf::MessageOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto)
private:
inline void set_has_name();
inline void clear_has_name();
inline void set_has_options();
inline void clear_has_options();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* name_;
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::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_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange > extension_range_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto > oneof_decl_;
::google::protobuf::MessageOptions* options_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
-
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();
-
+
void InitAsDefaultInstance();
static DescriptorProto* default_instance_;
};
@@ -687,37 +781,39 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
public:
FieldDescriptorProto();
virtual ~FieldDescriptorProto();
-
+
FieldDescriptorProto(const FieldDescriptorProto& from);
-
+
inline FieldDescriptorProto& operator=(const FieldDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FieldDescriptorProto& default_instance();
-
+
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);
void MergeFrom(const FieldDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -729,12 +825,20 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(FieldDescriptorProto* other);
+ 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 ----------------------------------------------------
-
+
typedef FieldDescriptorProto_Type Type;
static const Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE;
static const Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT;
@@ -774,7 +878,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
Type* value) {
return FieldDescriptorProto_Type_Parse(name, value);
}
-
+
typedef FieldDescriptorProto_Label Label;
static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL;
static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED;
@@ -799,82 +903,94 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
Label* value) {
return FieldDescriptorProto_Label_Parse(name, value);
}
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
- inline bool has_name() const;
- inline void clear_name();
+ bool has_name() const;
+ void clear_name();
static const int kNameFieldNumber = 1;
- inline const ::std::string& name() const;
- inline void set_name(const ::std::string& value);
- inline void set_name(const char* value);
- inline void set_name(const char* value, size_t size);
- inline ::std::string* mutable_name();
- inline ::std::string* release_name();
-
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void set_allocated_name(::std::string* name);
+
// optional int32 number = 3;
- inline bool has_number() const;
- inline void clear_number();
+ bool has_number() const;
+ void clear_number();
static const int kNumberFieldNumber = 3;
- inline ::google::protobuf::int32 number() const;
- inline void set_number(::google::protobuf::int32 value);
-
+ ::google::protobuf::int32 number() const;
+ void set_number(::google::protobuf::int32 value);
+
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
- inline bool has_label() const;
- inline void clear_label();
+ bool has_label() const;
+ void clear_label();
static const int kLabelFieldNumber = 4;
- inline ::google::protobuf::FieldDescriptorProto_Label label() const;
- inline void set_label(::google::protobuf::FieldDescriptorProto_Label value);
-
+ ::google::protobuf::FieldDescriptorProto_Label label() const;
+ void set_label(::google::protobuf::FieldDescriptorProto_Label value);
+
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
- inline bool has_type() const;
- inline void clear_type();
+ bool has_type() const;
+ void clear_type();
static const int kTypeFieldNumber = 5;
- inline ::google::protobuf::FieldDescriptorProto_Type type() const;
- inline void set_type(::google::protobuf::FieldDescriptorProto_Type value);
-
+ ::google::protobuf::FieldDescriptorProto_Type type() const;
+ void set_type(::google::protobuf::FieldDescriptorProto_Type value);
+
// optional string type_name = 6;
- inline bool has_type_name() const;
- inline void clear_type_name();
+ bool has_type_name() const;
+ void clear_type_name();
static const int kTypeNameFieldNumber = 6;
- inline const ::std::string& type_name() const;
- inline void set_type_name(const ::std::string& value);
- inline void set_type_name(const char* value);
- inline void set_type_name(const char* value, size_t size);
- inline ::std::string* mutable_type_name();
- inline ::std::string* release_type_name();
-
+ const ::std::string& type_name() const;
+ void set_type_name(const ::std::string& value);
+ void set_type_name(const char* value);
+ void set_type_name(const char* value, size_t size);
+ ::std::string* mutable_type_name();
+ ::std::string* release_type_name();
+ void set_allocated_type_name(::std::string* type_name);
+
// optional string extendee = 2;
- inline bool has_extendee() const;
- inline void clear_extendee();
+ bool has_extendee() const;
+ void clear_extendee();
static const int kExtendeeFieldNumber = 2;
- inline const ::std::string& extendee() const;
- inline void set_extendee(const ::std::string& value);
- inline void set_extendee(const char* value);
- inline void set_extendee(const char* value, size_t size);
- inline ::std::string* mutable_extendee();
- inline ::std::string* release_extendee();
-
+ const ::std::string& extendee() const;
+ void set_extendee(const ::std::string& value);
+ void set_extendee(const char* value);
+ void set_extendee(const char* value, size_t size);
+ ::std::string* mutable_extendee();
+ ::std::string* release_extendee();
+ void set_allocated_extendee(::std::string* extendee);
+
// optional string default_value = 7;
- inline bool has_default_value() const;
- inline void clear_default_value();
+ bool has_default_value() const;
+ void clear_default_value();
static const int kDefaultValueFieldNumber = 7;
- inline const ::std::string& default_value() const;
- inline void set_default_value(const ::std::string& value);
- inline void set_default_value(const char* value);
- inline void set_default_value(const char* value, size_t size);
- inline ::std::string* mutable_default_value();
- inline ::std::string* release_default_value();
-
+ const ::std::string& default_value() const;
+ void set_default_value(const ::std::string& value);
+ void set_default_value(const char* value);
+ void set_default_value(const char* value, size_t size);
+ ::std::string* mutable_default_value();
+ ::std::string* release_default_value();
+ void set_allocated_default_value(::std::string* default_value);
+
+ // optional int32 oneof_index = 9;
+ bool has_oneof_index() const;
+ void clear_oneof_index();
+ static const int kOneofIndexFieldNumber = 9;
+ ::google::protobuf::int32 oneof_index() const;
+ void set_oneof_index(::google::protobuf::int32 value);
+
// optional .google.protobuf.FieldOptions options = 8;
- inline bool has_options() const;
- inline void clear_options();
+ bool has_options() const;
+ void clear_options();
static const int kOptionsFieldNumber = 8;
- inline const ::google::protobuf::FieldOptions& options() const;
- inline ::google::protobuf::FieldOptions* mutable_options();
- inline ::google::protobuf::FieldOptions* release_options();
-
+ const ::google::protobuf::FieldOptions& options() const;
+ ::google::protobuf::FieldOptions* mutable_options();
+ ::google::protobuf::FieldOptions* release_options();
+ void set_allocated_options(::google::protobuf::FieldOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto)
private:
inline void set_has_name();
@@ -891,67 +1007,163 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
inline void clear_has_extendee();
inline void set_has_default_value();
inline void clear_has_default_value();
+ inline void set_has_oneof_index();
+ inline void clear_has_oneof_index();
inline void set_has_options();
inline void clear_has_options();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* name_;
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::google::protobuf::internal::ArenaStringPtr name_;
::google::protobuf::int32 number_;
int label_;
- ::std::string* type_name_;
- ::std::string* extendee_;
- ::std::string* default_value_;
- ::google::protobuf::FieldOptions* options_;
+ ::google::protobuf::internal::ArenaStringPtr type_name_;
+ ::google::protobuf::internal::ArenaStringPtr extendee_;
int type_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
-
+ ::google::protobuf::int32 oneof_index_;
+ ::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();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
-
+
void InitAsDefaultInstance();
static FieldDescriptorProto* default_instance_;
};
// -------------------------------------------------------------------
+class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Message {
+ public:
+ OneofDescriptorProto();
+ virtual ~OneofDescriptorProto();
+
+ OneofDescriptorProto(const OneofDescriptorProto& from);
+
+ inline OneofDescriptorProto& operator=(const OneofDescriptorProto& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const OneofDescriptorProto& default_instance();
+
+ void Swap(OneofDescriptorProto* other);
+
+ // implements Message ----------------------------------------------
+
+ 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);
+ void MergeFrom(const OneofDescriptorProto& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ void InternalSwap(OneofDescriptorProto* other);
+ 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 ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string name = 1;
+ bool has_name() const;
+ void clear_name();
+ static const int kNameFieldNumber = 1;
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void 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::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::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();
+
+ void InitAsDefaultInstance();
+ static OneofDescriptorProto* default_instance_;
+};
+// -------------------------------------------------------------------
+
class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Message {
public:
EnumDescriptorProto();
virtual ~EnumDescriptorProto();
-
+
EnumDescriptorProto(const EnumDescriptorProto& from);
-
+
inline EnumDescriptorProto& operator=(const EnumDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const EnumDescriptorProto& default_instance();
-
+
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);
void MergeFrom(const EnumDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -963,65 +1175,72 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(EnumDescriptorProto* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
- inline bool has_name() const;
- inline void clear_name();
+ bool has_name() const;
+ void clear_name();
static const int kNameFieldNumber = 1;
- inline const ::std::string& name() const;
- inline void set_name(const ::std::string& value);
- inline void set_name(const char* value);
- inline void set_name(const char* value, size_t size);
- inline ::std::string* mutable_name();
- inline ::std::string* release_name();
-
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void set_allocated_name(::std::string* name);
+
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
- inline int value_size() const;
- inline void clear_value();
+ int value_size() const;
+ void clear_value();
static const int kValueFieldNumber = 2;
- inline const ::google::protobuf::EnumValueDescriptorProto& value(int index) const;
- inline ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index);
- inline ::google::protobuf::EnumValueDescriptorProto* add_value();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
+ const ::google::protobuf::EnumValueDescriptorProto& value(int index) const;
+ ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index);
+ ::google::protobuf::EnumValueDescriptorProto* add_value();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
value() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
mutable_value();
-
+
// optional .google.protobuf.EnumOptions options = 3;
- inline bool has_options() const;
- inline void clear_options();
+ bool has_options() const;
+ void clear_options();
static const int kOptionsFieldNumber = 3;
- inline const ::google::protobuf::EnumOptions& options() const;
- inline ::google::protobuf::EnumOptions* mutable_options();
- inline ::google::protobuf::EnumOptions* release_options();
-
+ const ::google::protobuf::EnumOptions& options() const;
+ ::google::protobuf::EnumOptions* mutable_options();
+ ::google::protobuf::EnumOptions* release_options();
+ void set_allocated_options(::google::protobuf::EnumOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto)
private:
inline void set_has_name();
inline void clear_has_name();
inline void set_has_options();
inline void clear_has_options();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* name_;
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::google::protobuf::internal::ArenaStringPtr name_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto > value_;
::google::protobuf::EnumOptions* options_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
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();
-
+
void InitAsDefaultInstance();
static EnumDescriptorProto* default_instance_;
};
@@ -1031,37 +1250,39 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
public:
EnumValueDescriptorProto();
virtual ~EnumValueDescriptorProto();
-
+
EnumValueDescriptorProto(const EnumValueDescriptorProto& from);
-
+
inline EnumValueDescriptorProto& operator=(const EnumValueDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const EnumValueDescriptorProto& default_instance();
-
+
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);
void MergeFrom(const EnumValueDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1073,40 +1294,50 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(EnumValueDescriptorProto* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
- inline bool has_name() const;
- inline void clear_name();
+ bool has_name() const;
+ void clear_name();
static const int kNameFieldNumber = 1;
- inline const ::std::string& name() const;
- inline void set_name(const ::std::string& value);
- inline void set_name(const char* value);
- inline void set_name(const char* value, size_t size);
- inline ::std::string* mutable_name();
- inline ::std::string* release_name();
-
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void set_allocated_name(::std::string* name);
+
// optional int32 number = 2;
- inline bool has_number() const;
- inline void clear_number();
+ bool has_number() const;
+ void clear_number();
static const int kNumberFieldNumber = 2;
- inline ::google::protobuf::int32 number() const;
- inline void set_number(::google::protobuf::int32 value);
-
+ ::google::protobuf::int32 number() const;
+ void set_number(::google::protobuf::int32 value);
+
// optional .google.protobuf.EnumValueOptions options = 3;
- inline bool has_options() const;
- inline void clear_options();
+ bool has_options() const;
+ void clear_options();
static const int kOptionsFieldNumber = 3;
- inline const ::google::protobuf::EnumValueOptions& options() const;
- inline ::google::protobuf::EnumValueOptions* mutable_options();
- inline ::google::protobuf::EnumValueOptions* release_options();
-
+ const ::google::protobuf::EnumValueOptions& options() const;
+ ::google::protobuf::EnumValueOptions* mutable_options();
+ ::google::protobuf::EnumValueOptions* release_options();
+ void set_allocated_options(::google::protobuf::EnumValueOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto)
private:
inline void set_has_name();
@@ -1115,20 +1346,17 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
inline void clear_has_number();
inline void set_has_options();
inline void clear_has_options();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* name_;
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::google::protobuf::internal::ArenaStringPtr name_;
::google::protobuf::EnumValueOptions* options_;
::google::protobuf::int32 number_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
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();
-
+
void InitAsDefaultInstance();
static EnumValueDescriptorProto* default_instance_;
};
@@ -1138,37 +1366,39 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
public:
ServiceDescriptorProto();
virtual ~ServiceDescriptorProto();
-
+
ServiceDescriptorProto(const ServiceDescriptorProto& from);
-
+
inline ServiceDescriptorProto& operator=(const ServiceDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const ServiceDescriptorProto& default_instance();
-
+
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);
void MergeFrom(const ServiceDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1180,65 +1410,72 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(ServiceDescriptorProto* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
- inline bool has_name() const;
- inline void clear_name();
+ bool has_name() const;
+ void clear_name();
static const int kNameFieldNumber = 1;
- inline const ::std::string& name() const;
- inline void set_name(const ::std::string& value);
- inline void set_name(const char* value);
- inline void set_name(const char* value, size_t size);
- inline ::std::string* mutable_name();
- inline ::std::string* release_name();
-
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void set_allocated_name(::std::string* name);
+
// repeated .google.protobuf.MethodDescriptorProto method = 2;
- inline int method_size() const;
- inline void clear_method();
+ int method_size() const;
+ void clear_method();
static const int kMethodFieldNumber = 2;
- inline const ::google::protobuf::MethodDescriptorProto& method(int index) const;
- inline ::google::protobuf::MethodDescriptorProto* mutable_method(int index);
- inline ::google::protobuf::MethodDescriptorProto* add_method();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
+ const ::google::protobuf::MethodDescriptorProto& method(int index) const;
+ ::google::protobuf::MethodDescriptorProto* mutable_method(int index);
+ ::google::protobuf::MethodDescriptorProto* add_method();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
method() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
mutable_method();
-
+
// optional .google.protobuf.ServiceOptions options = 3;
- inline bool has_options() const;
- inline void clear_options();
+ bool has_options() const;
+ void clear_options();
static const int kOptionsFieldNumber = 3;
- inline const ::google::protobuf::ServiceOptions& options() const;
- inline ::google::protobuf::ServiceOptions* mutable_options();
- inline ::google::protobuf::ServiceOptions* release_options();
-
+ const ::google::protobuf::ServiceOptions& options() const;
+ ::google::protobuf::ServiceOptions* mutable_options();
+ ::google::protobuf::ServiceOptions* release_options();
+ void set_allocated_options(::google::protobuf::ServiceOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto)
private:
inline void set_has_name();
inline void clear_has_name();
inline void set_has_options();
inline void clear_has_options();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* name_;
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::google::protobuf::internal::ArenaStringPtr name_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto > method_;
::google::protobuf::ServiceOptions* options_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
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();
-
+
void InitAsDefaultInstance();
static ServiceDescriptorProto* default_instance_;
};
@@ -1248,37 +1485,39 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
public:
MethodDescriptorProto();
virtual ~MethodDescriptorProto();
-
+
MethodDescriptorProto(const MethodDescriptorProto& from);
-
+
inline MethodDescriptorProto& operator=(const MethodDescriptorProto& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const MethodDescriptorProto& default_instance();
-
+
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);
void MergeFrom(const MethodDescriptorProto& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1290,55 +1529,81 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(MethodDescriptorProto* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional string name = 1;
- inline bool has_name() const;
- inline void clear_name();
+ bool has_name() const;
+ void clear_name();
static const int kNameFieldNumber = 1;
- inline const ::std::string& name() const;
- inline void set_name(const ::std::string& value);
- inline void set_name(const char* value);
- inline void set_name(const char* value, size_t size);
- inline ::std::string* mutable_name();
- inline ::std::string* release_name();
-
+ const ::std::string& name() const;
+ void set_name(const ::std::string& value);
+ void set_name(const char* value);
+ void set_name(const char* value, size_t size);
+ ::std::string* mutable_name();
+ ::std::string* release_name();
+ void set_allocated_name(::std::string* name);
+
// optional string input_type = 2;
- inline bool has_input_type() const;
- inline void clear_input_type();
+ bool has_input_type() const;
+ void clear_input_type();
static const int kInputTypeFieldNumber = 2;
- inline const ::std::string& input_type() const;
- inline void set_input_type(const ::std::string& value);
- inline void set_input_type(const char* value);
- inline void set_input_type(const char* value, size_t size);
- inline ::std::string* mutable_input_type();
- inline ::std::string* release_input_type();
-
+ const ::std::string& input_type() const;
+ void set_input_type(const ::std::string& value);
+ void set_input_type(const char* value);
+ void set_input_type(const char* value, size_t size);
+ ::std::string* mutable_input_type();
+ ::std::string* release_input_type();
+ void set_allocated_input_type(::std::string* input_type);
+
// optional string output_type = 3;
- inline bool has_output_type() const;
- inline void clear_output_type();
+ bool has_output_type() const;
+ void clear_output_type();
static const int kOutputTypeFieldNumber = 3;
- inline const ::std::string& output_type() const;
- inline void set_output_type(const ::std::string& value);
- inline void set_output_type(const char* value);
- inline void set_output_type(const char* value, size_t size);
- inline ::std::string* mutable_output_type();
- inline ::std::string* release_output_type();
-
+ const ::std::string& output_type() const;
+ void set_output_type(const ::std::string& value);
+ void set_output_type(const char* value);
+ void set_output_type(const char* value, size_t size);
+ ::std::string* mutable_output_type();
+ ::std::string* release_output_type();
+ void set_allocated_output_type(::std::string* output_type);
+
// optional .google.protobuf.MethodOptions options = 4;
- inline bool has_options() const;
- inline void clear_options();
+ bool has_options() const;
+ void clear_options();
static const int kOptionsFieldNumber = 4;
- inline const ::google::protobuf::MethodOptions& options() const;
- inline ::google::protobuf::MethodOptions* mutable_options();
- inline ::google::protobuf::MethodOptions* release_options();
-
+ const ::google::protobuf::MethodOptions& options() const;
+ ::google::protobuf::MethodOptions* mutable_options();
+ ::google::protobuf::MethodOptions* release_options();
+ void set_allocated_options(::google::protobuf::MethodOptions* options);
+
+ // optional bool client_streaming = 5 [default = false];
+ bool has_client_streaming() const;
+ void clear_client_streaming();
+ static const int kClientStreamingFieldNumber = 5;
+ bool client_streaming() const;
+ void set_client_streaming(bool value);
+
+ // optional bool server_streaming = 6 [default = false];
+ bool has_server_streaming() const;
+ void clear_server_streaming();
+ static const int kServerStreamingFieldNumber = 6;
+ bool server_streaming() const;
+ void set_server_streaming(bool value);
+
// @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto)
private:
inline void set_has_name();
@@ -1349,21 +1614,24 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
inline void clear_has_output_type();
inline void set_has_options();
inline void clear_has_options();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* name_;
- ::std::string* input_type_;
- ::std::string* output_type_;
- ::google::protobuf::MethodOptions* options_;
-
+ inline void set_has_client_streaming();
+ inline void clear_has_client_streaming();
+ inline void set_has_server_streaming();
+ inline void clear_has_server_streaming();
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
-
+ ::google::protobuf::internal::ArenaStringPtr name_;
+ ::google::protobuf::internal::ArenaStringPtr input_type_;
+ ::google::protobuf::internal::ArenaStringPtr output_type_;
+ ::google::protobuf::MethodOptions* options_;
+ bool client_streaming_;
+ bool server_streaming_;
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();
-
+
void InitAsDefaultInstance();
static MethodDescriptorProto* default_instance_;
};
@@ -1373,37 +1641,39 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
public:
FileOptions();
virtual ~FileOptions();
-
+
FileOptions(const FileOptions& from);
-
+
inline FileOptions& operator=(const FileOptions& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FileOptions& default_instance();
-
+
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);
void MergeFrom(const FileOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1415,12 +1685,20 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(FileOptions* other);
+ 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 ----------------------------------------------------
-
+
typedef FileOptions_OptimizeMode OptimizeMode;
static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED;
static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE;
@@ -1445,85 +1723,132 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
OptimizeMode* value) {
return FileOptions_OptimizeMode_Parse(name, value);
}
-
+
// accessors -------------------------------------------------------
-
+
// optional string java_package = 1;
- inline bool has_java_package() const;
- inline void clear_java_package();
+ bool has_java_package() const;
+ void clear_java_package();
static const int kJavaPackageFieldNumber = 1;
- inline const ::std::string& java_package() const;
- inline void set_java_package(const ::std::string& value);
- inline void set_java_package(const char* value);
- inline void set_java_package(const char* value, size_t size);
- inline ::std::string* mutable_java_package();
- inline ::std::string* release_java_package();
-
+ const ::std::string& java_package() const;
+ void set_java_package(const ::std::string& value);
+ void set_java_package(const char* value);
+ void set_java_package(const char* value, size_t size);
+ ::std::string* mutable_java_package();
+ ::std::string* release_java_package();
+ void set_allocated_java_package(::std::string* java_package);
+
// optional string java_outer_classname = 8;
- inline bool has_java_outer_classname() const;
- inline void clear_java_outer_classname();
+ bool has_java_outer_classname() const;
+ void clear_java_outer_classname();
static const int kJavaOuterClassnameFieldNumber = 8;
- inline const ::std::string& java_outer_classname() const;
- inline void set_java_outer_classname(const ::std::string& value);
- inline void set_java_outer_classname(const char* value);
- inline void set_java_outer_classname(const char* value, size_t size);
- inline ::std::string* mutable_java_outer_classname();
- inline ::std::string* release_java_outer_classname();
-
+ const ::std::string& java_outer_classname() const;
+ void set_java_outer_classname(const ::std::string& value);
+ void set_java_outer_classname(const char* value);
+ void set_java_outer_classname(const char* value, size_t size);
+ ::std::string* mutable_java_outer_classname();
+ ::std::string* release_java_outer_classname();
+ void 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;
- inline void clear_java_multiple_files();
+ bool has_java_multiple_files() const;
+ void clear_java_multiple_files();
static const int kJavaMultipleFilesFieldNumber = 10;
- inline bool java_multiple_files() const;
- inline void set_java_multiple_files(bool value);
-
+ bool java_multiple_files() const;
+ void set_java_multiple_files(bool value);
+
// optional bool java_generate_equals_and_hash = 20 [default = false];
- inline bool has_java_generate_equals_and_hash() const;
- inline void clear_java_generate_equals_and_hash();
+ bool has_java_generate_equals_and_hash() const;
+ void clear_java_generate_equals_and_hash();
static const int kJavaGenerateEqualsAndHashFieldNumber = 20;
- inline bool java_generate_equals_and_hash() const;
- inline void set_java_generate_equals_and_hash(bool value);
-
+ bool java_generate_equals_and_hash() const;
+ void set_java_generate_equals_and_hash(bool value);
+
+ // optional bool java_string_check_utf8 = 27 [default = false];
+ bool has_java_string_check_utf8() const;
+ void clear_java_string_check_utf8();
+ static const int kJavaStringCheckUtf8FieldNumber = 27;
+ bool java_string_check_utf8() const;
+ void set_java_string_check_utf8(bool value);
+
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
- inline bool has_optimize_for() const;
- inline void clear_optimize_for();
+ bool has_optimize_for() const;
+ void clear_optimize_for();
static const int kOptimizeForFieldNumber = 9;
- inline ::google::protobuf::FileOptions_OptimizeMode optimize_for() const;
- inline void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value);
-
+ ::google::protobuf::FileOptions_OptimizeMode optimize_for() const;
+ void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value);
+
+ // optional string go_package = 11;
+ bool has_go_package() const;
+ void clear_go_package();
+ static const int kGoPackageFieldNumber = 11;
+ const ::std::string& go_package() const;
+ void set_go_package(const ::std::string& value);
+ void set_go_package(const char* value);
+ void set_go_package(const char* value, size_t size);
+ ::std::string* mutable_go_package();
+ ::std::string* release_go_package();
+ void set_allocated_go_package(::std::string* go_package);
+
// optional bool cc_generic_services = 16 [default = false];
- inline bool has_cc_generic_services() const;
- inline void clear_cc_generic_services();
+ bool has_cc_generic_services() const;
+ void clear_cc_generic_services();
static const int kCcGenericServicesFieldNumber = 16;
- inline bool cc_generic_services() const;
- inline void set_cc_generic_services(bool value);
-
+ bool cc_generic_services() const;
+ void set_cc_generic_services(bool value);
+
// optional bool java_generic_services = 17 [default = false];
- inline bool has_java_generic_services() const;
- inline void clear_java_generic_services();
+ bool has_java_generic_services() const;
+ void clear_java_generic_services();
static const int kJavaGenericServicesFieldNumber = 17;
- inline bool java_generic_services() const;
- inline void set_java_generic_services(bool value);
-
+ bool java_generic_services() const;
+ void set_java_generic_services(bool value);
+
// optional bool py_generic_services = 18 [default = false];
- inline bool has_py_generic_services() const;
- inline void clear_py_generic_services();
+ bool has_py_generic_services() const;
+ void clear_py_generic_services();
static const int kPyGenericServicesFieldNumber = 18;
- inline bool py_generic_services() const;
- inline void set_py_generic_services(bool value);
-
+ bool py_generic_services() const;
+ void set_py_generic_services(bool value);
+
+ // optional bool deprecated = 23 [default = false];
+ bool has_deprecated() const;
+ void clear_deprecated();
+ static const int kDeprecatedFieldNumber = 23;
+ bool deprecated() const;
+ void set_deprecated(bool value);
+
+ // optional bool cc_enable_arenas = 31 [default = false];
+ bool has_cc_enable_arenas() const;
+ void clear_cc_enable_arenas();
+ static const int kCcEnableArenasFieldNumber = 31;
+ bool cc_enable_arenas() const;
+ void set_cc_enable_arenas(bool value);
+
+ // optional string objc_class_prefix = 36;
+ bool has_objc_class_prefix() const;
+ void clear_objc_class_prefix();
+ static const int kObjcClassPrefixFieldNumber = 36;
+ const ::std::string& objc_class_prefix() const;
+ void set_objc_class_prefix(const ::std::string& value);
+ void set_objc_class_prefix(const char* value);
+ void set_objc_class_prefix(const char* value, size_t size);
+ ::std::string* mutable_objc_class_prefix();
+ ::std::string* release_objc_class_prefix();
+ void set_allocated_objc_class_prefix(::std::string* objc_class_prefix);
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- inline int uninterpreted_option_size() const;
- inline void clear_uninterpreted_option();
+ int uninterpreted_option_size() const;
+ void clear_uninterpreted_option();
static const int kUninterpretedOptionFieldNumber = 999;
- inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
- inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
- inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+ ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+ ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
uninterpreted_option() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.FileOptions)
private:
@@ -1535,36 +1860,48 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
inline void clear_has_java_multiple_files();
inline void set_has_java_generate_equals_and_hash();
inline void clear_has_java_generate_equals_and_hash();
+ inline void set_has_java_string_check_utf8();
+ inline void clear_has_java_string_check_utf8();
inline void set_has_optimize_for();
inline void clear_has_optimize_for();
+ inline void set_has_go_package();
+ inline void clear_has_go_package();
inline void set_has_cc_generic_services();
inline void clear_has_cc_generic_services();
inline void set_has_java_generic_services();
inline void clear_has_java_generic_services();
inline void set_has_py_generic_services();
inline void clear_has_py_generic_services();
-
+ inline void set_has_deprecated();
+ inline void clear_has_deprecated();
+ inline void set_has_cc_enable_arenas();
+ inline void clear_has_cc_enable_arenas();
+ inline void set_has_objc_class_prefix();
+ inline void clear_has_objc_class_prefix();
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* java_package_;
- ::std::string* java_outer_classname_;
- int optimize_for_;
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::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_;
- bool java_generic_services_;
+ int optimize_for_;
+ ::google::protobuf::internal::ArenaStringPtr go_package_;
+ ::google::protobuf::internal::ArenaStringPtr objc_class_prefix_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
+ bool java_generic_services_;
bool py_generic_services_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(9 + 31) / 32];
-
+ bool deprecated_;
+ bool cc_enable_arenas_;
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();
-
+
void InitAsDefaultInstance();
static FileOptions* default_instance_;
};
@@ -1574,37 +1911,39 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
public:
MessageOptions();
virtual ~MessageOptions();
-
+
MessageOptions(const MessageOptions& from);
-
+
inline MessageOptions& operator=(const MessageOptions& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const MessageOptions& default_instance();
-
+
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);
void MergeFrom(const MessageOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1616,40 +1955,62 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(MessageOptions* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// optional bool message_set_wire_format = 1 [default = false];
- inline bool has_message_set_wire_format() const;
- inline void clear_message_set_wire_format();
+ bool has_message_set_wire_format() const;
+ void clear_message_set_wire_format();
static const int kMessageSetWireFormatFieldNumber = 1;
- inline bool message_set_wire_format() const;
- inline void set_message_set_wire_format(bool value);
-
+ bool message_set_wire_format() const;
+ void set_message_set_wire_format(bool value);
+
// optional bool no_standard_descriptor_accessor = 2 [default = false];
- inline bool has_no_standard_descriptor_accessor() const;
- inline void clear_no_standard_descriptor_accessor();
+ bool has_no_standard_descriptor_accessor() const;
+ void clear_no_standard_descriptor_accessor();
static const int kNoStandardDescriptorAccessorFieldNumber = 2;
- inline bool no_standard_descriptor_accessor() const;
- inline void set_no_standard_descriptor_accessor(bool value);
-
+ bool no_standard_descriptor_accessor() const;
+ void set_no_standard_descriptor_accessor(bool value);
+
+ // optional bool deprecated = 3 [default = false];
+ bool has_deprecated() const;
+ void clear_deprecated();
+ static const int kDeprecatedFieldNumber = 3;
+ bool deprecated() const;
+ void set_deprecated(bool value);
+
+ // optional bool map_entry = 7;
+ bool has_map_entry() const;
+ void clear_map_entry();
+ static const int kMapEntryFieldNumber = 7;
+ bool map_entry() const;
+ void set_map_entry(bool value);
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- inline int uninterpreted_option_size() const;
- inline void clear_uninterpreted_option();
+ int uninterpreted_option_size() const;
+ void clear_uninterpreted_option();
static const int kUninterpretedOptionFieldNumber = 999;
- inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
- inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
- inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+ ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+ ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
uninterpreted_option() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions)
private:
@@ -1657,22 +2018,25 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
inline void clear_has_message_set_wire_format();
inline void set_has_no_standard_descriptor_accessor();
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_;
+ ::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_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-
+ 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();
-
+
void InitAsDefaultInstance();
static MessageOptions* default_instance_;
};
@@ -1682,37 +2046,39 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
public:
FieldOptions();
virtual ~FieldOptions();
-
+
FieldOptions(const FieldOptions& from);
-
+
inline FieldOptions& operator=(const FieldOptions& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const FieldOptions& default_instance();
-
+
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);
void MergeFrom(const FieldOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1724,12 +2090,20 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(FieldOptions* other);
+ 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 ----------------------------------------------------
-
+
typedef FieldOptions_CType CType;
static const CType STRING = FieldOptions_CType_STRING;
static const CType CORD = FieldOptions_CType_CORD;
@@ -1754,53 +2128,56 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
CType* value) {
return FieldOptions_CType_Parse(name, value);
}
-
+
// accessors -------------------------------------------------------
-
+
// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
- inline bool has_ctype() const;
- inline void clear_ctype();
+ bool has_ctype() const;
+ void clear_ctype();
static const int kCtypeFieldNumber = 1;
- inline ::google::protobuf::FieldOptions_CType ctype() const;
- inline void set_ctype(::google::protobuf::FieldOptions_CType value);
-
+ ::google::protobuf::FieldOptions_CType ctype() const;
+ void set_ctype(::google::protobuf::FieldOptions_CType value);
+
// optional bool packed = 2;
- inline bool has_packed() const;
- inline void clear_packed();
+ bool has_packed() const;
+ void clear_packed();
static const int kPackedFieldNumber = 2;
- inline bool packed() const;
- inline void set_packed(bool value);
-
+ bool packed() const;
+ void set_packed(bool value);
+
+ // optional bool lazy = 5 [default = false];
+ bool has_lazy() const;
+ void clear_lazy();
+ static const int kLazyFieldNumber = 5;
+ bool lazy() const;
+ void set_lazy(bool value);
+
// optional bool deprecated = 3 [default = false];
- inline bool has_deprecated() const;
- inline void clear_deprecated();
+ bool has_deprecated() const;
+ void clear_deprecated();
static const int kDeprecatedFieldNumber = 3;
- 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();
-
+ bool deprecated() const;
+ void set_deprecated(bool value);
+
+ // optional bool weak = 10 [default = false];
+ bool has_weak() const;
+ void clear_weak();
+ static const int kWeakFieldNumber = 10;
+ bool weak() const;
+ void set_weak(bool value);
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- inline int uninterpreted_option_size() const;
- inline void clear_uninterpreted_option();
+ int uninterpreted_option_size() const;
+ void clear_uninterpreted_option();
static const int kUninterpretedOptionFieldNumber = 999;
- inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
- inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
- inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+ ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+ ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
uninterpreted_option() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions)
private:
@@ -1808,28 +2185,28 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
inline void clear_has_ctype();
inline void set_has_packed();
inline void clear_has_packed();
+ inline void set_has_lazy();
+ 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_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
int ctype_;
bool packed_;
+ bool lazy_;
bool deprecated_;
- ::std::string* experimental_map_key_;
+ bool weak_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
-
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();
-
+
void InitAsDefaultInstance();
static FieldOptions* default_instance_;
};
@@ -1839,37 +2216,39 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
public:
EnumOptions();
virtual ~EnumOptions();
-
+
EnumOptions(const EnumOptions& from);
-
+
inline EnumOptions& operator=(const EnumOptions& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const EnumOptions& default_instance();
-
+
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);
void MergeFrom(const EnumOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1881,43 +2260,68 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(EnumOptions* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
+ // optional bool allow_alias = 2;
+ bool has_allow_alias() const;
+ void clear_allow_alias();
+ static const int kAllowAliasFieldNumber = 2;
+ bool allow_alias() const;
+ void set_allow_alias(bool value);
+
+ // optional bool deprecated = 3 [default = false];
+ bool has_deprecated() const;
+ void clear_deprecated();
+ static const int kDeprecatedFieldNumber = 3;
+ bool deprecated() const;
+ void set_deprecated(bool value);
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- inline int uninterpreted_option_size() const;
- inline void clear_uninterpreted_option();
+ int uninterpreted_option_size() const;
+ void clear_uninterpreted_option();
static const int kUninterpretedOptionFieldNumber = 999;
- inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
- inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
- inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+ ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+ ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
uninterpreted_option() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions)
private:
-
+ inline void set_has_allow_alias();
+ inline void clear_has_allow_alias();
+ inline void set_has_deprecated();
+ inline void clear_has_deprecated();
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
+ bool allow_alias_;
+ bool deprecated_;
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();
-
+
void InitAsDefaultInstance();
static EnumOptions* default_instance_;
};
@@ -1927,37 +2331,39 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
public:
EnumValueOptions();
virtual ~EnumValueOptions();
-
+
EnumValueOptions(const EnumValueOptions& from);
-
+
inline EnumValueOptions& operator=(const EnumValueOptions& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const EnumValueOptions& default_instance();
-
+
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);
void MergeFrom(const EnumValueOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -1969,43 +2375,58 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(EnumValueOptions* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
+ // optional bool deprecated = 1 [default = false];
+ bool has_deprecated() const;
+ void clear_deprecated();
+ static const int kDeprecatedFieldNumber = 1;
+ bool deprecated() const;
+ void set_deprecated(bool value);
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- inline int uninterpreted_option_size() const;
- inline void clear_uninterpreted_option();
+ int uninterpreted_option_size() const;
+ void clear_uninterpreted_option();
static const int kUninterpretedOptionFieldNumber = 999;
- inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
- inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
- inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+ ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+ ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
uninterpreted_option() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions)
private:
-
+ inline void set_has_deprecated();
+ inline void clear_has_deprecated();
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
+ bool deprecated_;
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();
-
+
void InitAsDefaultInstance();
static EnumValueOptions* default_instance_;
};
@@ -2015,37 +2436,39 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
public:
ServiceOptions();
virtual ~ServiceOptions();
-
+
ServiceOptions(const ServiceOptions& from);
-
+
inline ServiceOptions& operator=(const ServiceOptions& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const ServiceOptions& default_instance();
-
+
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);
void MergeFrom(const ServiceOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2057,43 +2480,58 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(ServiceOptions* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
+ // optional bool deprecated = 33 [default = false];
+ bool has_deprecated() const;
+ void clear_deprecated();
+ static const int kDeprecatedFieldNumber = 33;
+ bool deprecated() const;
+ void set_deprecated(bool value);
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- inline int uninterpreted_option_size() const;
- inline void clear_uninterpreted_option();
+ int uninterpreted_option_size() const;
+ void clear_uninterpreted_option();
static const int kUninterpretedOptionFieldNumber = 999;
- inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
- inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
- inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+ ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+ ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
uninterpreted_option() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions)
private:
-
+ inline void set_has_deprecated();
+ inline void clear_has_deprecated();
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
+ bool deprecated_;
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();
-
+
void InitAsDefaultInstance();
static ServiceOptions* default_instance_;
};
@@ -2103,37 +2541,39 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
public:
MethodOptions();
virtual ~MethodOptions();
-
+
MethodOptions(const MethodOptions& from);
-
+
inline MethodOptions& operator=(const MethodOptions& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const MethodOptions& default_instance();
-
+
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);
void MergeFrom(const MethodOptions& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2145,43 +2585,58 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(MethodOptions* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
+ // optional bool deprecated = 33 [default = false];
+ bool has_deprecated() const;
+ void clear_deprecated();
+ static const int kDeprecatedFieldNumber = 33;
+ bool deprecated() const;
+ void set_deprecated(bool value);
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- inline int uninterpreted_option_size() const;
- inline void clear_uninterpreted_option();
+ int uninterpreted_option_size() const;
+ void clear_uninterpreted_option();
static const int kUninterpretedOptionFieldNumber = 999;
- inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
- inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
- inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+ ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+ ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
uninterpreted_option() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
mutable_uninterpreted_option();
-
+
GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions)
// @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions)
private:
-
+ inline void set_has_deprecated();
+ inline void clear_has_deprecated();
+
::google::protobuf::internal::ExtensionSet _extensions_;
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
+ bool deprecated_;
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();
-
+
void InitAsDefaultInstance();
static MethodOptions* default_instance_;
};
@@ -2191,37 +2646,39 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
public:
UninterpretedOption_NamePart();
virtual ~UninterpretedOption_NamePart();
-
+
UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from);
-
+
inline UninterpretedOption_NamePart& operator=(const UninterpretedOption_NamePart& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const UninterpretedOption_NamePart& default_instance();
-
+
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);
void MergeFrom(const UninterpretedOption_NamePart& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2233,51 +2690,60 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(UninterpretedOption_NamePart* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// required string name_part = 1;
- inline bool has_name_part() const;
- inline void clear_name_part();
+ bool has_name_part() const;
+ void clear_name_part();
static const int kNamePartFieldNumber = 1;
- inline const ::std::string& name_part() const;
- inline void set_name_part(const ::std::string& value);
- inline void set_name_part(const char* value);
- inline void set_name_part(const char* value, size_t size);
- inline ::std::string* mutable_name_part();
- inline ::std::string* release_name_part();
-
+ const ::std::string& name_part() const;
+ void set_name_part(const ::std::string& value);
+ void set_name_part(const char* value);
+ void set_name_part(const char* value, size_t size);
+ ::std::string* mutable_name_part();
+ ::std::string* release_name_part();
+ void set_allocated_name_part(::std::string* name_part);
+
// required bool is_extension = 2;
- inline bool has_is_extension() const;
- inline void clear_is_extension();
+ bool has_is_extension() const;
+ void clear_is_extension();
static const int kIsExtensionFieldNumber = 2;
- inline bool is_extension() const;
- inline void set_is_extension(bool value);
-
+ bool is_extension() const;
+ void set_is_extension(bool value);
+
// @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart)
private:
inline void set_has_name_part();
inline void clear_has_name_part();
inline void set_has_is_extension();
inline void clear_has_is_extension();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::std::string* name_part_;
- bool is_extension_;
-
+
+ // helper for ByteSize()
+ int RequiredFieldsByteSizeFallback() const;
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
-
+ ::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();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
-
+
void InitAsDefaultInstance();
static UninterpretedOption_NamePart* default_instance_;
};
@@ -2287,37 +2753,39 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
public:
UninterpretedOption();
virtual ~UninterpretedOption();
-
+
UninterpretedOption(const UninterpretedOption& from);
-
+
inline UninterpretedOption& operator=(const UninterpretedOption& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const UninterpretedOption& default_instance();
-
+
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);
void MergeFrom(const UninterpretedOption& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2329,82 +2797,93 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(UninterpretedOption* other);
+ 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 ----------------------------------------------------
-
+
typedef UninterpretedOption_NamePart NamePart;
-
+
// accessors -------------------------------------------------------
-
+
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
- inline int name_size() const;
- inline void clear_name();
+ int name_size() const;
+ void clear_name();
static const int kNameFieldNumber = 2;
- inline const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const;
- inline ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index);
- inline ::google::protobuf::UninterpretedOption_NamePart* add_name();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
+ const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const;
+ ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index);
+ ::google::protobuf::UninterpretedOption_NamePart* add_name();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
name() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
mutable_name();
-
+
// optional string identifier_value = 3;
- inline bool has_identifier_value() const;
- inline void clear_identifier_value();
+ bool has_identifier_value() const;
+ void clear_identifier_value();
static const int kIdentifierValueFieldNumber = 3;
- inline const ::std::string& identifier_value() const;
- inline void set_identifier_value(const ::std::string& value);
- inline void set_identifier_value(const char* value);
- inline void set_identifier_value(const char* value, size_t size);
- inline ::std::string* mutable_identifier_value();
- inline ::std::string* release_identifier_value();
-
+ const ::std::string& identifier_value() const;
+ void set_identifier_value(const ::std::string& value);
+ void set_identifier_value(const char* value);
+ void set_identifier_value(const char* value, size_t size);
+ ::std::string* mutable_identifier_value();
+ ::std::string* release_identifier_value();
+ void set_allocated_identifier_value(::std::string* identifier_value);
+
// optional uint64 positive_int_value = 4;
- inline bool has_positive_int_value() const;
- inline void clear_positive_int_value();
+ bool has_positive_int_value() const;
+ void clear_positive_int_value();
static const int kPositiveIntValueFieldNumber = 4;
- inline ::google::protobuf::uint64 positive_int_value() const;
- inline void set_positive_int_value(::google::protobuf::uint64 value);
-
+ ::google::protobuf::uint64 positive_int_value() const;
+ void set_positive_int_value(::google::protobuf::uint64 value);
+
// optional int64 negative_int_value = 5;
- inline bool has_negative_int_value() const;
- inline void clear_negative_int_value();
+ bool has_negative_int_value() const;
+ void clear_negative_int_value();
static const int kNegativeIntValueFieldNumber = 5;
- inline ::google::protobuf::int64 negative_int_value() const;
- inline void set_negative_int_value(::google::protobuf::int64 value);
-
+ ::google::protobuf::int64 negative_int_value() const;
+ void set_negative_int_value(::google::protobuf::int64 value);
+
// optional double double_value = 6;
- inline bool has_double_value() const;
- inline void clear_double_value();
+ bool has_double_value() const;
+ void clear_double_value();
static const int kDoubleValueFieldNumber = 6;
- inline double double_value() const;
- inline void set_double_value(double value);
-
+ double double_value() const;
+ void set_double_value(double value);
+
// optional bytes string_value = 7;
- inline bool has_string_value() const;
- inline void clear_string_value();
+ bool has_string_value() const;
+ void clear_string_value();
static const int kStringValueFieldNumber = 7;
- inline const ::std::string& string_value() const;
- inline void set_string_value(const ::std::string& value);
- inline void set_string_value(const char* value);
- inline void set_string_value(const void* value, size_t size);
- inline ::std::string* mutable_string_value();
- inline ::std::string* release_string_value();
-
+ const ::std::string& string_value() const;
+ void set_string_value(const ::std::string& value);
+ void set_string_value(const char* value);
+ void set_string_value(const void* value, size_t size);
+ ::std::string* mutable_string_value();
+ ::std::string* release_string_value();
+ void set_allocated_string_value(::std::string* string_value);
+
// optional string aggregate_value = 8;
- inline bool has_aggregate_value() const;
- inline void clear_aggregate_value();
+ bool has_aggregate_value() const;
+ void clear_aggregate_value();
static const int kAggregateValueFieldNumber = 8;
- inline const ::std::string& aggregate_value() const;
- inline void set_aggregate_value(const ::std::string& value);
- inline void set_aggregate_value(const char* value);
- inline void set_aggregate_value(const char* value, size_t size);
- inline ::std::string* mutable_aggregate_value();
- inline ::std::string* release_aggregate_value();
-
+ const ::std::string& aggregate_value() const;
+ void set_aggregate_value(const ::std::string& value);
+ void set_aggregate_value(const char* value);
+ void set_aggregate_value(const char* value, size_t size);
+ ::std::string* mutable_aggregate_value();
+ ::std::string* release_aggregate_value();
+ void set_allocated_aggregate_value(::std::string* aggregate_value);
+
// @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption)
private:
inline void set_has_identifier_value();
@@ -2419,24 +2898,21 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
inline void clear_has_string_value();
inline void set_has_aggregate_value();
inline void clear_has_aggregate_value();
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::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_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
-
+ ::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();
-
+
void InitAsDefaultInstance();
static UninterpretedOption* default_instance_;
};
@@ -2446,37 +2922,39 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me
public:
SourceCodeInfo_Location();
virtual ~SourceCodeInfo_Location();
-
+
SourceCodeInfo_Location(const SourceCodeInfo_Location& from);
-
+
inline SourceCodeInfo_Location& operator=(const SourceCodeInfo_Location& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const SourceCodeInfo_Location& default_instance();
-
+
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);
void MergeFrom(const SourceCodeInfo_Location& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2488,55 +2966,107 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(SourceCodeInfo_Location* other);
+ 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 ----------------------------------------------------
-
+
// accessors -------------------------------------------------------
-
+
// repeated int32 path = 1 [packed = true];
- inline int path_size() const;
- inline void clear_path();
+ int path_size() const;
+ void clear_path();
static const int kPathFieldNumber = 1;
- inline ::google::protobuf::int32 path(int index) const;
- inline void set_path(int index, ::google::protobuf::int32 value);
- inline void add_path(::google::protobuf::int32 value);
- inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+ ::google::protobuf::int32 path(int index) const;
+ void set_path(int index, ::google::protobuf::int32 value);
+ void add_path(::google::protobuf::int32 value);
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
path() const;
- inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
mutable_path();
-
+
// repeated int32 span = 2 [packed = true];
- inline int span_size() const;
- inline void clear_span();
+ int span_size() const;
+ void clear_span();
static const int kSpanFieldNumber = 2;
- inline ::google::protobuf::int32 span(int index) const;
- inline void set_span(int index, ::google::protobuf::int32 value);
- inline void add_span(::google::protobuf::int32 value);
- inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+ ::google::protobuf::int32 span(int index) const;
+ void set_span(int index, ::google::protobuf::int32 value);
+ void add_span(::google::protobuf::int32 value);
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
span() const;
- inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
mutable_span();
-
+
+ // optional string leading_comments = 3;
+ bool has_leading_comments() const;
+ void clear_leading_comments();
+ static const int kLeadingCommentsFieldNumber = 3;
+ const ::std::string& leading_comments() const;
+ void set_leading_comments(const ::std::string& value);
+ void set_leading_comments(const char* value);
+ void set_leading_comments(const char* value, size_t size);
+ ::std::string* mutable_leading_comments();
+ ::std::string* release_leading_comments();
+ void set_allocated_leading_comments(::std::string* leading_comments);
+
+ // optional string trailing_comments = 4;
+ bool has_trailing_comments() const;
+ void clear_trailing_comments();
+ static const int kTrailingCommentsFieldNumber = 4;
+ const ::std::string& trailing_comments() const;
+ void set_trailing_comments(const ::std::string& value);
+ void set_trailing_comments(const char* value);
+ void set_trailing_comments(const char* value, size_t size);
+ ::std::string* mutable_trailing_comments();
+ ::std::string* release_trailing_comments();
+ void set_allocated_trailing_comments(::std::string* trailing_comments);
+
+ // repeated string leading_detached_comments = 6;
+ int leading_detached_comments_size() const;
+ void clear_leading_detached_comments();
+ static const int kLeadingDetachedCommentsFieldNumber = 6;
+ const ::std::string& leading_detached_comments(int index) const;
+ ::std::string* mutable_leading_detached_comments(int index);
+ void set_leading_detached_comments(int index, const ::std::string& value);
+ void set_leading_detached_comments(int index, const char* value);
+ void set_leading_detached_comments(int index, const char* value, size_t size);
+ ::std::string* add_leading_detached_comments();
+ void add_leading_detached_comments(const ::std::string& value);
+ void add_leading_detached_comments(const char* value);
+ void add_leading_detached_comments(const char* value, size_t size);
+ const ::google::protobuf::RepeatedPtrField< ::std::string>& leading_detached_comments() const;
+ ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_leading_detached_comments();
+
// @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location)
private:
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+ inline void set_has_leading_comments();
+ inline void clear_has_leading_comments();
+ inline void set_has_trailing_comments();
+ inline void clear_has_trailing_comments();
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::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_;
-
- mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
-
+ ::google::protobuf::internal::ArenaStringPtr leading_comments_;
+ ::google::protobuf::internal::ArenaStringPtr trailing_comments_;
+ ::google::protobuf::RepeatedPtrField< ::std::string> leading_detached_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();
-
+
void InitAsDefaultInstance();
static SourceCodeInfo_Location* default_instance_;
};
@@ -2546,37 +3076,39 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
public:
SourceCodeInfo();
virtual ~SourceCodeInfo();
-
+
SourceCodeInfo(const SourceCodeInfo& from);
-
+
inline SourceCodeInfo& operator=(const SourceCodeInfo& from) {
CopyFrom(from);
return *this;
}
-
+
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();
}
-
+
static const ::google::protobuf::Descriptor* descriptor();
static const SourceCodeInfo& default_instance();
-
+
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);
void MergeFrom(const SourceCodeInfo& from);
void Clear();
bool IsInitialized() const;
-
+
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
@@ -2588,42 +3120,47 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
+ void InternalSwap(SourceCodeInfo* other);
+ 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 ----------------------------------------------------
-
+
typedef SourceCodeInfo_Location Location;
-
+
// accessors -------------------------------------------------------
-
+
// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
- inline int location_size() const;
- inline void clear_location();
+ int location_size() const;
+ void clear_location();
static const int kLocationFieldNumber = 1;
- inline const ::google::protobuf::SourceCodeInfo_Location& location(int index) const;
- inline ::google::protobuf::SourceCodeInfo_Location* mutable_location(int index);
- inline ::google::protobuf::SourceCodeInfo_Location* add_location();
- inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
+ const ::google::protobuf::SourceCodeInfo_Location& location(int index) const;
+ ::google::protobuf::SourceCodeInfo_Location* mutable_location(int index);
+ ::google::protobuf::SourceCodeInfo_Location* add_location();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
location() const;
- inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
mutable_location();
-
+
// @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo)
private:
-
- ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location > location_;
-
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
- ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
-
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location > location_;
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();
-
+
void InitAsDefaultInstance();
static SourceCodeInfo* default_instance_;
};
@@ -2632,6 +3169,7 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
// ===================================================================
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
// FileDescriptorSet
// repeated .google.protobuf.FileDescriptorProto file = 1;
@@ -2642,20 +3180,25 @@ inline void FileDescriptorSet::clear_file() {
file_.Clear();
}
inline const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorSet.file)
return file_.Get(index);
}
inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorSet.file)
return file_.Mutable(index);
}
inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorSet.file)
return file_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
FileDescriptorSet::file() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file)
return file_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
FileDescriptorSet::mutable_file() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorSet.file)
return &file_;
}
@@ -2674,51 +3217,46 @@ inline void FileDescriptorProto::clear_has_name() {
_has_bits_[0] &= ~0x00000001u;
}
inline void FileDescriptorProto::clear_name() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_name();
}
inline const ::std::string& FileDescriptorProto::name() const {
- return *name_;
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void FileDescriptorProto::set_name(const ::std::string& value) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.name)
}
inline void FileDescriptorProto::set_name(const char* value, size_t size) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(reinterpret_cast<const char*>(value), size);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.name)
}
inline ::std::string* FileDescriptorProto::mutable_name() {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- return name_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* FileDescriptorProto::release_name() {
clear_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
} else {
- ::std::string* temp = name_;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_name();
}
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.name)
}
// optional string package = 2;
@@ -2732,51 +3270,46 @@ inline void FileDescriptorProto::clear_has_package() {
_has_bits_[0] &= ~0x00000002u;
}
inline void FileDescriptorProto::clear_package() {
- if (package_ != &::google::protobuf::internal::kEmptyString) {
- package_->clear();
- }
+ package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_package();
}
inline const ::std::string& FileDescriptorProto::package() const {
- return *package_;
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.package)
+ return package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void FileDescriptorProto::set_package(const ::std::string& value) {
set_has_package();
- if (package_ == &::google::protobuf::internal::kEmptyString) {
- package_ = new ::std::string;
- }
- package_->assign(value);
+ package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- package_ = new ::std::string;
- }
- package_->assign(value);
+ package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.package)
}
inline void FileDescriptorProto::set_package(const char* value, size_t size) {
set_has_package();
- if (package_ == &::google::protobuf::internal::kEmptyString) {
- package_ = new ::std::string;
- }
- package_->assign(reinterpret_cast<const char*>(value), size);
+ package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.package)
}
inline ::std::string* FileDescriptorProto::mutable_package() {
set_has_package();
- if (package_ == &::google::protobuf::internal::kEmptyString) {
- package_ = new ::std::string;
- }
- return package_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.package)
+ return package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* FileDescriptorProto::release_package() {
clear_has_package();
- if (package_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileDescriptorProto::set_allocated_package(::std::string* package) {
+ if (package != NULL) {
+ set_has_package();
} else {
- ::std::string* temp = package_;
- package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_package();
}
+ package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), package);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.package)
}
// repeated string dependency = 3;
@@ -2787,42 +3320,112 @@ inline void FileDescriptorProto::clear_dependency() {
dependency_.Clear();
}
inline const ::std::string& FileDescriptorProto::dependency(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.dependency)
return dependency_.Get(index);
}
inline ::std::string* FileDescriptorProto::mutable_dependency(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.dependency)
return dependency_.Mutable(index);
}
inline void FileDescriptorProto::set_dependency(int index, const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.dependency)
dependency_.Mutable(index)->assign(value);
}
inline void FileDescriptorProto::set_dependency(int index, const char* value) {
dependency_.Mutable(index)->assign(value);
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.dependency)
}
inline void FileDescriptorProto::set_dependency(int index, const char* value, size_t size) {
dependency_.Mutable(index)->assign(
reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency)
}
inline ::std::string* FileDescriptorProto::add_dependency() {
return dependency_.Add();
}
inline void FileDescriptorProto::add_dependency(const ::std::string& value) {
dependency_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.dependency)
}
inline void FileDescriptorProto::add_dependency(const char* value) {
dependency_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add_char:google.protobuf.FileDescriptorProto.dependency)
}
inline void FileDescriptorProto::add_dependency(const char* value, size_t size) {
dependency_.Add()->assign(reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_add_pointer:google.protobuf.FileDescriptorProto.dependency)
}
inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
FileDescriptorProto::dependency() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.dependency)
return dependency_;
}
inline ::google::protobuf::RepeatedPtrField< ::std::string>*
FileDescriptorProto::mutable_dependency() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.dependency)
return &dependency_;
}
+// repeated int32 public_dependency = 10;
+inline int FileDescriptorProto::public_dependency_size() const {
+ return public_dependency_.size();
+}
+inline void FileDescriptorProto::clear_public_dependency() {
+ public_dependency_.Clear();
+}
+inline ::google::protobuf::int32 FileDescriptorProto::public_dependency(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.public_dependency)
+ return public_dependency_.Get(index);
+}
+inline void FileDescriptorProto::set_public_dependency(int index, ::google::protobuf::int32 value) {
+ public_dependency_.Set(index, value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.public_dependency)
+}
+inline void FileDescriptorProto::add_public_dependency(::google::protobuf::int32 value) {
+ public_dependency_.Add(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.public_dependency)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+FileDescriptorProto::public_dependency() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.public_dependency)
+ return public_dependency_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+FileDescriptorProto::mutable_public_dependency() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.public_dependency)
+ return &public_dependency_;
+}
+
+// repeated int32 weak_dependency = 11;
+inline int FileDescriptorProto::weak_dependency_size() const {
+ return weak_dependency_.size();
+}
+inline void FileDescriptorProto::clear_weak_dependency() {
+ weak_dependency_.Clear();
+}
+inline ::google::protobuf::int32 FileDescriptorProto::weak_dependency(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.weak_dependency)
+ return weak_dependency_.Get(index);
+}
+inline void FileDescriptorProto::set_weak_dependency(int index, ::google::protobuf::int32 value) {
+ weak_dependency_.Set(index, value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+inline void FileDescriptorProto::add_weak_dependency(::google::protobuf::int32 value) {
+ weak_dependency_.Add(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+FileDescriptorProto::weak_dependency() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.weak_dependency)
+ return weak_dependency_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+FileDescriptorProto::mutable_weak_dependency() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.weak_dependency)
+ return &weak_dependency_;
+}
+
// repeated .google.protobuf.DescriptorProto message_type = 4;
inline int FileDescriptorProto::message_type_size() const {
return message_type_.size();
@@ -2831,20 +3434,25 @@ inline void FileDescriptorProto::clear_message_type() {
message_type_.Clear();
}
inline const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.message_type)
return message_type_.Get(index);
}
inline ::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.message_type)
return message_type_.Mutable(index);
}
inline ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.message_type)
return message_type_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
FileDescriptorProto::message_type() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type)
return message_type_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
FileDescriptorProto::mutable_message_type() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.message_type)
return &message_type_;
}
@@ -2856,20 +3464,25 @@ inline void FileDescriptorProto::clear_enum_type() {
enum_type_.Clear();
}
inline const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.enum_type)
return enum_type_.Get(index);
}
inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.enum_type)
return enum_type_.Mutable(index);
}
inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.enum_type)
return enum_type_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
FileDescriptorProto::enum_type() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type)
return enum_type_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
FileDescriptorProto::mutable_enum_type() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.enum_type)
return &enum_type_;
}
@@ -2881,20 +3494,25 @@ inline void FileDescriptorProto::clear_service() {
service_.Clear();
}
inline const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.service)
return service_.Get(index);
}
inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.service)
return service_.Mutable(index);
}
inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.service)
return service_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
FileDescriptorProto::service() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service)
return service_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
FileDescriptorProto::mutable_service() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.service)
return &service_;
}
@@ -2906,43 +3524,52 @@ inline void FileDescriptorProto::clear_extension() {
extension_.Clear();
}
inline const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.extension)
return extension_.Get(index);
}
inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.extension)
return extension_.Mutable(index);
}
inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.extension)
return extension_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
FileDescriptorProto::extension() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension)
return extension_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
FileDescriptorProto::mutable_extension() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.extension)
return &extension_;
}
// optional .google.protobuf.FileOptions options = 8;
inline bool FileDescriptorProto::has_options() const {
- return (_has_bits_[0] & 0x00000080u) != 0;
+ return (_has_bits_[0] & 0x00000200u) != 0;
}
inline void FileDescriptorProto::set_has_options() {
- _has_bits_[0] |= 0x00000080u;
+ _has_bits_[0] |= 0x00000200u;
}
inline void FileDescriptorProto::clear_has_options() {
- _has_bits_[0] &= ~0x00000080u;
+ _has_bits_[0] &= ~0x00000200u;
}
inline void FileDescriptorProto::clear_options() {
if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
clear_has_options();
}
inline const ::google::protobuf::FileOptions& FileDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.options)
return options_ != NULL ? *options_ : *default_instance_->options_;
}
inline ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() {
set_has_options();
- if (options_ == NULL) options_ = new ::google::protobuf::FileOptions;
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::FileOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options)
return options_;
}
inline ::google::protobuf::FileOptions* FileDescriptorProto::release_options() {
@@ -2951,27 +3578,41 @@ inline ::google::protobuf::FileOptions* FileDescriptorProto::release_options() {
options_ = NULL;
return temp;
}
+inline void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.options)
+}
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
inline bool FileDescriptorProto::has_source_code_info() const {
- return (_has_bits_[0] & 0x00000100u) != 0;
+ return (_has_bits_[0] & 0x00000400u) != 0;
}
inline void FileDescriptorProto::set_has_source_code_info() {
- _has_bits_[0] |= 0x00000100u;
+ _has_bits_[0] |= 0x00000400u;
}
inline void FileDescriptorProto::clear_has_source_code_info() {
- _has_bits_[0] &= ~0x00000100u;
+ _has_bits_[0] &= ~0x00000400u;
}
inline void FileDescriptorProto::clear_source_code_info() {
if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear();
clear_has_source_code_info();
}
inline const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_code_info() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.source_code_info)
return source_code_info_ != NULL ? *source_code_info_ : *default_instance_->source_code_info_;
}
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_ = new ::google::protobuf::SourceCodeInfo;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info)
return source_code_info_;
}
inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() {
@@ -2980,6 +3621,69 @@ inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_c
source_code_info_ = NULL;
return temp;
}
+inline void FileDescriptorProto::set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info) {
+ 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_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_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_syntax();
+}
+inline const ::std::string& FileDescriptorProto::syntax() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.syntax)
+ return syntax_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileDescriptorProto::set_syntax(const ::std::string& value) {
+ set_has_syntax();
+ syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.syntax)
+}
+inline void FileDescriptorProto::set_syntax(const char* value) {
+ set_has_syntax();
+ syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@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_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* FileDescriptorProto::release_syntax() {
+ clear_has_syntax();
+ return syntax_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileDescriptorProto::set_allocated_syntax(::std::string* syntax) {
+ if (syntax != NULL) {
+ set_has_syntax();
+ } else {
+ clear_has_syntax();
+ }
+ syntax_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), syntax);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.syntax)
+}
// -------------------------------------------------------------------
@@ -3000,11 +3704,13 @@ inline void DescriptorProto_ExtensionRange::clear_start() {
clear_has_start();
}
inline ::google::protobuf::int32 DescriptorProto_ExtensionRange::start() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.start)
return start_;
}
inline void DescriptorProto_ExtensionRange::set_start(::google::protobuf::int32 value) {
set_has_start();
start_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.start)
}
// optional int32 end = 2;
@@ -3022,11 +3728,13 @@ inline void DescriptorProto_ExtensionRange::clear_end() {
clear_has_end();
}
inline ::google::protobuf::int32 DescriptorProto_ExtensionRange::end() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.end)
return end_;
}
inline void DescriptorProto_ExtensionRange::set_end(::google::protobuf::int32 value) {
set_has_end();
end_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.end)
}
// -------------------------------------------------------------------
@@ -3044,51 +3752,46 @@ inline void DescriptorProto::clear_has_name() {
_has_bits_[0] &= ~0x00000001u;
}
inline void DescriptorProto::clear_name() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_name();
}
inline const ::std::string& DescriptorProto::name() const {
- return *name_;
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void DescriptorProto::set_name(const ::std::string& value) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.name)
}
inline void DescriptorProto::set_name(const char* value, size_t size) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(reinterpret_cast<const char*>(value), size);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.name)
}
inline ::std::string* DescriptorProto::mutable_name() {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- return name_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* DescriptorProto::release_name() {
clear_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void DescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
} else {
- ::std::string* temp = name_;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_name();
}
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.name)
}
// repeated .google.protobuf.FieldDescriptorProto field = 2;
@@ -3099,20 +3802,25 @@ inline void DescriptorProto::clear_field() {
field_.Clear();
}
inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.field)
return field_.Get(index);
}
inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.field)
return field_.Mutable(index);
}
inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.field)
return field_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
DescriptorProto::field() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field)
return field_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
DescriptorProto::mutable_field() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.field)
return &field_;
}
@@ -3124,20 +3832,25 @@ inline void DescriptorProto::clear_extension() {
extension_.Clear();
}
inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension)
return extension_.Get(index);
}
inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension)
return extension_.Mutable(index);
}
inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension)
return extension_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
DescriptorProto::extension() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension)
return extension_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
DescriptorProto::mutable_extension() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension)
return &extension_;
}
@@ -3149,20 +3862,25 @@ inline void DescriptorProto::clear_nested_type() {
nested_type_.Clear();
}
inline const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.nested_type)
return nested_type_.Get(index);
}
inline ::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.nested_type)
return nested_type_.Mutable(index);
}
inline ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.nested_type)
return nested_type_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
DescriptorProto::nested_type() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type)
return nested_type_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
DescriptorProto::mutable_nested_type() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.nested_type)
return &nested_type_;
}
@@ -3174,20 +3892,25 @@ inline void DescriptorProto::clear_enum_type() {
enum_type_.Clear();
}
inline const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.enum_type)
return enum_type_.Get(index);
}
inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.enum_type)
return enum_type_.Mutable(index);
}
inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.enum_type)
return enum_type_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
DescriptorProto::enum_type() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type)
return enum_type_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
DescriptorProto::mutable_enum_type() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.enum_type)
return &enum_type_;
}
@@ -3199,43 +3922,82 @@ inline void DescriptorProto::clear_extension_range() {
extension_range_.Clear();
}
inline const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension_range)
return extension_range_.Get(index);
}
inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension_range)
return extension_range_.Mutable(index);
}
inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension_range)
return extension_range_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
DescriptorProto::extension_range() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range)
return extension_range_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
DescriptorProto::mutable_extension_range() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension_range)
return &extension_range_;
}
+// repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+inline int DescriptorProto::oneof_decl_size() const {
+ return oneof_decl_.size();
+}
+inline void DescriptorProto::clear_oneof_decl() {
+ oneof_decl_.Clear();
+}
+inline const ::google::protobuf::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.oneof_decl)
+ return oneof_decl_.Get(index);
+}
+inline ::google::protobuf::OneofDescriptorProto* DescriptorProto::mutable_oneof_decl(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.oneof_decl)
+ return oneof_decl_.Mutable(index);
+}
+inline ::google::protobuf::OneofDescriptorProto* DescriptorProto::add_oneof_decl() {
+ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.oneof_decl)
+ return oneof_decl_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
+DescriptorProto::oneof_decl() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl)
+ return oneof_decl_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >*
+DescriptorProto::mutable_oneof_decl() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.oneof_decl)
+ return &oneof_decl_;
+}
+
// optional .google.protobuf.MessageOptions options = 7;
inline bool DescriptorProto::has_options() const {
- return (_has_bits_[0] & 0x00000040u) != 0;
+ return (_has_bits_[0] & 0x00000080u) != 0;
}
inline void DescriptorProto::set_has_options() {
- _has_bits_[0] |= 0x00000040u;
+ _has_bits_[0] |= 0x00000080u;
}
inline void DescriptorProto::clear_has_options() {
- _has_bits_[0] &= ~0x00000040u;
+ _has_bits_[0] &= ~0x00000080u;
}
inline void DescriptorProto::clear_options() {
if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear();
clear_has_options();
}
inline const ::google::protobuf::MessageOptions& DescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.options)
return options_ != NULL ? *options_ : *default_instance_->options_;
}
inline ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() {
set_has_options();
- if (options_ == NULL) options_ = new ::google::protobuf::MessageOptions;
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::MessageOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options)
return options_;
}
inline ::google::protobuf::MessageOptions* DescriptorProto::release_options() {
@@ -3244,6 +4006,16 @@ inline ::google::protobuf::MessageOptions* DescriptorProto::release_options() {
options_ = NULL;
return temp;
}
+inline void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options)
+}
// -------------------------------------------------------------------
@@ -3260,51 +4032,46 @@ inline void FieldDescriptorProto::clear_has_name() {
_has_bits_[0] &= ~0x00000001u;
}
inline void FieldDescriptorProto::clear_name() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_name();
}
inline const ::std::string& FieldDescriptorProto::name() const {
- return *name_;
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void FieldDescriptorProto::set_name(const ::std::string& value) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.name)
}
inline void FieldDescriptorProto::set_name(const char* value, size_t size) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(reinterpret_cast<const char*>(value), size);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.name)
}
inline ::std::string* FieldDescriptorProto::mutable_name() {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- return name_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* FieldDescriptorProto::release_name() {
clear_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FieldDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
} else {
- ::std::string* temp = name_;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_name();
}
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.name)
}
// optional int32 number = 3;
@@ -3322,11 +4089,13 @@ inline void FieldDescriptorProto::clear_number() {
clear_has_number();
}
inline ::google::protobuf::int32 FieldDescriptorProto::number() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.number)
return number_;
}
inline void FieldDescriptorProto::set_number(::google::protobuf::int32 value) {
set_has_number();
number_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.number)
}
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
@@ -3344,12 +4113,14 @@ inline void FieldDescriptorProto::clear_label() {
clear_has_label();
}
inline ::google::protobuf::FieldDescriptorProto_Label FieldDescriptorProto::label() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.label)
return static_cast< ::google::protobuf::FieldDescriptorProto_Label >(label_);
}
inline void FieldDescriptorProto::set_label(::google::protobuf::FieldDescriptorProto_Label value) {
- GOOGLE_DCHECK(::google::protobuf::FieldDescriptorProto_Label_IsValid(value));
+ assert(::google::protobuf::FieldDescriptorProto_Label_IsValid(value));
set_has_label();
label_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.label)
}
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
@@ -3367,12 +4138,14 @@ inline void FieldDescriptorProto::clear_type() {
clear_has_type();
}
inline ::google::protobuf::FieldDescriptorProto_Type FieldDescriptorProto::type() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type)
return static_cast< ::google::protobuf::FieldDescriptorProto_Type >(type_);
}
inline void FieldDescriptorProto::set_type(::google::protobuf::FieldDescriptorProto_Type value) {
- GOOGLE_DCHECK(::google::protobuf::FieldDescriptorProto_Type_IsValid(value));
+ assert(::google::protobuf::FieldDescriptorProto_Type_IsValid(value));
set_has_type();
type_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type)
}
// optional string type_name = 6;
@@ -3386,51 +4159,46 @@ inline void FieldDescriptorProto::clear_has_type_name() {
_has_bits_[0] &= ~0x00000010u;
}
inline void FieldDescriptorProto::clear_type_name() {
- if (type_name_ != &::google::protobuf::internal::kEmptyString) {
- type_name_->clear();
- }
+ type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_type_name();
}
inline const ::std::string& FieldDescriptorProto::type_name() const {
- return *type_name_;
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type_name)
+ return type_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void FieldDescriptorProto::set_type_name(const ::std::string& value) {
set_has_type_name();
- if (type_name_ == &::google::protobuf::internal::kEmptyString) {
- type_name_ = new ::std::string;
- }
- type_name_->assign(value);
+ type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- type_name_ = new ::std::string;
- }
- type_name_->assign(value);
+ type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.type_name)
}
inline void FieldDescriptorProto::set_type_name(const char* value, size_t size) {
set_has_type_name();
- if (type_name_ == &::google::protobuf::internal::kEmptyString) {
- type_name_ = new ::std::string;
- }
- type_name_->assign(reinterpret_cast<const char*>(value), size);
+ type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- type_name_ = new ::std::string;
- }
- return type_name_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.type_name)
+ return type_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* FieldDescriptorProto::release_type_name() {
clear_has_type_name();
- if (type_name_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return type_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FieldDescriptorProto::set_allocated_type_name(::std::string* type_name) {
+ if (type_name != NULL) {
+ set_has_type_name();
} else {
- ::std::string* temp = type_name_;
- type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_type_name();
}
+ type_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.type_name)
}
// optional string extendee = 2;
@@ -3444,51 +4212,46 @@ inline void FieldDescriptorProto::clear_has_extendee() {
_has_bits_[0] &= ~0x00000020u;
}
inline void FieldDescriptorProto::clear_extendee() {
- if (extendee_ != &::google::protobuf::internal::kEmptyString) {
- extendee_->clear();
- }
+ extendee_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_extendee();
}
inline const ::std::string& FieldDescriptorProto::extendee() const {
- return *extendee_;
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.extendee)
+ return extendee_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void FieldDescriptorProto::set_extendee(const ::std::string& value) {
set_has_extendee();
- if (extendee_ == &::google::protobuf::internal::kEmptyString) {
- extendee_ = new ::std::string;
- }
- extendee_->assign(value);
+ extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- extendee_ = new ::std::string;
- }
- extendee_->assign(value);
+ extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.extendee)
}
inline void FieldDescriptorProto::set_extendee(const char* value, size_t size) {
set_has_extendee();
- if (extendee_ == &::google::protobuf::internal::kEmptyString) {
- extendee_ = new ::std::string;
- }
- extendee_->assign(reinterpret_cast<const char*>(value), size);
+ extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.extendee)
}
inline ::std::string* FieldDescriptorProto::mutable_extendee() {
set_has_extendee();
- if (extendee_ == &::google::protobuf::internal::kEmptyString) {
- extendee_ = new ::std::string;
- }
- return extendee_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.extendee)
+ return extendee_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* FieldDescriptorProto::release_extendee() {
clear_has_extendee();
- if (extendee_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return extendee_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FieldDescriptorProto::set_allocated_extendee(::std::string* extendee) {
+ if (extendee != NULL) {
+ set_has_extendee();
} else {
- ::std::string* temp = extendee_;
- extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_extendee();
}
+ extendee_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), extendee);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.extendee)
}
// optional string default_value = 7;
@@ -3502,73 +4265,96 @@ inline void FieldDescriptorProto::clear_has_default_value() {
_has_bits_[0] &= ~0x00000040u;
}
inline void FieldDescriptorProto::clear_default_value() {
- if (default_value_ != &::google::protobuf::internal::kEmptyString) {
- default_value_->clear();
- }
+ default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_default_value();
}
inline const ::std::string& FieldDescriptorProto::default_value() const {
- return *default_value_;
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.default_value)
+ return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void FieldDescriptorProto::set_default_value(const ::std::string& value) {
set_has_default_value();
- if (default_value_ == &::google::protobuf::internal::kEmptyString) {
- default_value_ = new ::std::string;
- }
- default_value_->assign(value);
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- default_value_ = new ::std::string;
- }
- default_value_->assign(value);
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.default_value)
}
inline void FieldDescriptorProto::set_default_value(const char* value, size_t size) {
set_has_default_value();
- if (default_value_ == &::google::protobuf::internal::kEmptyString) {
- default_value_ = new ::std::string;
- }
- default_value_->assign(reinterpret_cast<const char*>(value), size);
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- default_value_ = new ::std::string;
- }
- return default_value_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.default_value)
+ return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* FieldDescriptorProto::release_default_value() {
clear_has_default_value();
- if (default_value_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FieldDescriptorProto::set_allocated_default_value(::std::string* default_value) {
+ if (default_value != NULL) {
+ set_has_default_value();
} else {
- ::std::string* temp = default_value_;
- default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_default_value();
}
+ default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.default_value)
+}
+
+// optional int32 oneof_index = 9;
+inline bool FieldDescriptorProto::has_oneof_index() const {
+ return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void FieldDescriptorProto::set_has_oneof_index() {
+ _has_bits_[0] |= 0x00000080u;
+}
+inline void FieldDescriptorProto::clear_has_oneof_index() {
+ _has_bits_[0] &= ~0x00000080u;
+}
+inline void FieldDescriptorProto::clear_oneof_index() {
+ oneof_index_ = 0;
+ clear_has_oneof_index();
+}
+inline ::google::protobuf::int32 FieldDescriptorProto::oneof_index() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.oneof_index)
+ return oneof_index_;
+}
+inline void FieldDescriptorProto::set_oneof_index(::google::protobuf::int32 value) {
+ set_has_oneof_index();
+ oneof_index_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
}
// optional .google.protobuf.FieldOptions options = 8;
inline bool FieldDescriptorProto::has_options() const {
- return (_has_bits_[0] & 0x00000080u) != 0;
+ return (_has_bits_[0] & 0x00000100u) != 0;
}
inline void FieldDescriptorProto::set_has_options() {
- _has_bits_[0] |= 0x00000080u;
+ _has_bits_[0] |= 0x00000100u;
}
inline void FieldDescriptorProto::clear_has_options() {
- _has_bits_[0] &= ~0x00000080u;
+ _has_bits_[0] &= ~0x00000100u;
}
inline void FieldDescriptorProto::clear_options() {
if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
clear_has_options();
}
inline const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.options)
return options_ != NULL ? *options_ : *default_instance_->options_;
}
inline ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() {
set_has_options();
- if (options_ == NULL) options_ = new ::google::protobuf::FieldOptions;
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::FieldOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options)
return options_;
}
inline ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() {
@@ -3577,6 +4363,73 @@ inline ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options()
options_ = NULL;
return temp;
}
+inline void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.options)
+}
+
+// -------------------------------------------------------------------
+
+// OneofDescriptorProto
+
+// optional string name = 1;
+inline bool OneofDescriptorProto::has_name() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void OneofDescriptorProto::set_has_name() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void OneofDescriptorProto::clear_has_name() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void OneofDescriptorProto::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_name();
+}
+inline const ::std::string& OneofDescriptorProto::name() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OneofDescriptorProto::set_name(const ::std::string& value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.OneofDescriptorProto.name)
+}
+inline void OneofDescriptorProto::set_name(const char* value) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.OneofDescriptorProto.name)
+}
+inline void OneofDescriptorProto::set_name(const char* value, size_t size) {
+ set_has_name();
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.OneofDescriptorProto.name)
+}
+inline ::std::string* OneofDescriptorProto::mutable_name() {
+ set_has_name();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* OneofDescriptorProto::release_name() {
+ clear_has_name();
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OneofDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
+ } else {
+ clear_has_name();
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
+}
// -------------------------------------------------------------------
@@ -3593,51 +4446,46 @@ inline void EnumDescriptorProto::clear_has_name() {
_has_bits_[0] &= ~0x00000001u;
}
inline void EnumDescriptorProto::clear_name() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_name();
}
inline const ::std::string& EnumDescriptorProto::name() const {
- return *name_;
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void EnumDescriptorProto::set_name(const ::std::string& value) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.EnumDescriptorProto.name)
}
inline void EnumDescriptorProto::set_name(const char* value, size_t size) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(reinterpret_cast<const char*>(value), size);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumDescriptorProto.name)
}
inline ::std::string* EnumDescriptorProto::mutable_name() {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- return name_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* EnumDescriptorProto::release_name() {
clear_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void EnumDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
} else {
- ::std::string* temp = name_;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_name();
}
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.name)
}
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
@@ -3648,20 +4496,25 @@ inline void EnumDescriptorProto::clear_value() {
value_.Clear();
}
inline const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.value)
return value_.Get(index);
}
inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.value)
return value_.Mutable(index);
}
inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() {
+ // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.value)
return value_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
EnumDescriptorProto::value() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value)
return value_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
EnumDescriptorProto::mutable_value() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.value)
return &value_;
}
@@ -3680,11 +4533,15 @@ inline void EnumDescriptorProto::clear_options() {
clear_has_options();
}
inline const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.options)
return options_ != NULL ? *options_ : *default_instance_->options_;
}
inline ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() {
set_has_options();
- if (options_ == NULL) options_ = new ::google::protobuf::EnumOptions;
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::EnumOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options)
return options_;
}
inline ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() {
@@ -3693,6 +4550,16 @@ inline ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() {
options_ = NULL;
return temp;
}
+inline void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.options)
+}
// -------------------------------------------------------------------
@@ -3709,51 +4576,46 @@ inline void EnumValueDescriptorProto::clear_has_name() {
_has_bits_[0] &= ~0x00000001u;
}
inline void EnumValueDescriptorProto::clear_name() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_name();
}
inline const ::std::string& EnumValueDescriptorProto::name() const {
- return *name_;
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void EnumValueDescriptorProto::set_name(const ::std::string& value) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.EnumValueDescriptorProto.name)
}
inline void EnumValueDescriptorProto::set_name(const char* value, size_t size) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(reinterpret_cast<const char*>(value), size);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumValueDescriptorProto.name)
}
inline ::std::string* EnumValueDescriptorProto::mutable_name() {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- return name_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* EnumValueDescriptorProto::release_name() {
clear_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void EnumValueDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
} else {
- ::std::string* temp = name_;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_name();
}
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.name)
}
// optional int32 number = 2;
@@ -3771,11 +4633,13 @@ inline void EnumValueDescriptorProto::clear_number() {
clear_has_number();
}
inline ::google::protobuf::int32 EnumValueDescriptorProto::number() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.number)
return number_;
}
inline void EnumValueDescriptorProto::set_number(::google::protobuf::int32 value) {
set_has_number();
number_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.number)
}
// optional .google.protobuf.EnumValueOptions options = 3;
@@ -3793,11 +4657,15 @@ inline void EnumValueDescriptorProto::clear_options() {
clear_has_options();
}
inline const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.options)
return options_ != NULL ? *options_ : *default_instance_->options_;
}
inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() {
set_has_options();
- if (options_ == NULL) options_ = new ::google::protobuf::EnumValueOptions;
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::EnumValueOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options)
return options_;
}
inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() {
@@ -3806,6 +4674,16 @@ inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_o
options_ = NULL;
return temp;
}
+inline void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.options)
+}
// -------------------------------------------------------------------
@@ -3822,51 +4700,46 @@ inline void ServiceDescriptorProto::clear_has_name() {
_has_bits_[0] &= ~0x00000001u;
}
inline void ServiceDescriptorProto::clear_name() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_name();
}
inline const ::std::string& ServiceDescriptorProto::name() const {
- return *name_;
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void ServiceDescriptorProto::set_name(const ::std::string& value) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.ServiceDescriptorProto.name)
}
inline void ServiceDescriptorProto::set_name(const char* value, size_t size) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(reinterpret_cast<const char*>(value), size);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.ServiceDescriptorProto.name)
}
inline ::std::string* ServiceDescriptorProto::mutable_name() {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- return name_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* ServiceDescriptorProto::release_name() {
clear_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void ServiceDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
} else {
- ::std::string* temp = name_;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_name();
}
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.name)
}
// repeated .google.protobuf.MethodDescriptorProto method = 2;
@@ -3877,20 +4750,25 @@ inline void ServiceDescriptorProto::clear_method() {
method_.Clear();
}
inline const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.method)
return method_.Get(index);
}
inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.method)
return method_.Mutable(index);
}
inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() {
+ // @@protoc_insertion_point(field_add:google.protobuf.ServiceDescriptorProto.method)
return method_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
ServiceDescriptorProto::method() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method)
return method_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
ServiceDescriptorProto::mutable_method() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceDescriptorProto.method)
return &method_;
}
@@ -3909,11 +4787,15 @@ inline void ServiceDescriptorProto::clear_options() {
clear_has_options();
}
inline const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.options)
return options_ != NULL ? *options_ : *default_instance_->options_;
}
inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() {
set_has_options();
- if (options_ == NULL) options_ = new ::google::protobuf::ServiceOptions;
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::ServiceOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options)
return options_;
}
inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() {
@@ -3922,6 +4804,16 @@ inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_optio
options_ = NULL;
return temp;
}
+inline void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.options)
+}
// -------------------------------------------------------------------
@@ -3938,51 +4830,46 @@ inline void MethodDescriptorProto::clear_has_name() {
_has_bits_[0] &= ~0x00000001u;
}
inline void MethodDescriptorProto::clear_name() {
- if (name_ != &::google::protobuf::internal::kEmptyString) {
- name_->clear();
- }
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_name();
}
inline const ::std::string& MethodDescriptorProto::name() const {
- return *name_;
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void MethodDescriptorProto::set_name(const ::std::string& value) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(value);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.name)
}
inline void MethodDescriptorProto::set_name(const char* value, size_t size) {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- name_->assign(reinterpret_cast<const char*>(value), size);
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.name)
}
inline ::std::string* MethodDescriptorProto::mutable_name() {
set_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- name_ = new ::std::string;
- }
- return name_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* MethodDescriptorProto::release_name() {
clear_has_name();
- if (name_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void MethodDescriptorProto::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+ set_has_name();
} else {
- ::std::string* temp = name_;
- name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_name();
}
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.name)
}
// optional string input_type = 2;
@@ -3996,51 +4883,46 @@ inline void MethodDescriptorProto::clear_has_input_type() {
_has_bits_[0] &= ~0x00000002u;
}
inline void MethodDescriptorProto::clear_input_type() {
- if (input_type_ != &::google::protobuf::internal::kEmptyString) {
- input_type_->clear();
- }
+ input_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_input_type();
}
inline const ::std::string& MethodDescriptorProto::input_type() const {
- return *input_type_;
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.input_type)
+ return input_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void MethodDescriptorProto::set_input_type(const ::std::string& value) {
set_has_input_type();
- if (input_type_ == &::google::protobuf::internal::kEmptyString) {
- input_type_ = new ::std::string;
- }
- input_type_->assign(value);
+ input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- input_type_ = new ::std::string;
- }
- input_type_->assign(value);
+ input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.input_type)
}
inline void MethodDescriptorProto::set_input_type(const char* value, size_t size) {
set_has_input_type();
- if (input_type_ == &::google::protobuf::internal::kEmptyString) {
- input_type_ = new ::std::string;
- }
- input_type_->assign(reinterpret_cast<const char*>(value), size);
+ input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- input_type_ = new ::std::string;
- }
- return input_type_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.input_type)
+ return input_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* MethodDescriptorProto::release_input_type() {
clear_has_input_type();
- if (input_type_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return input_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void MethodDescriptorProto::set_allocated_input_type(::std::string* input_type) {
+ if (input_type != NULL) {
+ set_has_input_type();
} else {
- ::std::string* temp = input_type_;
- input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_input_type();
}
+ input_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), input_type);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.input_type)
}
// optional string output_type = 3;
@@ -4054,51 +4936,46 @@ inline void MethodDescriptorProto::clear_has_output_type() {
_has_bits_[0] &= ~0x00000004u;
}
inline void MethodDescriptorProto::clear_output_type() {
- if (output_type_ != &::google::protobuf::internal::kEmptyString) {
- output_type_->clear();
- }
+ output_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_output_type();
}
inline const ::std::string& MethodDescriptorProto::output_type() const {
- return *output_type_;
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.output_type)
+ return output_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void MethodDescriptorProto::set_output_type(const ::std::string& value) {
set_has_output_type();
- if (output_type_ == &::google::protobuf::internal::kEmptyString) {
- output_type_ = new ::std::string;
- }
- output_type_->assign(value);
+ output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- output_type_ = new ::std::string;
- }
- output_type_->assign(value);
+ output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.output_type)
}
inline void MethodDescriptorProto::set_output_type(const char* value, size_t size) {
set_has_output_type();
- if (output_type_ == &::google::protobuf::internal::kEmptyString) {
- output_type_ = new ::std::string;
- }
- output_type_->assign(reinterpret_cast<const char*>(value), size);
+ output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- output_type_ = new ::std::string;
- }
- return output_type_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.output_type)
+ return output_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* MethodDescriptorProto::release_output_type() {
clear_has_output_type();
- if (output_type_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return output_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void MethodDescriptorProto::set_allocated_output_type(::std::string* output_type) {
+ if (output_type != NULL) {
+ set_has_output_type();
} else {
- ::std::string* temp = output_type_;
- output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_output_type();
}
+ output_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), output_type);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.output_type)
}
// optional .google.protobuf.MethodOptions options = 4;
@@ -4116,11 +4993,15 @@ inline void MethodDescriptorProto::clear_options() {
clear_has_options();
}
inline const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.options)
return options_ != NULL ? *options_ : *default_instance_->options_;
}
inline ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() {
set_has_options();
- if (options_ == NULL) options_ = new ::google::protobuf::MethodOptions;
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::MethodOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options)
return options_;
}
inline ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() {
@@ -4129,6 +5010,64 @@ inline ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options
options_ = NULL;
return temp;
}
+inline void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.options)
+}
+
+// optional bool client_streaming = 5 [default = false];
+inline bool MethodDescriptorProto::has_client_streaming() const {
+ return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void MethodDescriptorProto::set_has_client_streaming() {
+ _has_bits_[0] |= 0x00000010u;
+}
+inline void MethodDescriptorProto::clear_has_client_streaming() {
+ _has_bits_[0] &= ~0x00000010u;
+}
+inline void MethodDescriptorProto::clear_client_streaming() {
+ client_streaming_ = false;
+ clear_has_client_streaming();
+}
+inline bool MethodDescriptorProto::client_streaming() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.client_streaming)
+ return client_streaming_;
+}
+inline void MethodDescriptorProto::set_client_streaming(bool value) {
+ set_has_client_streaming();
+ client_streaming_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.client_streaming)
+}
+
+// optional bool server_streaming = 6 [default = false];
+inline bool MethodDescriptorProto::has_server_streaming() const {
+ return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void MethodDescriptorProto::set_has_server_streaming() {
+ _has_bits_[0] |= 0x00000020u;
+}
+inline void MethodDescriptorProto::clear_has_server_streaming() {
+ _has_bits_[0] &= ~0x00000020u;
+}
+inline void MethodDescriptorProto::clear_server_streaming() {
+ server_streaming_ = false;
+ clear_has_server_streaming();
+}
+inline bool MethodDescriptorProto::server_streaming() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.server_streaming)
+ return server_streaming_;
+}
+inline void MethodDescriptorProto::set_server_streaming(bool value) {
+ set_has_server_streaming();
+ server_streaming_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.server_streaming)
+}
// -------------------------------------------------------------------
@@ -4145,51 +5084,46 @@ inline void FileOptions::clear_has_java_package() {
_has_bits_[0] &= ~0x00000001u;
}
inline void FileOptions::clear_java_package() {
- if (java_package_ != &::google::protobuf::internal::kEmptyString) {
- java_package_->clear();
- }
+ java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_java_package();
}
inline const ::std::string& FileOptions::java_package() const {
- return *java_package_;
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_package)
+ return java_package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void FileOptions::set_java_package(const ::std::string& value) {
set_has_java_package();
- if (java_package_ == &::google::protobuf::internal::kEmptyString) {
- java_package_ = new ::std::string;
- }
- java_package_->assign(value);
+ java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- java_package_ = new ::std::string;
- }
- java_package_->assign(value);
+ java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.java_package)
}
inline void FileOptions::set_java_package(const char* value, size_t size) {
set_has_java_package();
- if (java_package_ == &::google::protobuf::internal::kEmptyString) {
- java_package_ = new ::std::string;
- }
- java_package_->assign(reinterpret_cast<const char*>(value), size);
+ java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- java_package_ = new ::std::string;
- }
- return java_package_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_package)
+ return java_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* FileOptions::release_java_package() {
clear_has_java_package();
- if (java_package_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return java_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_allocated_java_package(::std::string* java_package) {
+ if (java_package != NULL) {
+ set_has_java_package();
} else {
- ::std::string* temp = java_package_;
- java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_java_package();
}
+ java_package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_package);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_package)
}
// optional string java_outer_classname = 8;
@@ -4203,51 +5137,46 @@ 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::kEmptyString) {
- java_outer_classname_->clear();
- }
+ java_outer_classname_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_java_outer_classname();
}
inline const ::std::string& FileOptions::java_outer_classname() const {
- return *java_outer_classname_;
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_outer_classname)
+ return java_outer_classname_.GetNoArena(&::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::kEmptyString) {
- java_outer_classname_ = new ::std::string;
- }
- java_outer_classname_->assign(value);
+ java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- java_outer_classname_ = new ::std::string;
- }
- java_outer_classname_->assign(value);
+ java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@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) {
set_has_java_outer_classname();
- if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) {
- java_outer_classname_ = new ::std::string;
- }
- java_outer_classname_->assign(reinterpret_cast<const char*>(value), size);
+ java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- java_outer_classname_ = new ::std::string;
- }
- return java_outer_classname_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_outer_classname)
+ return java_outer_classname_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* FileOptions::release_java_outer_classname() {
clear_has_java_outer_classname();
- if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return java_outer_classname_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_allocated_java_outer_classname(::std::string* java_outer_classname) {
+ if (java_outer_classname != NULL) {
+ set_has_java_outer_classname();
} else {
- ::std::string* temp = java_outer_classname_;
- java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_java_outer_classname();
}
+ java_outer_classname_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_outer_classname);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_outer_classname)
}
// optional bool java_multiple_files = 10 [default = false];
@@ -4265,11 +5194,13 @@ inline void FileOptions::clear_java_multiple_files() {
clear_has_java_multiple_files();
}
inline bool FileOptions::java_multiple_files() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_multiple_files)
return java_multiple_files_;
}
inline void FileOptions::set_java_multiple_files(bool value) {
set_has_java_multiple_files();
java_multiple_files_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_multiple_files)
}
// optional bool java_generate_equals_and_hash = 20 [default = false];
@@ -4287,100 +5218,288 @@ inline void FileOptions::clear_java_generate_equals_and_hash() {
clear_has_java_generate_equals_and_hash();
}
inline bool FileOptions::java_generate_equals_and_hash() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generate_equals_and_hash)
return java_generate_equals_and_hash_;
}
inline void FileOptions::set_java_generate_equals_and_hash(bool value) {
set_has_java_generate_equals_and_hash();
java_generate_equals_and_hash_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generate_equals_and_hash)
+}
+
+// optional bool java_string_check_utf8 = 27 [default = false];
+inline bool FileOptions::has_java_string_check_utf8() const {
+ return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void FileOptions::set_has_java_string_check_utf8() {
+ _has_bits_[0] |= 0x00000010u;
+}
+inline void FileOptions::clear_has_java_string_check_utf8() {
+ _has_bits_[0] &= ~0x00000010u;
+}
+inline void FileOptions::clear_java_string_check_utf8() {
+ java_string_check_utf8_ = false;
+ clear_has_java_string_check_utf8();
+}
+inline bool FileOptions::java_string_check_utf8() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_string_check_utf8)
+ return java_string_check_utf8_;
+}
+inline void FileOptions::set_java_string_check_utf8(bool value) {
+ set_has_java_string_check_utf8();
+ java_string_check_utf8_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_string_check_utf8)
}
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
inline bool FileOptions::has_optimize_for() const {
- return (_has_bits_[0] & 0x00000010u) != 0;
+ return (_has_bits_[0] & 0x00000020u) != 0;
}
inline void FileOptions::set_has_optimize_for() {
- _has_bits_[0] |= 0x00000010u;
+ _has_bits_[0] |= 0x00000020u;
}
inline void FileOptions::clear_has_optimize_for() {
- _has_bits_[0] &= ~0x00000010u;
+ _has_bits_[0] &= ~0x00000020u;
}
inline void FileOptions::clear_optimize_for() {
optimize_for_ = 1;
clear_has_optimize_for();
}
inline ::google::protobuf::FileOptions_OptimizeMode FileOptions::optimize_for() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.optimize_for)
return static_cast< ::google::protobuf::FileOptions_OptimizeMode >(optimize_for_);
}
inline void FileOptions::set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value) {
- GOOGLE_DCHECK(::google::protobuf::FileOptions_OptimizeMode_IsValid(value));
+ assert(::google::protobuf::FileOptions_OptimizeMode_IsValid(value));
set_has_optimize_for();
optimize_for_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.optimize_for)
+}
+
+// optional string go_package = 11;
+inline bool FileOptions::has_go_package() const {
+ return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void FileOptions::set_has_go_package() {
+ _has_bits_[0] |= 0x00000040u;
+}
+inline void FileOptions::clear_has_go_package() {
+ _has_bits_[0] &= ~0x00000040u;
+}
+inline void FileOptions::clear_go_package() {
+ go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ 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_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_go_package(const ::std::string& value) {
+ set_has_go_package();
+ go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.go_package)
+}
+inline void FileOptions::set_go_package(const char* value) {
+ set_has_go_package();
+ go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.go_package)
+}
+inline void FileOptions::set_go_package(const char* value, size_t size) {
+ set_has_go_package();
+ go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.go_package)
+}
+inline ::std::string* FileOptions::mutable_go_package() {
+ set_has_go_package();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.go_package)
+ return go_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* FileOptions::release_go_package() {
+ clear_has_go_package();
+ return go_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_allocated_go_package(::std::string* go_package) {
+ if (go_package != NULL) {
+ set_has_go_package();
+ } else {
+ clear_has_go_package();
+ }
+ go_package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), go_package);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.go_package)
}
// optional bool cc_generic_services = 16 [default = false];
inline bool FileOptions::has_cc_generic_services() const {
- return (_has_bits_[0] & 0x00000020u) != 0;
+ return (_has_bits_[0] & 0x00000080u) != 0;
}
inline void FileOptions::set_has_cc_generic_services() {
- _has_bits_[0] |= 0x00000020u;
+ _has_bits_[0] |= 0x00000080u;
}
inline void FileOptions::clear_has_cc_generic_services() {
- _has_bits_[0] &= ~0x00000020u;
+ _has_bits_[0] &= ~0x00000080u;
}
inline void FileOptions::clear_cc_generic_services() {
cc_generic_services_ = false;
clear_has_cc_generic_services();
}
inline bool FileOptions::cc_generic_services() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_generic_services)
return cc_generic_services_;
}
inline void FileOptions::set_cc_generic_services(bool value) {
set_has_cc_generic_services();
cc_generic_services_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_generic_services)
}
// optional bool java_generic_services = 17 [default = false];
inline bool FileOptions::has_java_generic_services() const {
- return (_has_bits_[0] & 0x00000040u) != 0;
+ return (_has_bits_[0] & 0x00000100u) != 0;
}
inline void FileOptions::set_has_java_generic_services() {
- _has_bits_[0] |= 0x00000040u;
+ _has_bits_[0] |= 0x00000100u;
}
inline void FileOptions::clear_has_java_generic_services() {
- _has_bits_[0] &= ~0x00000040u;
+ _has_bits_[0] &= ~0x00000100u;
}
inline void FileOptions::clear_java_generic_services() {
java_generic_services_ = false;
clear_has_java_generic_services();
}
inline bool FileOptions::java_generic_services() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generic_services)
return java_generic_services_;
}
inline void FileOptions::set_java_generic_services(bool value) {
set_has_java_generic_services();
java_generic_services_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generic_services)
}
// optional bool py_generic_services = 18 [default = false];
inline bool FileOptions::has_py_generic_services() const {
- return (_has_bits_[0] & 0x00000080u) != 0;
+ return (_has_bits_[0] & 0x00000200u) != 0;
}
inline void FileOptions::set_has_py_generic_services() {
- _has_bits_[0] |= 0x00000080u;
+ _has_bits_[0] |= 0x00000200u;
}
inline void FileOptions::clear_has_py_generic_services() {
- _has_bits_[0] &= ~0x00000080u;
+ _has_bits_[0] &= ~0x00000200u;
}
inline void FileOptions::clear_py_generic_services() {
py_generic_services_ = false;
clear_has_py_generic_services();
}
inline bool FileOptions::py_generic_services() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.py_generic_services)
return py_generic_services_;
}
inline void FileOptions::set_py_generic_services(bool value) {
set_has_py_generic_services();
py_generic_services_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.py_generic_services)
+}
+
+// optional bool deprecated = 23 [default = false];
+inline bool FileOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000400u) != 0;
+}
+inline void FileOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000400u;
+}
+inline void FileOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000400u;
+}
+inline void FileOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+inline bool FileOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.deprecated)
+ return deprecated_;
+}
+inline void FileOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.deprecated)
+}
+
+// optional bool cc_enable_arenas = 31 [default = false];
+inline bool FileOptions::has_cc_enable_arenas() const {
+ return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void FileOptions::set_has_cc_enable_arenas() {
+ _has_bits_[0] |= 0x00000800u;
+}
+inline void FileOptions::clear_has_cc_enable_arenas() {
+ _has_bits_[0] &= ~0x00000800u;
+}
+inline void FileOptions::clear_cc_enable_arenas() {
+ cc_enable_arenas_ = false;
+ clear_has_cc_enable_arenas();
+}
+inline bool FileOptions::cc_enable_arenas() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_enable_arenas)
+ return cc_enable_arenas_;
+}
+inline void FileOptions::set_cc_enable_arenas(bool value) {
+ set_has_cc_enable_arenas();
+ cc_enable_arenas_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_enable_arenas)
+}
+
+// optional string objc_class_prefix = 36;
+inline bool FileOptions::has_objc_class_prefix() const {
+ return (_has_bits_[0] & 0x00001000u) != 0;
+}
+inline void FileOptions::set_has_objc_class_prefix() {
+ _has_bits_[0] |= 0x00001000u;
+}
+inline void FileOptions::clear_has_objc_class_prefix() {
+ _has_bits_[0] &= ~0x00001000u;
+}
+inline void FileOptions::clear_objc_class_prefix() {
+ objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_objc_class_prefix();
+}
+inline const ::std::string& FileOptions::objc_class_prefix() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.objc_class_prefix)
+ return objc_class_prefix_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_objc_class_prefix(const ::std::string& value) {
+ set_has_objc_class_prefix();
+ objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.objc_class_prefix)
+}
+inline void FileOptions::set_objc_class_prefix(const char* value) {
+ set_has_objc_class_prefix();
+ objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.objc_class_prefix)
+}
+inline void FileOptions::set_objc_class_prefix(const char* value, size_t size) {
+ set_has_objc_class_prefix();
+ objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.objc_class_prefix)
+}
+inline ::std::string* FileOptions::mutable_objc_class_prefix() {
+ set_has_objc_class_prefix();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.objc_class_prefix)
+ return objc_class_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* FileOptions::release_objc_class_prefix() {
+ clear_has_objc_class_prefix();
+ return objc_class_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_allocated_objc_class_prefix(::std::string* objc_class_prefix) {
+ if (objc_class_prefix != NULL) {
+ set_has_objc_class_prefix();
+ } else {
+ clear_has_objc_class_prefix();
+ }
+ objc_class_prefix_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), objc_class_prefix);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.objc_class_prefix)
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
@@ -4391,20 +5510,25 @@ inline void FileOptions::clear_uninterpreted_option() {
uninterpreted_option_.Clear();
}
inline const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.uninterpreted_option)
return uninterpreted_option_.Get(index);
}
inline ::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.uninterpreted_option)
return uninterpreted_option_.Mutable(index);
}
inline ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FileOptions.uninterpreted_option)
return uninterpreted_option_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
FileOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option)
return uninterpreted_option_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
FileOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileOptions.uninterpreted_option)
return &uninterpreted_option_;
}
@@ -4427,11 +5551,13 @@ inline void MessageOptions::clear_message_set_wire_format() {
clear_has_message_set_wire_format();
}
inline bool MessageOptions::message_set_wire_format() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.message_set_wire_format)
return message_set_wire_format_;
}
inline void MessageOptions::set_message_set_wire_format(bool value) {
set_has_message_set_wire_format();
message_set_wire_format_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.message_set_wire_format)
}
// optional bool no_standard_descriptor_accessor = 2 [default = false];
@@ -4449,11 +5575,61 @@ inline void MessageOptions::clear_no_standard_descriptor_accessor() {
clear_has_no_standard_descriptor_accessor();
}
inline bool MessageOptions::no_standard_descriptor_accessor() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
return no_standard_descriptor_accessor_;
}
inline void MessageOptions::set_no_standard_descriptor_accessor(bool value) {
set_has_no_standard_descriptor_accessor();
no_standard_descriptor_accessor_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
+}
+
+// optional bool deprecated = 3 [default = false];
+inline bool MessageOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void MessageOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000004u;
+}
+inline void MessageOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+inline void MessageOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+inline bool MessageOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.deprecated)
+ return deprecated_;
+}
+inline void MessageOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = 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;
@@ -4464,20 +5640,25 @@ inline void MessageOptions::clear_uninterpreted_option() {
uninterpreted_option_.Clear();
}
inline const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.uninterpreted_option)
return uninterpreted_option_.Get(index);
}
inline ::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MessageOptions.uninterpreted_option)
return uninterpreted_option_.Mutable(index);
}
inline ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.MessageOptions.uninterpreted_option)
return uninterpreted_option_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
MessageOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option)
return uninterpreted_option_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
MessageOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.MessageOptions.uninterpreted_option)
return &uninterpreted_option_;
}
@@ -4500,12 +5681,14 @@ inline void FieldOptions::clear_ctype() {
clear_has_ctype();
}
inline ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.ctype)
return static_cast< ::google::protobuf::FieldOptions_CType >(ctype_);
}
inline void FieldOptions::set_ctype(::google::protobuf::FieldOptions_CType value) {
- GOOGLE_DCHECK(::google::protobuf::FieldOptions_CType_IsValid(value));
+ assert(::google::protobuf::FieldOptions_CType_IsValid(value));
set_has_ctype();
ctype_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.ctype)
}
// optional bool packed = 2;
@@ -4523,91 +5706,85 @@ inline void FieldOptions::clear_packed() {
clear_has_packed();
}
inline bool FieldOptions::packed() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.packed)
return packed_;
}
inline void FieldOptions::set_packed(bool value) {
set_has_packed();
packed_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed)
+}
+
+// optional bool lazy = 5 [default = false];
+inline bool FieldOptions::has_lazy() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void FieldOptions::set_has_lazy() {
+ _has_bits_[0] |= 0x00000004u;
+}
+inline void FieldOptions::clear_has_lazy() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+inline void FieldOptions::clear_lazy() {
+ lazy_ = false;
+ clear_has_lazy();
+}
+inline bool FieldOptions::lazy() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.lazy)
+ return lazy_;
+}
+inline void FieldOptions::set_lazy(bool value) {
+ set_has_lazy();
+ lazy_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.lazy)
}
// optional bool deprecated = 3 [default = false];
inline bool FieldOptions::has_deprecated() const {
- return (_has_bits_[0] & 0x00000004u) != 0;
+ return (_has_bits_[0] & 0x00000008u) != 0;
}
inline void FieldOptions::set_has_deprecated() {
- _has_bits_[0] |= 0x00000004u;
+ _has_bits_[0] |= 0x00000008u;
}
inline void FieldOptions::clear_has_deprecated() {
- _has_bits_[0] &= ~0x00000004u;
+ _has_bits_[0] &= ~0x00000008u;
}
inline void FieldOptions::clear_deprecated() {
deprecated_ = false;
clear_has_deprecated();
}
inline bool FieldOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.deprecated)
return deprecated_;
}
inline void FieldOptions::set_deprecated(bool value) {
set_has_deprecated();
deprecated_ = 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] & 0x00000008u) != 0;
-}
-inline void FieldOptions::set_has_experimental_map_key() {
- _has_bits_[0] |= 0x00000008u;
-}
-inline void FieldOptions::clear_has_experimental_map_key() {
- _has_bits_[0] &= ~0x00000008u;
-}
-inline void FieldOptions::clear_experimental_map_key() {
- if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) {
- experimental_map_key_->clear();
- }
- clear_has_experimental_map_key();
-}
-inline const ::std::string& FieldOptions::experimental_map_key() const {
- return *experimental_map_key_;
+// optional bool weak = 10 [default = false];
+inline bool FieldOptions::has_weak() const {
+ return (_has_bits_[0] & 0x00000010u) != 0;
}
-inline void FieldOptions::set_experimental_map_key(const ::std::string& value) {
- set_has_experimental_map_key();
- if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) {
- experimental_map_key_ = new ::std::string;
- }
- experimental_map_key_->assign(value);
+inline void FieldOptions::set_has_weak() {
+ _has_bits_[0] |= 0x00000010u;
}
-inline void FieldOptions::set_experimental_map_key(const char* value) {
- set_has_experimental_map_key();
- if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) {
- experimental_map_key_ = new ::std::string;
- }
- experimental_map_key_->assign(value);
+inline void FieldOptions::clear_has_weak() {
+ _has_bits_[0] &= ~0x00000010u;
}
-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::kEmptyString) {
- experimental_map_key_ = new ::std::string;
- }
- experimental_map_key_->assign(reinterpret_cast<const char*>(value), size);
+inline void FieldOptions::clear_weak() {
+ weak_ = false;
+ clear_has_weak();
}
-inline ::std::string* FieldOptions::mutable_experimental_map_key() {
- set_has_experimental_map_key();
- if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) {
- experimental_map_key_ = new ::std::string;
- }
- return experimental_map_key_;
+inline bool FieldOptions::weak() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.weak)
+ return weak_;
}
-inline ::std::string* FieldOptions::release_experimental_map_key() {
- clear_has_experimental_map_key();
- if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
- } else {
- ::std::string* temp = experimental_map_key_;
- experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
- }
+inline void FieldOptions::set_weak(bool value) {
+ set_has_weak();
+ weak_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.weak)
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
@@ -4618,20 +5795,25 @@ inline void FieldOptions::clear_uninterpreted_option() {
uninterpreted_option_.Clear();
}
inline const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.uninterpreted_option)
return uninterpreted_option_.Get(index);
}
inline ::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.FieldOptions.uninterpreted_option)
return uninterpreted_option_.Mutable(index);
}
inline ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.FieldOptions.uninterpreted_option)
return uninterpreted_option_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
FieldOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option)
return uninterpreted_option_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
FieldOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldOptions.uninterpreted_option)
return &uninterpreted_option_;
}
@@ -4639,6 +5821,54 @@ FieldOptions::mutable_uninterpreted_option() {
// EnumOptions
+// optional bool allow_alias = 2;
+inline bool EnumOptions::has_allow_alias() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void EnumOptions::set_has_allow_alias() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void EnumOptions::clear_has_allow_alias() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void EnumOptions::clear_allow_alias() {
+ allow_alias_ = false;
+ clear_has_allow_alias();
+}
+inline bool EnumOptions::allow_alias() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.allow_alias)
+ return allow_alias_;
+}
+inline void EnumOptions::set_allow_alias(bool value) {
+ set_has_allow_alias();
+ allow_alias_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.allow_alias)
+}
+
+// optional bool deprecated = 3 [default = false];
+inline bool EnumOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void EnumOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void EnumOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void EnumOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+inline bool EnumOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.deprecated)
+ return deprecated_;
+}
+inline void EnumOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.deprecated)
+}
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int EnumOptions::uninterpreted_option_size() const {
return uninterpreted_option_.size();
@@ -4647,20 +5877,25 @@ inline void EnumOptions::clear_uninterpreted_option() {
uninterpreted_option_.Clear();
}
inline const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.uninterpreted_option)
return uninterpreted_option_.Get(index);
}
inline ::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumOptions.uninterpreted_option)
return uninterpreted_option_.Mutable(index);
}
inline ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.EnumOptions.uninterpreted_option)
return uninterpreted_option_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
EnumOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option)
return uninterpreted_option_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
EnumOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumOptions.uninterpreted_option)
return &uninterpreted_option_;
}
@@ -4668,6 +5903,30 @@ EnumOptions::mutable_uninterpreted_option() {
// EnumValueOptions
+// optional bool deprecated = 1 [default = false];
+inline bool EnumValueOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void EnumValueOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void EnumValueOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void EnumValueOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+inline bool EnumValueOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.deprecated)
+ return deprecated_;
+}
+inline void EnumValueOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.EnumValueOptions.deprecated)
+}
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int EnumValueOptions::uninterpreted_option_size() const {
return uninterpreted_option_.size();
@@ -4676,20 +5935,25 @@ inline void EnumValueOptions::clear_uninterpreted_option() {
uninterpreted_option_.Clear();
}
inline const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.uninterpreted_option)
return uninterpreted_option_.Get(index);
}
inline ::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueOptions.uninterpreted_option)
return uninterpreted_option_.Mutable(index);
}
inline ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.EnumValueOptions.uninterpreted_option)
return uninterpreted_option_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
EnumValueOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option)
return uninterpreted_option_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
EnumValueOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValueOptions.uninterpreted_option)
return &uninterpreted_option_;
}
@@ -4697,6 +5961,30 @@ EnumValueOptions::mutable_uninterpreted_option() {
// ServiceOptions
+// optional bool deprecated = 33 [default = false];
+inline bool ServiceOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ServiceOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void ServiceOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void ServiceOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+inline bool ServiceOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.deprecated)
+ return deprecated_;
+}
+inline void ServiceOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.ServiceOptions.deprecated)
+}
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int ServiceOptions::uninterpreted_option_size() const {
return uninterpreted_option_.size();
@@ -4705,20 +5993,25 @@ inline void ServiceOptions::clear_uninterpreted_option() {
uninterpreted_option_.Clear();
}
inline const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.uninterpreted_option)
return uninterpreted_option_.Get(index);
}
inline ::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceOptions.uninterpreted_option)
return uninterpreted_option_.Mutable(index);
}
inline ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.ServiceOptions.uninterpreted_option)
return uninterpreted_option_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
ServiceOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option)
return uninterpreted_option_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
ServiceOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceOptions.uninterpreted_option)
return &uninterpreted_option_;
}
@@ -4726,6 +6019,30 @@ ServiceOptions::mutable_uninterpreted_option() {
// MethodOptions
+// optional bool deprecated = 33 [default = false];
+inline bool MethodOptions::has_deprecated() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void MethodOptions::set_has_deprecated() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void MethodOptions::clear_has_deprecated() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void MethodOptions::clear_deprecated() {
+ deprecated_ = false;
+ clear_has_deprecated();
+}
+inline bool MethodOptions::deprecated() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.deprecated)
+ return deprecated_;
+}
+inline void MethodOptions::set_deprecated(bool value) {
+ set_has_deprecated();
+ deprecated_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.MethodOptions.deprecated)
+}
+
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int MethodOptions::uninterpreted_option_size() const {
return uninterpreted_option_.size();
@@ -4734,20 +6051,25 @@ inline void MethodOptions::clear_uninterpreted_option() {
uninterpreted_option_.Clear();
}
inline const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.uninterpreted_option)
return uninterpreted_option_.Get(index);
}
inline ::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.MethodOptions.uninterpreted_option)
return uninterpreted_option_.Mutable(index);
}
inline ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.MethodOptions.uninterpreted_option)
return uninterpreted_option_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
MethodOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option)
return uninterpreted_option_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
MethodOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.MethodOptions.uninterpreted_option)
return &uninterpreted_option_;
}
@@ -4766,51 +6088,46 @@ 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::kEmptyString) {
- name_part_->clear();
- }
+ name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_name_part();
}
inline const ::std::string& UninterpretedOption_NamePart::name_part() const {
- return *name_part_;
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.name_part)
+ return name_part_.GetNoArena(&::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::kEmptyString) {
- name_part_ = new ::std::string;
- }
- name_part_->assign(value);
+ name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- name_part_ = new ::std::string;
- }
- name_part_->assign(value);
+ name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@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) {
set_has_name_part();
- if (name_part_ == &::google::protobuf::internal::kEmptyString) {
- name_part_ = new ::std::string;
- }
- name_part_->assign(reinterpret_cast<const char*>(value), size);
+ name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- name_part_ = new ::std::string;
- }
- return name_part_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.NamePart.name_part)
+ return name_part_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* UninterpretedOption_NamePart::release_name_part() {
clear_has_name_part();
- if (name_part_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return name_part_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void UninterpretedOption_NamePart::set_allocated_name_part(::std::string* name_part) {
+ if (name_part != NULL) {
+ set_has_name_part();
} else {
- ::std::string* temp = name_part_;
- name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_name_part();
}
+ name_part_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name_part);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.NamePart.name_part)
}
// required bool is_extension = 2;
@@ -4828,11 +6145,13 @@ inline void UninterpretedOption_NamePart::clear_is_extension() {
clear_has_is_extension();
}
inline bool UninterpretedOption_NamePart::is_extension() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.is_extension)
return is_extension_;
}
inline void UninterpretedOption_NamePart::set_is_extension(bool value) {
set_has_is_extension();
is_extension_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.is_extension)
}
// -------------------------------------------------------------------
@@ -4847,20 +6166,25 @@ inline void UninterpretedOption::clear_name() {
name_.Clear();
}
inline const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.name)
return name_.Get(index);
}
inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mutable_name(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.name)
return name_.Mutable(index);
}
inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() {
+ // @@protoc_insertion_point(field_add:google.protobuf.UninterpretedOption.name)
return name_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
UninterpretedOption::name() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name)
return name_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
UninterpretedOption::mutable_name() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.UninterpretedOption.name)
return &name_;
}
@@ -4875,51 +6199,46 @@ inline void UninterpretedOption::clear_has_identifier_value() {
_has_bits_[0] &= ~0x00000002u;
}
inline void UninterpretedOption::clear_identifier_value() {
- if (identifier_value_ != &::google::protobuf::internal::kEmptyString) {
- identifier_value_->clear();
- }
+ identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_identifier_value();
}
inline const ::std::string& UninterpretedOption::identifier_value() const {
- return *identifier_value_;
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.identifier_value)
+ return identifier_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void UninterpretedOption::set_identifier_value(const ::std::string& value) {
set_has_identifier_value();
- if (identifier_value_ == &::google::protobuf::internal::kEmptyString) {
- identifier_value_ = new ::std::string;
- }
- identifier_value_->assign(value);
+ identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- identifier_value_ = new ::std::string;
- }
- identifier_value_->assign(value);
+ identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.identifier_value)
}
inline void UninterpretedOption::set_identifier_value(const char* value, size_t size) {
set_has_identifier_value();
- if (identifier_value_ == &::google::protobuf::internal::kEmptyString) {
- identifier_value_ = new ::std::string;
- }
- identifier_value_->assign(reinterpret_cast<const char*>(value), size);
+ identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- identifier_value_ = new ::std::string;
- }
- return identifier_value_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.identifier_value)
+ return identifier_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* UninterpretedOption::release_identifier_value() {
clear_has_identifier_value();
- if (identifier_value_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return identifier_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void UninterpretedOption::set_allocated_identifier_value(::std::string* identifier_value) {
+ if (identifier_value != NULL) {
+ set_has_identifier_value();
} else {
- ::std::string* temp = identifier_value_;
- identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_identifier_value();
}
+ identifier_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), identifier_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.identifier_value)
}
// optional uint64 positive_int_value = 4;
@@ -4937,11 +6256,13 @@ inline void UninterpretedOption::clear_positive_int_value() {
clear_has_positive_int_value();
}
inline ::google::protobuf::uint64 UninterpretedOption::positive_int_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.positive_int_value)
return positive_int_value_;
}
inline void UninterpretedOption::set_positive_int_value(::google::protobuf::uint64 value) {
set_has_positive_int_value();
positive_int_value_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.positive_int_value)
}
// optional int64 negative_int_value = 5;
@@ -4959,11 +6280,13 @@ inline void UninterpretedOption::clear_negative_int_value() {
clear_has_negative_int_value();
}
inline ::google::protobuf::int64 UninterpretedOption::negative_int_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.negative_int_value)
return negative_int_value_;
}
inline void UninterpretedOption::set_negative_int_value(::google::protobuf::int64 value) {
set_has_negative_int_value();
negative_int_value_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.negative_int_value)
}
// optional double double_value = 6;
@@ -4981,11 +6304,13 @@ inline void UninterpretedOption::clear_double_value() {
clear_has_double_value();
}
inline double UninterpretedOption::double_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.double_value)
return double_value_;
}
inline void UninterpretedOption::set_double_value(double value) {
set_has_double_value();
double_value_ = value;
+ // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.double_value)
}
// optional bytes string_value = 7;
@@ -4999,51 +6324,46 @@ inline void UninterpretedOption::clear_has_string_value() {
_has_bits_[0] &= ~0x00000020u;
}
inline void UninterpretedOption::clear_string_value() {
- if (string_value_ != &::google::protobuf::internal::kEmptyString) {
- string_value_->clear();
- }
+ string_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_string_value();
}
inline const ::std::string& UninterpretedOption::string_value() const {
- return *string_value_;
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.string_value)
+ return string_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void UninterpretedOption::set_string_value(const ::std::string& value) {
set_has_string_value();
- if (string_value_ == &::google::protobuf::internal::kEmptyString) {
- string_value_ = new ::std::string;
- }
- string_value_->assign(value);
+ string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- string_value_ = new ::std::string;
- }
- string_value_->assign(value);
+ string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.string_value)
}
inline void UninterpretedOption::set_string_value(const void* value, size_t size) {
set_has_string_value();
- if (string_value_ == &::google::protobuf::internal::kEmptyString) {
- string_value_ = new ::std::string;
- }
- string_value_->assign(reinterpret_cast<const char*>(value), size);
+ string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- string_value_ = new ::std::string;
- }
- return string_value_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.string_value)
+ return string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* UninterpretedOption::release_string_value() {
clear_has_string_value();
- if (string_value_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void UninterpretedOption::set_allocated_string_value(::std::string* string_value) {
+ if (string_value != NULL) {
+ set_has_string_value();
} else {
- ::std::string* temp = string_value_;
- string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_string_value();
}
+ string_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), string_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.string_value)
}
// optional string aggregate_value = 8;
@@ -5057,51 +6377,46 @@ inline void UninterpretedOption::clear_has_aggregate_value() {
_has_bits_[0] &= ~0x00000040u;
}
inline void UninterpretedOption::clear_aggregate_value() {
- if (aggregate_value_ != &::google::protobuf::internal::kEmptyString) {
- aggregate_value_->clear();
- }
+ aggregate_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_aggregate_value();
}
inline const ::std::string& UninterpretedOption::aggregate_value() const {
- return *aggregate_value_;
+ // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.aggregate_value)
+ return aggregate_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void UninterpretedOption::set_aggregate_value(const ::std::string& value) {
set_has_aggregate_value();
- if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) {
- aggregate_value_ = new ::std::string;
- }
- aggregate_value_->assign(value);
+ aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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::kEmptyString) {
- aggregate_value_ = new ::std::string;
- }
- aggregate_value_->assign(value);
+ aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.aggregate_value)
}
inline void UninterpretedOption::set_aggregate_value(const char* value, size_t size) {
set_has_aggregate_value();
- if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) {
- aggregate_value_ = new ::std::string;
- }
- aggregate_value_->assign(reinterpret_cast<const char*>(value), size);
+ aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@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::kEmptyString) {
- aggregate_value_ = new ::std::string;
- }
- return aggregate_value_;
+ // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.aggregate_value)
+ return aggregate_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* UninterpretedOption::release_aggregate_value() {
clear_has_aggregate_value();
- if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) {
- return NULL;
+ return aggregate_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void UninterpretedOption::set_allocated_aggregate_value(::std::string* aggregate_value) {
+ if (aggregate_value != NULL) {
+ set_has_aggregate_value();
} else {
- ::std::string* temp = aggregate_value_;
- aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
- return temp;
+ clear_has_aggregate_value();
}
+ aggregate_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), aggregate_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.aggregate_value)
}
// -------------------------------------------------------------------
@@ -5116,20 +6431,25 @@ inline void SourceCodeInfo_Location::clear_path() {
path_.Clear();
}
inline ::google::protobuf::int32 SourceCodeInfo_Location::path(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.path)
return path_.Get(index);
}
inline void SourceCodeInfo_Location::set_path(int index, ::google::protobuf::int32 value) {
path_.Set(index, value);
+ // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.path)
}
inline void SourceCodeInfo_Location::add_path(::google::protobuf::int32 value) {
path_.Add(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.path)
}
inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
SourceCodeInfo_Location::path() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.path)
return path_;
}
inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
SourceCodeInfo_Location::mutable_path() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.path)
return &path_;
}
@@ -5141,23 +6461,188 @@ inline void SourceCodeInfo_Location::clear_span() {
span_.Clear();
}
inline ::google::protobuf::int32 SourceCodeInfo_Location::span(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.span)
return span_.Get(index);
}
inline void SourceCodeInfo_Location::set_span(int index, ::google::protobuf::int32 value) {
span_.Set(index, value);
+ // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.span)
}
inline void SourceCodeInfo_Location::add_span(::google::protobuf::int32 value) {
span_.Add(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.span)
}
inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
SourceCodeInfo_Location::span() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.span)
return span_;
}
inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
SourceCodeInfo_Location::mutable_span() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.span)
return &span_;
}
+// optional string leading_comments = 3;
+inline bool SourceCodeInfo_Location::has_leading_comments() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void SourceCodeInfo_Location::set_has_leading_comments() {
+ _has_bits_[0] |= 0x00000004u;
+}
+inline void SourceCodeInfo_Location::clear_has_leading_comments() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+inline void SourceCodeInfo_Location::clear_leading_comments() {
+ leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ 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_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SourceCodeInfo_Location::set_leading_comments(const ::std::string& value) {
+ set_has_leading_comments();
+ leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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();
+ leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@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) {
+ set_has_leading_comments();
+ leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+inline ::std::string* SourceCodeInfo_Location::mutable_leading_comments() {
+ set_has_leading_comments();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_comments)
+ return leading_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* SourceCodeInfo_Location::release_leading_comments() {
+ clear_has_leading_comments();
+ return leading_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SourceCodeInfo_Location::set_allocated_leading_comments(::std::string* leading_comments) {
+ if (leading_comments != NULL) {
+ set_has_leading_comments();
+ } else {
+ clear_has_leading_comments();
+ }
+ leading_comments_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), leading_comments);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+
+// optional string trailing_comments = 4;
+inline bool SourceCodeInfo_Location::has_trailing_comments() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void SourceCodeInfo_Location::set_has_trailing_comments() {
+ _has_bits_[0] |= 0x00000008u;
+}
+inline void SourceCodeInfo_Location::clear_has_trailing_comments() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+inline void SourceCodeInfo_Location::clear_trailing_comments() {
+ trailing_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ 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_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SourceCodeInfo_Location::set_trailing_comments(const ::std::string& value) {
+ set_has_trailing_comments();
+ trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@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();
+ trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@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) {
+ set_has_trailing_comments();
+ trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+inline ::std::string* SourceCodeInfo_Location::mutable_trailing_comments() {
+ set_has_trailing_comments();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+ return trailing_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* SourceCodeInfo_Location::release_trailing_comments() {
+ clear_has_trailing_comments();
+ return trailing_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SourceCodeInfo_Location::set_allocated_trailing_comments(::std::string* trailing_comments) {
+ if (trailing_comments != NULL) {
+ set_has_trailing_comments();
+ } else {
+ clear_has_trailing_comments();
+ }
+ trailing_comments_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), trailing_comments);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+
+// repeated string leading_detached_comments = 6;
+inline int SourceCodeInfo_Location::leading_detached_comments_size() const {
+ return leading_detached_comments_.size();
+}
+inline void SourceCodeInfo_Location::clear_leading_detached_comments() {
+ leading_detached_comments_.Clear();
+}
+inline const ::std::string& SourceCodeInfo_Location::leading_detached_comments(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ return leading_detached_comments_.Get(index);
+}
+inline ::std::string* SourceCodeInfo_Location::mutable_leading_detached_comments(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ return leading_detached_comments_.Mutable(index);
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ leading_detached_comments_.Mutable(index)->assign(value);
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value) {
+ leading_detached_comments_.Mutable(index)->assign(value);
+ // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value, size_t size) {
+ leading_detached_comments_.Mutable(index)->assign(
+ reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline ::std::string* SourceCodeInfo_Location::add_leading_detached_comments() {
+ return leading_detached_comments_.Add();
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const ::std::string& value) {
+ leading_detached_comments_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const char* value) {
+ leading_detached_comments_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const char* value, size_t size) {
+ leading_detached_comments_.Add()->assign(reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_add_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+SourceCodeInfo_Location::leading_detached_comments() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ return leading_detached_comments_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+SourceCodeInfo_Location::mutable_leading_detached_comments() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+ return &leading_detached_comments_;
+}
+
// -------------------------------------------------------------------
// SourceCodeInfo
@@ -5170,23 +6655,29 @@ inline void SourceCodeInfo::clear_location() {
location_.Clear();
}
inline const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.location)
return location_.Get(index);
}
inline ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::mutable_location(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.location)
return location_.Mutable(index);
}
inline ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::add_location() {
+ // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.location)
return location_.Add();
}
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
SourceCodeInfo::location() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location)
return location_;
}
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
SourceCodeInfo::mutable_location() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.location)
return &location_;
}
+#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS
// @@protoc_insertion_point(namespace_scope)
@@ -5197,25 +6688,29 @@ SourceCodeInfo::mutable_location() {
namespace google {
namespace protobuf {
+template <> struct is_proto_enum< ::google::protobuf::FieldDescriptorProto_Type> : ::google::protobuf::internal::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Type>() {
return ::google::protobuf::FieldDescriptorProto_Type_descriptor();
}
+template <> struct is_proto_enum< ::google::protobuf::FieldDescriptorProto_Label> : ::google::protobuf::internal::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Label>() {
return ::google::protobuf::FieldDescriptorProto_Label_descriptor();
}
+template <> struct is_proto_enum< ::google::protobuf::FileOptions_OptimizeMode> : ::google::protobuf::internal::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FileOptions_OptimizeMode>() {
return ::google::protobuf::FileOptions_OptimizeMode_descriptor();
}
+template <> struct is_proto_enum< ::google::protobuf::FieldOptions_CType> : ::google::protobuf::internal::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_CType>() {
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 233f8794..367b16e5 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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";
@@ -59,6 +60,11 @@ message FileDescriptorProto {
// Names of files imported by this file.
repeated string dependency = 3;
+ // Indexes of the public imported files in the dependency list above.
+ repeated int32 public_dependency = 10;
+ // Indexes of the weak imported files in the dependency list.
+ // For Google-internal migration only. Do not use.
+ repeated int32 weak_dependency = 11;
// All top-level definitions in this file.
repeated DescriptorProto message_type = 4;
@@ -69,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.
@@ -91,6 +101,8 @@ message DescriptorProto {
}
repeated ExtensionRange extension_range = 5;
+ repeated OneofDescriptorProto oneof_decl = 8;
+
optional MessageOptions options = 7;
}
@@ -101,13 +113,13 @@ message FieldDescriptorProto {
// Order is weird for historical reasons.
TYPE_DOUBLE = 1;
TYPE_FLOAT = 2;
- TYPE_INT64 = 3; // Not ZigZag encoded. Negative numbers
- // take 10 bytes. Use TYPE_SINT64 if negative
- // values are likely.
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
+ // negative values are likely.
+ TYPE_INT64 = 3;
TYPE_UINT64 = 4;
- TYPE_INT32 = 5; // Not ZigZag encoded. Negative numbers
- // take 10 bytes. Use TYPE_SINT32 if negative
- // values are likely.
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
+ // negative values are likely.
+ TYPE_INT32 = 5;
TYPE_FIXED64 = 6;
TYPE_FIXED32 = 7;
TYPE_BOOL = 8;
@@ -138,7 +150,7 @@ message FieldDescriptorProto {
optional Label label = 4;
// If type_name is set, this need not be set. If both this and type_name
- // are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
+ // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
optional Type type = 5;
// For message and enum types, this is the name of the type. If the name
@@ -159,9 +171,18 @@ message FieldDescriptorProto {
// TODO(kenton): Base-64 encode?
optional string default_value = 7;
+ // If set, gives the index of a oneof in the containing type's oneof_decl
+ // list. This field is a member of that oneof.
+ optional int32 oneof_index = 9;
+
optional FieldOptions options = 8;
}
+// Describes a oneof.
+message OneofDescriptorProto {
+ optional string name = 1;
+}
+
// Describes an enum type.
message EnumDescriptorProto {
optional string name = 1;
@@ -197,8 +218,14 @@ message MethodDescriptorProto {
optional string output_type = 3;
optional MethodOptions options = 4;
+
+ // Identifies if client streams multiple client messages
+ optional bool client_streaming = 5 [default=false];
+ // Identifies if server streams multiple server messages
+ optional bool server_streaming = 6 [default=false];
}
+
// ===================================================================
// Options
@@ -220,10 +247,15 @@ message MethodDescriptorProto {
// through 99999. It is up to you to ensure that you do not use the
// same number for multiple options.
// * For options which will be published and used publicly by multiple
-// independent entities, e-mail kenton@google.com to reserve extension
-// numbers. Simply tell me how many you need and I'll send you back a
-// set of numbers to use -- there's no need to explain how you intend to
-// use them. If this turns out to be popular, a web service will be set up
+// independent entities, e-mail protobuf-global-extension-registry@google.com
+// to reserve extension numbers. Simply provide your project name (e.g.
+// Object-C plugin) and your porject website (if available) -- there's no need
+// to explain how you intend to use them. Usually you only need one extension
+// number. You can declare multiple options with only one extension number by
+// putting them in a sub-message. See the Custom Options section of the docs
+// for examples:
+// https://developers.google.com/protocol-buffers/docs/proto#options
+// If this turns out to be popular, a web service will be set up
// to automatically assign option numbers.
@@ -252,11 +284,26 @@ message FileOptions {
optional bool java_multiple_files = 10 [default=false];
// If set true, then the Java code generator will generate equals() and
- // hashCode() methods for all messages defined in the .proto file. This is
- // purely a speed optimization, as the AbstractMessage base class includes
- // reflection-based implementations of these methods.
+ // hashCode() methods for all messages defined in the .proto file.
+ // - In the full runtime, this is purely a speed optimization, as the
+ // AbstractMessage base class includes reflection-based implementations of
+ // these methods.
+ //- In the lite runtime, setting this option changes the semantics of
+ // equals() and hashCode() to more closely match those of the full runtime;
+ // the generated methods compute their results based on field values rather
+ // than object identity. (Implementations should not assume that hashcodes
+ // will be consistent across runtimes or versions of the protocol compiler.)
optional bool java_generate_equals_and_hash = 20 [default=false];
+ // If set true, then the Java2 code generator will generate code that
+ // throws an exception whenever an attempt is made to assign a non-UTF-8
+ // byte sequence to a string field.
+ // Message reflection will do the same.
+ // However, an extension field still accepts non-UTF-8 byte sequences.
+ // This option has no effect on when used with the lite runtime.
+ optional bool java_string_check_utf8 = 27 [default=false];
+
+
// Generated classes can be optimized for speed or code size.
enum OptimizeMode {
SPEED = 1; // Generate complete code for parsing, serialization,
@@ -266,6 +313,12 @@ message FileOptions {
}
optional OptimizeMode optimize_for = 9 [default=SPEED];
+ // Sets the Go package where structs generated from this .proto will be
+ // 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;
@@ -273,7 +326,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,
@@ -283,6 +336,21 @@ message FileOptions {
optional bool java_generic_services = 17 [default=false];
optional bool py_generic_services = 18 [default=false];
+ // Is this file deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for everything in the file, or it will be completely ignored; in the very
+ // least, this is a formalization for deprecating files.
+ optional bool deprecated = 23 [default=false];
+
+ // Enables the use of arenas for the proto messages in this file. This applies
+ // only to generated classes for C++.
+ optional bool cc_enable_arenas = 31 [default=false];
+
+
+ // Sets the objective c class prefix which is prepended to all objective c
+ // generated classes from this .proto. There is no default.
+ optional string objc_class_prefix = 36;
+
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@@ -316,6 +384,35 @@ message MessageOptions {
// from proto1 easier; new code should avoid fields named "descriptor".
optional bool no_standard_descriptor_accessor = 2 [default=false];
+ // Is this message deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the message, or it will be completely ignored; in the very least,
+ // 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<KeyType, ValueType> 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;
@@ -344,25 +441,47 @@ message FieldOptions {
optional bool packed = 2;
+
+ // Should this field be parsed lazily? Lazy applies only to message-type
+ // fields. It means that when the outer message is initially parsed, the
+ // inner message's contents will not be parsed but instead stored in encoded
+ // form. The inner message will actually be parsed when it is first accessed.
+ //
+ // This is only a hint. Implementations are free to choose whether to use
+ // eager or lazy parsing regardless of the value of this option. However,
+ // setting this option true suggests that the protocol author believes that
+ // using lazy parsing on this field is worth the additional bookkeeping
+ // overhead typically needed to implement it.
+ //
+ // This option does not affect the public interface of any generated code;
+ // all method signatures remain the same. Furthermore, thread-safety of the
+ // interface is not affected by this option; const methods remain safe to
+ // call from multiple threads concurrently, while non-const methods continue
+ // to require exclusive access.
+ //
+ //
+ // Note that implementations may choose not to check required fields within
+ // a lazy sub-message. That is, calling IsInitialized() on the outher message
+ // may return true even if the inner message has missing required fields.
+ // This is necessary because otherwise the inner message would have to be
+ // parsed in order to perform the check, defeating the purpose of lazy
+ // parsing. An implementation which chooses not to check required fields
+ // must be consistent about it. That is, for any particular sub-message, the
+ // implementation must either *always* check its required fields, or *never*
+ // check its required fields, regardless of whether or not the message has
+ // been parsed.
+ optional bool lazy = 5 [default=false];
+
// Is this field deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for accessors, or it will be completely ignored; in the very least, this
// 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];
+
+
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@@ -373,6 +492,16 @@ message FieldOptions {
message EnumOptions {
+ // Set this option to true to allow mapping different tag names to the same
+ // value.
+ optional bool allow_alias = 2;
+
+ // Is this enum deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the enum, or it will be completely ignored; in the very least, this
+ // is a formalization for deprecating enums.
+ optional bool deprecated = 3 [default=false];
+
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@@ -381,6 +510,12 @@ message EnumOptions {
}
message EnumValueOptions {
+ // Is this enum value deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the enum value, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating enum values.
+ optional bool deprecated = 1 [default=false];
+
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@@ -395,6 +530,12 @@ message ServiceOptions {
// we were already using them long before we decided to release Protocol
// Buffers.
+ // Is this service deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the service, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating services.
+ optional bool deprecated = 33 [default=false];
+
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@@ -409,6 +550,12 @@ message MethodOptions {
// we were already using them long before we decided to release Protocol
// Buffers.
+ // Is this method deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the method, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating methods.
+ optional bool deprecated = 33 [default=false];
+
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@@ -416,6 +563,7 @@ message MethodOptions {
extensions 1000 to max;
}
+
// A message representing a option the parser does not recognize. This only
// appears in options protos created by the compiler::Parser class.
// DescriptorPool resolves these when building Descriptor objects. Therefore,
@@ -527,7 +675,55 @@ message SourceCodeInfo {
// 1 to each before displaying to a user.
repeated int32 span = 2 [packed=true];
- // TODO(kenton): Record comments appearing before and after the
- // declaration.
+ // If this SourceCodeInfo represents a complete declaration, these are any
+ // comments appearing before and after the declaration which appear to be
+ // attached to the declaration.
+ //
+ // A series of line comments appearing on consecutive lines, with no other
+ // tokens appearing on those lines, will be treated as a single comment.
+ //
+ // leading_detached_comments will keep paragraphs of comments that appear
+ // before (but not connected to) the current element. Each paragraph,
+ // separated by empty lines, will be one comment element in the repeated
+ // field.
+ //
+ // Only the comment content is provided; comment markers (e.g. //) are
+ // stripped out. For block comments, leading whitespace and an asterisk
+ // will be stripped from the beginning of each line other than the first.
+ // Newlines are included in the output.
+ //
+ // Examples:
+ //
+ // optional int32 foo = 1; // Comment attached to foo.
+ // // Comment attached to bar.
+ // optional int32 bar = 2;
+ //
+ // optional string baz = 3;
+ // // Comment attached to baz.
+ // // Another line attached to baz.
+ //
+ // // Comment attached to qux.
+ // //
+ // // Another line attached to qux.
+ // optional double qux = 4;
+ //
+ // // Detached comment for corge. This is not leading or trailing comments
+ // // to qux or corge because there are blank lines separating it from
+ // // both.
+ //
+ // // Detached comment for corge paragraph 2.
+ //
+ // optional string corge = 5;
+ // /* Block comment attached
+ // * to corge. Leading asterisks
+ // * will be removed. */
+ // /* Block comment attached to
+ // * grault. */
+ // optional int32 grault = 6;
+ //
+ // // ignored detached comments.
+ optional string leading_comments = 3;
+ optional string trailing_comments = 4;
+ repeated string leading_detached_comments = 6;
}
}
diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc
index 23e48a67..2117c020 100644
--- a/src/google/protobuf/descriptor_database.cc
+++ b/src/google/protobuf/descriptor_database.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -39,8 +39,8 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
-#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/map_util.h>
namespace google {
namespace protobuf {
@@ -153,10 +153,10 @@ bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
if (!field.extendee().empty() && field.extendee()[0] == '.') {
// The extension is fully-qualified. We can use it as a lookup key in
// the by_symbol_ table.
- if (!InsertIfNotPresent(&by_extension_,
- make_pair(field.extendee().substr(1),
- field.number()),
- value)) {
+ if (!InsertIfNotPresent(
+ &by_extension_,
+ std::make_pair(field.extendee().substr(1), field.number()),
+ value)) {
GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
"extend " << field.extendee() << " { "
<< field.name() << " = " << field.number() << " }";
@@ -189,17 +189,16 @@ template <typename Value>
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
const string& containing_type,
int field_number) {
- return FindWithDefault(by_extension_,
- make_pair(containing_type, field_number),
- Value());
+ return FindWithDefault(
+ by_extension_, std::make_pair(containing_type, field_number), Value());
}
template <typename Value>
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
const string& containing_type,
vector<int>* output) {
- typename map<pair<string, int>, Value >::const_iterator it =
- by_extension_.lower_bound(make_pair(containing_type, 0));
+ typename map<pair<string, int>, Value>::const_iterator it =
+ by_extension_.lower_bound(std::make_pair(containing_type, 0));
bool success = false;
for (; it != by_extension_.end() && it->first.first == containing_type;
@@ -289,6 +288,7 @@ bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
return index_.FindAllExtensionNumbers(extendee_type, output);
}
+
bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
FileDescriptorProto* output) {
if (file == NULL) return false;
@@ -309,7 +309,7 @@ bool EncodedDescriptorDatabase::Add(
const void* encoded_file_descriptor, int size) {
FileDescriptorProto file;
if (file.ParseFromArray(encoded_file_descriptor, size)) {
- return index_.AddFile(file, make_pair(encoded_file_descriptor, size));
+ return index_.AddFile(file, std::make_pair(encoded_file_descriptor, size));
} else {
GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
"EncodedDescriptorDatabase::Add().";
@@ -524,18 +524,20 @@ bool MergedDescriptorDatabase::FindAllExtensionNumbers(
for (int i = 0; i < sources_.size(); i++) {
if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
- copy(results.begin(), results.end(),
- insert_iterator<set<int> >(merged_results, merged_results.begin()));
+ std::copy(
+ results.begin(), results.end(),
+ insert_iterator<set<int> >(merged_results, merged_results.begin()));
success = true;
}
results.clear();
}
- copy(merged_results.begin(), merged_results.end(),
- insert_iterator<vector<int> >(*output, output->end()));
+ std::copy(merged_results.begin(), merged_results.end(),
+ insert_iterator<vector<int> >(*output, output->end()));
return success;
}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h
index f32b1db9..934e4022 100644
--- a/src/google/protobuf/descriptor_database.h
+++ b/src/google/protobuf/descriptor_database.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -41,6 +41,7 @@
#include <string>
#include <utility>
#include <vector>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
namespace google {
@@ -95,11 +96,12 @@ class LIBPROTOBUF_EXPORT DescriptorDatabase {
//
// This method has a default implementation that always returns
// false.
- virtual bool FindAllExtensionNumbers(const string& extendee_type,
- vector<int>* output) {
+ virtual bool FindAllExtensionNumbers(const string& /* extendee_type */,
+ vector<int>* /* output */) {
return false;
}
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase);
};
@@ -355,6 +357,7 @@ class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
bool FindAllExtensionNumbers(const string& extendee_type,
vector<int>* output);
+
private:
vector<DescriptorDatabase*> sources_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase);
diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc
index ac72ddcd..1c03c443 100644
--- a/src/google/protobuf/descriptor_database_unittest.cc
+++ b/src/google/protobuf/descriptor_database_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -408,7 +408,7 @@ TEST_P(DescriptorDatabaseTest, FindAllExtensionNumbers) {
vector<int> numbers;
EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers));
ASSERT_EQ(2, numbers.size());
- sort(numbers.begin(), numbers.end());
+ std::sort(numbers.begin(), numbers.end());
EXPECT_EQ(5, numbers[0]);
EXPECT_EQ(32, numbers[1]);
}
@@ -722,7 +722,7 @@ TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) {
vector<int> numbers;
EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers));
ASSERT_EQ(2, numbers.size());
- sort(numbers.begin(), numbers.end());
+ std::sort(numbers.begin(), numbers.end());
EXPECT_EQ(12, numbers[0]);
EXPECT_EQ(13, numbers[1]);
}
@@ -731,7 +731,7 @@ TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) {
vector<int> numbers;
EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers));
ASSERT_EQ(2, numbers.size());
- sort(numbers.begin(), numbers.end());
+ std::sort(numbers.begin(), numbers.end());
EXPECT_EQ(12, numbers[0]);
EXPECT_EQ(13, numbers[1]);
}
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index 55aebfd1..fdce3d78 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -36,13 +36,15 @@
#include <vector>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_custom_options.pb.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor_database.h>
#include <google/protobuf/dynamic_message.h>
-#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/text_format.h>
-#include <google/protobuf/unittest.pb.h>
-#include <google/protobuf/unittest_custom_options.pb.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
@@ -358,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.
@@ -385,6 +415,11 @@ class DescriptorTest : public testing::Test {
// required string quux = 6;
// }
//
+ // // in "map.proto"
+ // message TestMessage3 {
+ // map<int32, int32> map_int32_int32 = 1;
+ // }
+ //
// We cheat and use TestForeign as the type for qux rather than create
// an actual nested type.
//
@@ -432,6 +467,24 @@ class DescriptorTest : public testing::Test {
FieldDescriptorProto::LABEL_REQUIRED,
FieldDescriptorProto::TYPE_STRING);
+ FileDescriptorProto map_file;
+ map_file.set_name("map.proto");
+ DescriptorProto* message3 = AddMessage(&map_file, "TestMessage3");
+
+ DescriptorProto* entry = AddNestedMessage(message3, "MapInt32Int32Entry");
+ AddField(entry, "key", 1,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddField(entry, "value", 2,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ entry->mutable_options()->set_map_entry(true);
+
+ AddField(message3, "map_int32_int32", 1,
+ FieldDescriptorProto::LABEL_REPEATED,
+ FieldDescriptorProto::TYPE_MESSAGE)
+ ->set_type_name("MapInt32Int32Entry");
+
// Build the descriptors and get the pointers.
foo_file_ = pool_.BuildFile(foo_file);
ASSERT_TRUE(foo_file_ != NULL);
@@ -439,6 +492,9 @@ class DescriptorTest : public testing::Test {
bar_file_ = pool_.BuildFile(bar_file);
ASSERT_TRUE(bar_file_ != NULL);
+ map_file_ = pool_.BuildFile(map_file);
+ ASSERT_TRUE(map_file_ != NULL);
+
ASSERT_EQ(1, foo_file_->enum_type_count());
enum_ = foo_file_->enum_type(0);
@@ -459,15 +515,23 @@ class DescriptorTest : public testing::Test {
foo2_ = message2_->field(0);
bar2_ = message2_->field(1);
quux2_ = message2_->field(2);
+
+ ASSERT_EQ(1, map_file_->message_type_count());
+ message3_ = map_file_->message_type(0);
+
+ ASSERT_EQ(1, message3_->field_count());
+ map_ = message3_->field(0);
}
DescriptorPool pool_;
const FileDescriptor* foo_file_;
const FileDescriptor* bar_file_;
+ const FileDescriptor* map_file_;
const Descriptor* message_;
const Descriptor* message2_;
+ const Descriptor* message3_;
const Descriptor* foreign_;
const EnumDescriptor* enum_;
@@ -479,6 +543,8 @@ class DescriptorTest : public testing::Test {
const FieldDescriptor* foo2_;
const FieldDescriptor* bar2_;
const FieldDescriptor* quux2_;
+
+ const FieldDescriptor* map_;
};
TEST_F(DescriptorTest, Name) {
@@ -608,6 +674,12 @@ TEST_F(DescriptorTest, FieldLabel) {
EXPECT_TRUE (baz_->is_repeated());
}
+TEST_F(DescriptorTest, IsMap) {
+ EXPECT_TRUE(map_->is_map());
+ EXPECT_FALSE(baz_->is_map());
+ EXPECT_TRUE(map_->message_type()->options().map_entry());
+}
+
TEST_F(DescriptorTest, FieldHasDefault) {
EXPECT_FALSE(foo_->has_default_value());
EXPECT_FALSE(bar_->has_default_value());
@@ -644,6 +716,104 @@ TEST_F(DescriptorTest, FieldEnumType) {
// ===================================================================
+// Test simple flat messages and fields.
+class OneofDescriptorTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Build descriptors for the following definitions:
+ //
+ // package garply;
+ // message TestOneof {
+ // optional int32 a = 1;
+ // oneof foo {
+ // string b = 2;
+ // TestOneof c = 3;
+ // }
+ // oneof bar {
+ // float d = 4;
+ // }
+ // }
+
+ FileDescriptorProto baz_file;
+ baz_file.set_name("baz.proto");
+ baz_file.set_package("garply");
+
+ DescriptorProto* oneof_message = AddMessage(&baz_file, "TestOneof");
+ oneof_message->add_oneof_decl()->set_name("foo");
+ oneof_message->add_oneof_decl()->set_name("bar");
+
+ AddField(oneof_message, "a", 1,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddField(oneof_message, "b", 2,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_STRING);
+ oneof_message->mutable_field(1)->set_oneof_index(0);
+ AddField(oneof_message, "c", 3,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_MESSAGE);
+ oneof_message->mutable_field(2)->set_oneof_index(0);
+ oneof_message->mutable_field(2)->set_type_name("TestOneof");
+
+ AddField(oneof_message, "d", 4,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_FLOAT);
+ oneof_message->mutable_field(3)->set_oneof_index(1);
+
+ // Build the descriptors and get the pointers.
+ baz_file_ = pool_.BuildFile(baz_file);
+ ASSERT_TRUE(baz_file_ != NULL);
+
+ ASSERT_EQ(1, baz_file_->message_type_count());
+ oneof_message_ = baz_file_->message_type(0);
+
+ ASSERT_EQ(2, oneof_message_->oneof_decl_count());
+ oneof_ = oneof_message_->oneof_decl(0);
+ oneof2_ = oneof_message_->oneof_decl(1);
+
+ ASSERT_EQ(4, oneof_message_->field_count());
+ a_ = oneof_message_->field(0);
+ b_ = oneof_message_->field(1);
+ c_ = oneof_message_->field(2);
+ d_ = oneof_message_->field(3);
+ }
+
+ DescriptorPool pool_;
+
+ const FileDescriptor* baz_file_;
+
+ const Descriptor* oneof_message_;
+
+ const OneofDescriptor* oneof_;
+ const OneofDescriptor* oneof2_;
+ const FieldDescriptor* a_;
+ const FieldDescriptor* b_;
+ const FieldDescriptor* c_;
+ const FieldDescriptor* d_;
+ const FieldDescriptor* e_;
+ const FieldDescriptor* f_;
+};
+
+TEST_F(OneofDescriptorTest, Normal) {
+ EXPECT_EQ("foo", oneof_->name());
+ EXPECT_EQ("garply.TestOneof.foo", oneof_->full_name());
+ EXPECT_EQ(0, oneof_->index());
+ ASSERT_EQ(2, oneof_->field_count());
+ EXPECT_EQ(b_, oneof_->field(0));
+ EXPECT_EQ(c_, oneof_->field(1));
+ EXPECT_TRUE(a_->containing_oneof() == NULL);
+ EXPECT_EQ(oneof_, b_->containing_oneof());
+ EXPECT_EQ(oneof_, c_->containing_oneof());
+}
+
+TEST_F(OneofDescriptorTest, FindByName) {
+ EXPECT_EQ(oneof_, oneof_message_->FindOneofByName("foo"));
+ EXPECT_EQ(oneof2_, oneof_message_->FindOneofByName("bar"));
+ EXPECT_TRUE(oneof_message_->FindOneofByName("no_such_oneof") == NULL);
+}
+
+// ===================================================================
+
class StylizedFieldNamesTest : public testing::Test {
protected:
void SetUp() {
@@ -1514,13 +1684,46 @@ TEST_F(ExtensionDescriptorTest, FindAllExtensions) {
EXPECT_EQ(39, extensions[3]->number());
}
+TEST_F(ExtensionDescriptorTest, DuplicateFieldNumber) {
+ 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.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);
+ // Add "bar.proto":
+ // import "google/protobuf/descriptor.proto";
+ // extend google.protobuf.FieldOptions {
+ // optional int32 option2 = 1000;
+ // }
+ file_proto.Clear();
+ file_proto.set_name("bar.proto");
+ file_proto.add_dependency("google/protobuf/descriptor.proto");
+ AddExtension(&file_proto, "google.protobuf.FieldOptions", "option2", 1000,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ // Currently we only generate a warning for conflicting extension numbers.
+ // TODO(xiaofeng): Change it to an error.
+ ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+}
+
// ===================================================================
class MiscTest : public testing::Test {
protected:
- // Function which makes a field of the given type just to find out what its
- // cpp_type is.
- FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) {
+ // Function which makes a field descriptor of the given type.
+ const FieldDescriptor* GetFieldDescriptorOfType(FieldDescriptor::Type type) {
FileDescriptorProto file_proto;
file_proto.set_name("foo.proto");
AddEmptyEnum(&file_proto, "DummyEnum");
@@ -1538,19 +1741,99 @@ class MiscTest : public testing::Test {
}
// Build the descriptors and get the pointers.
- DescriptorPool pool;
- const FileDescriptor* file = pool.BuildFile(file_proto);
+ pool_.reset(new DescriptorPool());
+ const FileDescriptor* file = pool_->BuildFile(file_proto);
if (file != NULL &&
file->message_type_count() == 1 &&
file->message_type(0)->field_count() == 1) {
- return file->message_type(0)->field(0)->cpp_type();
+ return file->message_type(0)->field(0);
} else {
- return static_cast<FieldDescriptor::CppType>(0);
+ return NULL;
}
}
+
+ const char* GetTypeNameForFieldType(FieldDescriptor::Type type) {
+ const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+ return field != NULL ? field->type_name() : "";
+ }
+
+ FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) {
+ const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+ return field != NULL ? field->cpp_type() :
+ static_cast<FieldDescriptor::CppType>(0);
+ }
+
+ const char* GetCppTypeNameForFieldType(FieldDescriptor::Type type) {
+ const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+ return field != NULL ? field->cpp_type_name() : "";
+ }
+
+ const Descriptor* GetMessageDescriptorForFieldType(
+ FieldDescriptor::Type type) {
+ const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+ return field != NULL ? field->message_type() : NULL;
+ }
+
+ const EnumDescriptor* GetEnumDescriptorForFieldType(
+ FieldDescriptor::Type type) {
+ const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+ return field != NULL ? field->enum_type() : NULL;
+ }
+
+ scoped_ptr<DescriptorPool> pool_;
};
+TEST_F(MiscTest, TypeNames) {
+ // Test that correct type names are returned.
+
+ typedef FieldDescriptor FD; // avoid ugly line wrapping
+
+ EXPECT_STREQ("double" , GetTypeNameForFieldType(FD::TYPE_DOUBLE ));
+ EXPECT_STREQ("float" , GetTypeNameForFieldType(FD::TYPE_FLOAT ));
+ EXPECT_STREQ("int64" , GetTypeNameForFieldType(FD::TYPE_INT64 ));
+ EXPECT_STREQ("uint64" , GetTypeNameForFieldType(FD::TYPE_UINT64 ));
+ EXPECT_STREQ("int32" , GetTypeNameForFieldType(FD::TYPE_INT32 ));
+ EXPECT_STREQ("fixed64" , GetTypeNameForFieldType(FD::TYPE_FIXED64 ));
+ EXPECT_STREQ("fixed32" , GetTypeNameForFieldType(FD::TYPE_FIXED32 ));
+ EXPECT_STREQ("bool" , GetTypeNameForFieldType(FD::TYPE_BOOL ));
+ EXPECT_STREQ("string" , GetTypeNameForFieldType(FD::TYPE_STRING ));
+ EXPECT_STREQ("group" , GetTypeNameForFieldType(FD::TYPE_GROUP ));
+ EXPECT_STREQ("message" , GetTypeNameForFieldType(FD::TYPE_MESSAGE ));
+ EXPECT_STREQ("bytes" , GetTypeNameForFieldType(FD::TYPE_BYTES ));
+ EXPECT_STREQ("uint32" , GetTypeNameForFieldType(FD::TYPE_UINT32 ));
+ EXPECT_STREQ("enum" , GetTypeNameForFieldType(FD::TYPE_ENUM ));
+ EXPECT_STREQ("sfixed32", GetTypeNameForFieldType(FD::TYPE_SFIXED32));
+ EXPECT_STREQ("sfixed64", GetTypeNameForFieldType(FD::TYPE_SFIXED64));
+ EXPECT_STREQ("sint32" , GetTypeNameForFieldType(FD::TYPE_SINT32 ));
+ EXPECT_STREQ("sint64" , GetTypeNameForFieldType(FD::TYPE_SINT64 ));
+}
+
+TEST_F(MiscTest, StaticTypeNames) {
+ // Test that correct type names are returned.
+
+ typedef FieldDescriptor FD; // avoid ugly line wrapping
+
+ EXPECT_STREQ("double" , FD::TypeName(FD::TYPE_DOUBLE ));
+ EXPECT_STREQ("float" , FD::TypeName(FD::TYPE_FLOAT ));
+ EXPECT_STREQ("int64" , FD::TypeName(FD::TYPE_INT64 ));
+ EXPECT_STREQ("uint64" , FD::TypeName(FD::TYPE_UINT64 ));
+ EXPECT_STREQ("int32" , FD::TypeName(FD::TYPE_INT32 ));
+ EXPECT_STREQ("fixed64" , FD::TypeName(FD::TYPE_FIXED64 ));
+ EXPECT_STREQ("fixed32" , FD::TypeName(FD::TYPE_FIXED32 ));
+ EXPECT_STREQ("bool" , FD::TypeName(FD::TYPE_BOOL ));
+ EXPECT_STREQ("string" , FD::TypeName(FD::TYPE_STRING ));
+ EXPECT_STREQ("group" , FD::TypeName(FD::TYPE_GROUP ));
+ EXPECT_STREQ("message" , FD::TypeName(FD::TYPE_MESSAGE ));
+ EXPECT_STREQ("bytes" , FD::TypeName(FD::TYPE_BYTES ));
+ EXPECT_STREQ("uint32" , FD::TypeName(FD::TYPE_UINT32 ));
+ EXPECT_STREQ("enum" , FD::TypeName(FD::TYPE_ENUM ));
+ EXPECT_STREQ("sfixed32", FD::TypeName(FD::TYPE_SFIXED32));
+ EXPECT_STREQ("sfixed64", FD::TypeName(FD::TYPE_SFIXED64));
+ EXPECT_STREQ("sint32" , FD::TypeName(FD::TYPE_SINT32 ));
+ EXPECT_STREQ("sint64" , FD::TypeName(FD::TYPE_SINT64 ));
+}
+
TEST_F(MiscTest, CppTypes) {
// Test that CPP types are assigned correctly.
@@ -1576,6 +1859,99 @@ TEST_F(MiscTest, CppTypes) {
EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_SINT64 ));
}
+TEST_F(MiscTest, CppTypeNames) {
+ // Test that correct CPP type names are returned.
+
+ typedef FieldDescriptor FD; // avoid ugly line wrapping
+
+ EXPECT_STREQ("double" , GetCppTypeNameForFieldType(FD::TYPE_DOUBLE ));
+ EXPECT_STREQ("float" , GetCppTypeNameForFieldType(FD::TYPE_FLOAT ));
+ EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_INT64 ));
+ EXPECT_STREQ("uint64" , GetCppTypeNameForFieldType(FD::TYPE_UINT64 ));
+ EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_INT32 ));
+ EXPECT_STREQ("uint64" , GetCppTypeNameForFieldType(FD::TYPE_FIXED64 ));
+ EXPECT_STREQ("uint32" , GetCppTypeNameForFieldType(FD::TYPE_FIXED32 ));
+ EXPECT_STREQ("bool" , GetCppTypeNameForFieldType(FD::TYPE_BOOL ));
+ EXPECT_STREQ("string" , GetCppTypeNameForFieldType(FD::TYPE_STRING ));
+ EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_GROUP ));
+ EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_MESSAGE ));
+ EXPECT_STREQ("string" , GetCppTypeNameForFieldType(FD::TYPE_BYTES ));
+ EXPECT_STREQ("uint32" , GetCppTypeNameForFieldType(FD::TYPE_UINT32 ));
+ EXPECT_STREQ("enum" , GetCppTypeNameForFieldType(FD::TYPE_ENUM ));
+ EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_SFIXED32));
+ EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_SFIXED64));
+ EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_SINT32 ));
+ EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_SINT64 ));
+}
+
+TEST_F(MiscTest, StaticCppTypeNames) {
+ // Test that correct CPP type names are returned.
+
+ typedef FieldDescriptor FD; // avoid ugly line wrapping
+
+ EXPECT_STREQ("int32" , FD::CppTypeName(FD::CPPTYPE_INT32 ));
+ EXPECT_STREQ("int64" , FD::CppTypeName(FD::CPPTYPE_INT64 ));
+ EXPECT_STREQ("uint32" , FD::CppTypeName(FD::CPPTYPE_UINT32 ));
+ EXPECT_STREQ("uint64" , FD::CppTypeName(FD::CPPTYPE_UINT64 ));
+ EXPECT_STREQ("double" , FD::CppTypeName(FD::CPPTYPE_DOUBLE ));
+ EXPECT_STREQ("float" , FD::CppTypeName(FD::CPPTYPE_FLOAT ));
+ EXPECT_STREQ("bool" , FD::CppTypeName(FD::CPPTYPE_BOOL ));
+ EXPECT_STREQ("enum" , FD::CppTypeName(FD::CPPTYPE_ENUM ));
+ EXPECT_STREQ("string" , FD::CppTypeName(FD::CPPTYPE_STRING ));
+ EXPECT_STREQ("message", FD::CppTypeName(FD::CPPTYPE_MESSAGE));
+}
+
+TEST_F(MiscTest, MessageType) {
+ // Test that message_type() is NULL for non-aggregate fields
+
+ typedef FieldDescriptor FD; // avoid ugly line wrapping
+
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_DOUBLE ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_FLOAT ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_INT64 ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_UINT64 ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_INT32 ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_FIXED64 ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_FIXED32 ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_BOOL ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_STRING ));
+ EXPECT_TRUE(NULL != GetMessageDescriptorForFieldType(FD::TYPE_GROUP ));
+ EXPECT_TRUE(NULL != GetMessageDescriptorForFieldType(FD::TYPE_MESSAGE ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_BYTES ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_UINT32 ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_ENUM ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED32));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED64));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_SINT32 ));
+ EXPECT_TRUE(NULL == GetMessageDescriptorForFieldType(FD::TYPE_SINT64 ));
+}
+
+TEST_F(MiscTest, EnumType) {
+ // Test that enum_type() is NULL for non-enum fields
+
+ typedef FieldDescriptor FD; // avoid ugly line wrapping
+
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_DOUBLE ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_FLOAT ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_INT64 ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_UINT64 ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_INT32 ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_FIXED64 ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_FIXED32 ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_BOOL ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_STRING ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_GROUP ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_MESSAGE ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_BYTES ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_UINT32 ));
+ EXPECT_TRUE(NULL != GetEnumDescriptorForFieldType(FD::TYPE_ENUM ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED32));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED64));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_SINT32 ));
+ EXPECT_TRUE(NULL == GetEnumDescriptorForFieldType(FD::TYPE_SINT64 ));
+}
+
+
TEST_F(MiscTest, DefaultValues) {
// Test that setting default values works.
FileDescriptorProto file_proto;
@@ -1670,7 +2046,7 @@ TEST_F(MiscTest, DefaultValues) {
message->field(3)->default_value_uint64());
EXPECT_EQ(4.5 , message->field(4)->default_value_float ());
EXPECT_EQ(10e100 , message->field(5)->default_value_double());
- EXPECT_EQ(true , message->field(6)->default_value_bool ());
+ EXPECT_TRUE( message->field(6)->default_value_bool ());
EXPECT_EQ("hello" , message->field(7)->default_value_string());
EXPECT_EQ("\001\002\003" , message->field(8)->default_value_string());
EXPECT_EQ(enum_value_b , message->field(9)->default_value_enum ());
@@ -1693,7 +2069,7 @@ TEST_F(MiscTest, DefaultValues) {
EXPECT_EQ(0 , message->field(14)->default_value_uint64());
EXPECT_EQ(0.0f , message->field(15)->default_value_float ());
EXPECT_EQ(0.0 , message->field(16)->default_value_double());
- EXPECT_EQ(false, message->field(17)->default_value_bool ());
+ EXPECT_FALSE( message->field(17)->default_value_bool ());
EXPECT_EQ("" , message->field(18)->default_value_string());
EXPECT_EQ("" , message->field(19)->default_value_string());
EXPECT_EQ(enum_value_a, message->field(20)->default_value_enum());
@@ -1739,13 +2115,31 @@ TEST_F(MiscTest, FieldOptions) {
}
// ===================================================================
+enum DescriptorPoolMode {
+ NO_DATABASE,
+ FALLBACK_DATABASE
+};
-class AllowUnknownDependenciesTest : public testing::Test {
+class AllowUnknownDependenciesTest
+ : public testing::TestWithParam<DescriptorPoolMode> {
protected:
+ DescriptorPoolMode mode() {
+ return GetParam();
+ }
+
virtual void SetUp() {
FileDescriptorProto foo_proto, bar_proto;
- pool_.AllowUnknownDependencies();
+ switch (mode()) {
+ case NO_DATABASE:
+ pool_.reset(new DescriptorPool);
+ break;
+ case FALLBACK_DATABASE:
+ pool_.reset(new DescriptorPool(&db_));
+ break;
+ }
+
+ pool_->AllowUnknownDependencies();
ASSERT_TRUE(TextFormat::ParseFromString(
"name: 'foo.proto'"
@@ -1776,13 +2170,13 @@ class AllowUnknownDependenciesTest : public testing::Test {
&bar_proto));
// Collect pointers to stuff.
- bar_file_ = pool_.BuildFile(bar_proto);
+ bar_file_ = BuildFile(bar_proto);
ASSERT_TRUE(bar_file_ != NULL);
ASSERT_EQ(1, bar_file_->message_type_count());
bar_type_ = bar_file_->message_type(0);
- foo_file_ = pool_.BuildFile(foo_proto);
+ foo_file_ = BuildFile(foo_proto);
ASSERT_TRUE(foo_file_ != NULL);
ASSERT_EQ(1, foo_file_->message_type_count());
@@ -1794,6 +2188,20 @@ class AllowUnknownDependenciesTest : public testing::Test {
qux_field_ = foo_type_->field(2);
}
+ const FileDescriptor* BuildFile(const FileDescriptorProto& proto) {
+ switch (mode()) {
+ case NO_DATABASE:
+ return pool_->BuildFile(proto);
+ break;
+ case FALLBACK_DATABASE: {
+ EXPECT_TRUE(db_.Add(proto));
+ return pool_->FindFileByName(proto.name());
+ }
+ }
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+ }
+
const FileDescriptor* bar_file_;
const Descriptor* bar_type_;
const FileDescriptor* foo_file_;
@@ -1802,46 +2210,56 @@ class AllowUnknownDependenciesTest : public testing::Test {
const FieldDescriptor* baz_field_;
const FieldDescriptor* qux_field_;
- DescriptorPool pool_;
+ SimpleDescriptorDatabase db_; // used if in FALLBACK_DATABASE mode.
+ scoped_ptr<DescriptorPool> pool_;
};
-TEST_F(AllowUnknownDependenciesTest, PlaceholderFile) {
+TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
ASSERT_EQ(2, foo_file_->dependency_count());
EXPECT_EQ(bar_file_, foo_file_->dependency(0));
+ EXPECT_FALSE(bar_file_->is_placeholder());
const FileDescriptor* baz_file = foo_file_->dependency(1);
EXPECT_EQ("baz.proto", baz_file->name());
EXPECT_EQ(0, baz_file->message_type_count());
+ EXPECT_TRUE(baz_file->is_placeholder());
// Placeholder files should not be findable.
- EXPECT_EQ(bar_file_, pool_.FindFileByName(bar_file_->name()));
- EXPECT_TRUE(pool_.FindFileByName(baz_file->name()) == NULL);
+ 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_F(AllowUnknownDependenciesTest, PlaceholderTypes) {
+TEST_P(AllowUnknownDependenciesTest, PlaceholderTypes) {
ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_field_->type());
EXPECT_EQ(bar_type_, bar_field_->message_type());
+ EXPECT_FALSE(bar_type_->is_placeholder());
ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_field_->type());
const Descriptor* baz_type = baz_field_->message_type();
EXPECT_EQ("Baz", baz_type->name());
EXPECT_EQ("Baz", baz_type->full_name());
- EXPECT_EQ("Baz.placeholder.proto", baz_type->file()->name());
EXPECT_EQ(0, baz_type->extension_range_count());
+ EXPECT_TRUE(baz_type->is_placeholder());
ASSERT_EQ(FieldDescriptor::TYPE_ENUM, qux_field_->type());
const EnumDescriptor* qux_type = qux_field_->enum_type();
EXPECT_EQ("Qux", qux_type->name());
EXPECT_EQ("corge.Qux", qux_type->full_name());
- EXPECT_EQ("corge.Qux.placeholder.proto", qux_type->file()->name());
+ EXPECT_TRUE(qux_type->is_placeholder());
// Placeholder types should not be findable.
- EXPECT_EQ(bar_type_, pool_.FindMessageTypeByName(bar_type_->full_name()));
- EXPECT_TRUE(pool_.FindMessageTypeByName(baz_type->full_name()) == NULL);
- EXPECT_TRUE(pool_.FindEnumTypeByName(qux_type->full_name()) == NULL);
+ EXPECT_EQ(bar_type_, pool_->FindMessageTypeByName(bar_type_->full_name()));
+ EXPECT_TRUE(pool_->FindMessageTypeByName(baz_type->full_name()) == NULL);
+ EXPECT_TRUE(pool_->FindEnumTypeByName(qux_type->full_name()) == NULL);
}
-TEST_F(AllowUnknownDependenciesTest, CopyTo) {
+TEST_P(AllowUnknownDependenciesTest, CopyTo) {
// FieldDescriptor::CopyTo() should write non-fully-qualified type names
// for placeholder types which were not originally fully-qualified.
FieldDescriptorProto proto;
@@ -1864,7 +2282,7 @@ TEST_F(AllowUnknownDependenciesTest, CopyTo) {
EXPECT_EQ(FieldDescriptorProto::TYPE_ENUM, proto.type());
}
-TEST_F(AllowUnknownDependenciesTest, CustomOptions) {
+TEST_P(AllowUnknownDependenciesTest, CustomOptions) {
// Qux should still have the uninterpreted option attached.
ASSERT_EQ(1, qux_field_->options().uninterpreted_option_size());
const UninterpretedOption& option =
@@ -1873,7 +2291,7 @@ TEST_F(AllowUnknownDependenciesTest, CustomOptions) {
EXPECT_EQ("grault", option.name(0).name_part());
}
-TEST_F(AllowUnknownDependenciesTest, UnknownExtendee) {
+TEST_P(AllowUnknownDependenciesTest, UnknownExtendee) {
// Test that we can extend an unknown type. This is slightly tricky because
// it means that the placeholder type must have an extension range.
@@ -1884,19 +2302,20 @@ TEST_F(AllowUnknownDependenciesTest, UnknownExtendee) {
"extension { extendee: 'UnknownType' name:'some_extension' number:123"
" label:LABEL_OPTIONAL type:TYPE_INT32 }",
&extension_proto));
- const FileDescriptor* file = pool_.BuildFile(extension_proto);
+ const FileDescriptor* file = BuildFile(extension_proto);
ASSERT_TRUE(file != NULL);
ASSERT_EQ(1, file->extension_count());
const Descriptor* extendee = file->extension(0)->containing_type();
EXPECT_EQ("UnknownType", extendee->name());
+ EXPECT_TRUE(extendee->is_placeholder());
ASSERT_EQ(1, extendee->extension_range_count());
EXPECT_EQ(1, extendee->extension_range(0)->start);
EXPECT_EQ(FieldDescriptor::kMaxNumber + 1, extendee->extension_range(0)->end);
}
-TEST_F(AllowUnknownDependenciesTest, CustomOption) {
+TEST_P(AllowUnknownDependenciesTest, CustomOption) {
// Test that we can use a custom option without having parsed
// descriptor.proto.
@@ -1937,7 +2356,7 @@ TEST_F(AllowUnknownDependenciesTest, CustomOption) {
"}",
&option_proto));
- const FileDescriptor* file = pool_.BuildFile(option_proto);
+ const FileDescriptor* file = BuildFile(option_proto);
ASSERT_TRUE(file != NULL);
// Verify that no extension options were set, but they were left as
@@ -1949,6 +2368,81 @@ TEST_F(AllowUnknownDependenciesTest, CustomOption) {
EXPECT_EQ(2, file->options().uninterpreted_option_size());
}
+TEST_P(AllowUnknownDependenciesTest,
+ UndeclaredDependencyTriggersBuildOfDependency) {
+ // Crazy case: suppose foo.proto refers to a symbol without declaring the
+ // dependency that finds it. In the event that the pool is backed by a
+ // DescriptorDatabase, the pool will attempt to find the symbol in the
+ // database. If successful, it will build the undeclared dependency to verify
+ // that the file does indeed contain the symbol. If that file fails to build,
+ // then its descriptors must be rolled back. However, we still want foo.proto
+ // to build successfully, since we are allowing unknown dependencies.
+
+ FileDescriptorProto undeclared_dep_proto;
+ // We make this file fail to build by giving it two fields with tag 1.
+ ASSERT_TRUE(TextFormat::ParseFromString(
+ "name: \"invalid_file_as_undeclared_dep.proto\" "
+ "package: \"undeclared\" "
+ "message_type: { "
+ " name: \"Quux\" "
+ " field { "
+ " name:'qux' number:1 label:LABEL_OPTIONAL type: TYPE_INT32 "
+ " }"
+ " field { "
+ " name:'quux' number:1 label:LABEL_OPTIONAL type: TYPE_INT64 "
+ " }"
+ "}",
+ &undeclared_dep_proto));
+ // We can't use the BuildFile() helper because we don't actually want to build
+ // it into the descriptor pool in the fallback database case: it just needs to
+ // be sitting in the database so that it gets built during the building of
+ // test.proto below.
+ switch (mode()) {
+ case NO_DATABASE: {
+ ASSERT_TRUE(pool_->BuildFile(undeclared_dep_proto) == NULL);
+ break;
+ }
+ case FALLBACK_DATABASE: {
+ ASSERT_TRUE(db_.Add(undeclared_dep_proto));
+ }
+ }
+
+ FileDescriptorProto test_proto;
+ ASSERT_TRUE(TextFormat::ParseFromString(
+ "name: \"test.proto\" "
+ "message_type: { "
+ " name: \"Corge\" "
+ " field { "
+ " name:'quux' number:1 label: LABEL_OPTIONAL "
+ " type_name:'undeclared.Quux' type: TYPE_MESSAGE "
+ " }"
+ "}",
+ &test_proto));
+
+ const FileDescriptor* file = BuildFile(test_proto);
+ ASSERT_TRUE(file != NULL);
+ GOOGLE_LOG(INFO) << file->DebugString();
+
+ EXPECT_EQ(0, file->dependency_count());
+ ASSERT_EQ(1, file->message_type_count());
+ const Descriptor* corge_desc = file->message_type(0);
+ ASSERT_EQ("Corge", corge_desc->name());
+ ASSERT_EQ(1, corge_desc->field_count());
+ EXPECT_FALSE(corge_desc->is_placeholder());
+
+ const FieldDescriptor* quux_field = corge_desc->field(0);
+ ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, quux_field->type());
+ ASSERT_EQ("Quux", quux_field->message_type()->name());
+ ASSERT_EQ("undeclared.Quux", quux_field->message_type()->full_name());
+ EXPECT_TRUE(quux_field->message_type()->is_placeholder());
+ // The place holder type should not be findable.
+ ASSERT_TRUE(pool_->FindMessageTypeByName("undeclared.Quux") == NULL);
+}
+
+INSTANTIATE_TEST_CASE_P(DatabaseSource,
+ AllowUnknownDependenciesTest,
+ testing::Values(NO_DATABASE, FALLBACK_DATABASE));
+
// ===================================================================
TEST(CustomOptions, OptionLocations) {
@@ -2212,6 +2706,170 @@ TEST(CustomOptions, MessageOptionThreeFieldsSet) {
EXPECT_EQ(1234, options.GetExtension(protobuf_unittest::complex_opt1).foo());
}
+TEST(CustomOptions, MessageOptionRepeatedLeafFieldSet) {
+ // This test verifies that repeated fields in custom options can be
+ // given multiple values by repeating the option with a different value.
+ // This test checks repeated leaf values. Each repeated custom value
+ // appears in a different uninterpreted_option, which will be concatenated
+ // when they are merged into the final option value.
+ DescriptorPool pool;
+
+ FileDescriptorProto file_proto;
+ FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+ ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+ protobuf_unittest::TestMessageWithCustomOptions::descriptor()
+ ->file()->CopyTo(&file_proto);
+ ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+ // The following represents the definition:
+ //
+ // import "google/protobuf/unittest_custom_options.proto"
+ // package protobuf_unittest;
+ // message Foo {
+ // option (complex_opt1).foo4 = 12;
+ // option (complex_opt1).foo4 = 34;
+ // option (complex_opt1).foo4 = 56;
+ // }
+ ASSERT_TRUE(TextFormat::ParseFromString(
+ "name: \"custom_options_import.proto\" "
+ "package: \"protobuf_unittest\" "
+ "dependency: \"google/protobuf/unittest_custom_options.proto\" "
+ "message_type { "
+ " name: \"Foo\" "
+ " options { "
+ " uninterpreted_option { "
+ " name { "
+ " name_part: \"complex_opt1\" "
+ " is_extension: true "
+ " } "
+ " name { "
+ " name_part: \"foo4\" "
+ " is_extension: false "
+ " } "
+ " positive_int_value: 12 "
+ " } "
+ " uninterpreted_option { "
+ " name { "
+ " name_part: \"complex_opt1\" "
+ " is_extension: true "
+ " } "
+ " name { "
+ " name_part: \"foo4\" "
+ " is_extension: false "
+ " } "
+ " positive_int_value: 34 "
+ " } "
+ " uninterpreted_option { "
+ " name { "
+ " name_part: \"complex_opt1\" "
+ " is_extension: true "
+ " } "
+ " name { "
+ " name_part: \"foo4\" "
+ " is_extension: false "
+ " } "
+ " positive_int_value: 56 "
+ " } "
+ " } "
+ "}",
+ &file_proto));
+
+ const FileDescriptor* file = pool.BuildFile(file_proto);
+ ASSERT_TRUE(file != NULL);
+ ASSERT_EQ(1, file->message_type_count());
+
+ const MessageOptions& options = file->message_type(0)->options();
+ EXPECT_EQ(3, options.GetExtension(protobuf_unittest::complex_opt1).foo4_size());
+ EXPECT_EQ(12, options.GetExtension(protobuf_unittest::complex_opt1).foo4(0));
+ EXPECT_EQ(34, options.GetExtension(protobuf_unittest::complex_opt1).foo4(1));
+ EXPECT_EQ(56, options.GetExtension(protobuf_unittest::complex_opt1).foo4(2));
+}
+
+TEST(CustomOptions, MessageOptionRepeatedMsgFieldSet) {
+ // This test verifies that repeated fields in custom options can be
+ // given multiple values by repeating the option with a different value.
+ // This test checks repeated message values. Each repeated custom value
+ // appears in a different uninterpreted_option, which will be concatenated
+ // when they are merged into the final option value.
+ DescriptorPool pool;
+
+ FileDescriptorProto file_proto;
+ FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+ ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+ protobuf_unittest::TestMessageWithCustomOptions::descriptor()
+ ->file()->CopyTo(&file_proto);
+ ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+ // The following represents the definition:
+ //
+ // import "google/protobuf/unittest_custom_options.proto"
+ // package protobuf_unittest;
+ // message Foo {
+ // option (complex_opt2).barney = {waldo: 1};
+ // option (complex_opt2).barney = {waldo: 10};
+ // option (complex_opt2).barney = {waldo: 100};
+ // }
+ ASSERT_TRUE(TextFormat::ParseFromString(
+ "name: \"custom_options_import.proto\" "
+ "package: \"protobuf_unittest\" "
+ "dependency: \"google/protobuf/unittest_custom_options.proto\" "
+ "message_type { "
+ " name: \"Foo\" "
+ " options { "
+ " uninterpreted_option { "
+ " name { "
+ " name_part: \"complex_opt2\" "
+ " is_extension: true "
+ " } "
+ " name { "
+ " name_part: \"barney\" "
+ " is_extension: false "
+ " } "
+ " aggregate_value: \"waldo: 1\" "
+ " } "
+ " uninterpreted_option { "
+ " name { "
+ " name_part: \"complex_opt2\" "
+ " is_extension: true "
+ " } "
+ " name { "
+ " name_part: \"barney\" "
+ " is_extension: false "
+ " } "
+ " aggregate_value: \"waldo: 10\" "
+ " } "
+ " uninterpreted_option { "
+ " name { "
+ " name_part: \"complex_opt2\" "
+ " is_extension: true "
+ " } "
+ " name { "
+ " name_part: \"barney\" "
+ " is_extension: false "
+ " } "
+ " aggregate_value: \"waldo: 100\" "
+ " } "
+ " } "
+ "}",
+ &file_proto));
+
+ const FileDescriptor* file = pool.BuildFile(file_proto);
+ ASSERT_TRUE(file != NULL);
+ ASSERT_EQ(1, file->message_type_count());
+
+ const MessageOptions& options = file->message_type(0)->options();
+ EXPECT_EQ(3, options.GetExtension(
+ protobuf_unittest::complex_opt2).barney_size());
+ EXPECT_EQ(1,options.GetExtension(
+ protobuf_unittest::complex_opt2).barney(0).waldo());
+ EXPECT_EQ(10, options.GetExtension(
+ protobuf_unittest::complex_opt2).barney(1).waldo());
+ EXPECT_EQ(100, options.GetExtension(
+ protobuf_unittest::complex_opt2).barney(2).waldo());
+}
+
// Check that aggregate options were parsed and saved correctly in
// the appropriate descriptors.
TEST(CustomOptions, AggregateOptions) {
@@ -2252,6 +2910,27 @@ TEST(CustomOptions, AggregateOptions) {
method->options().GetExtension(protobuf_unittest::methodopt).s());
}
+TEST(CustomOptions, UnusedImportWarning) {
+ DescriptorPool pool;
+
+ FileDescriptorProto file_proto;
+ FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+ ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+ protobuf_unittest::TestMessageWithCustomOptions::descriptor()
+ ->file()->CopyTo(&file_proto);
+ ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+
+ pool.AddUnusedImportTrackFile("custom_options_import.proto");
+ ASSERT_TRUE(TextFormat::ParseFromString(
+ "name: \"custom_options_import.proto\" "
+ "package: \"protobuf_unittest\" "
+ "dependency: \"google/protobuf/unittest_custom_options.proto\" ",
+ &file_proto));
+ pool.BuildFile(file_proto);
+}
+
// ===================================================================
// The tests below trigger every unique call to AddError() in descriptor.cc,
@@ -2265,6 +2944,7 @@ class MockErrorCollector : public DescriptorPool::ErrorCollector {
~MockErrorCollector() {}
string text_;
+ string warning_text_;
// implements ErrorCollector ---------------------------------------
void AddError(const string& filename,
@@ -2288,6 +2968,29 @@ class MockErrorCollector : public DescriptorPool::ErrorCollector {
&text_, "$0: $1: $2: $3\n",
filename, element_name, location_name, message);
}
+
+ // implements ErrorCollector ---------------------------------------
+ void AddWarning(const string& filename, const string& element_name,
+ const Message* descriptor, ErrorLocation location,
+ const string& message) {
+ const char* location_name = NULL;
+ switch (location) {
+ case NAME : location_name = "NAME" ; break;
+ case NUMBER : location_name = "NUMBER" ; break;
+ case TYPE : location_name = "TYPE" ; break;
+ case EXTENDEE : location_name = "EXTENDEE" ; break;
+ case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
+ case OPTION_NAME : location_name = "OPTION_NAME" ; break;
+ case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
+ case INPUT_TYPE : location_name = "INPUT_TYPE" ; break;
+ case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break;
+ case OTHER : location_name = "OTHER" ; break;
+ }
+
+ strings::SubstituteAndAppend(
+ &warning_text_, "$0: $1: $2: $3\n",
+ filename, element_name, location_name, message);
+ }
};
class ValidationErrorTest : public testing::Test {
@@ -2314,6 +3017,19 @@ class ValidationErrorTest : public testing::Test {
EXPECT_EQ(expected_errors, error_collector.text_);
}
+ // Parse file_text as a FileDescriptorProto in text format and add it
+ // to the DescriptorPool. Expect errors to be produced which match the
+ // given warning text.
+ void BuildFileWithWarnings(const string& file_text,
+ const string& expected_warnings) {
+ FileDescriptorProto file_proto;
+ ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
+
+ MockErrorCollector error_collector;
+ EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector));
+ EXPECT_EQ(expected_warnings, error_collector.warning_text_);
+ }
+
// Builds some already-parsed file in our test pool.
void BuildFileInTestPool(const FileDescriptor* file) {
FileDescriptorProto file_proto;
@@ -2451,6 +3167,15 @@ TEST_F(ValidationErrorTest, UnknownDependency) {
"bar.proto: bar.proto: OTHER: Import \"foo.proto\" has not been loaded.\n");
}
+TEST_F(ValidationErrorTest, InvalidPublicDependencyIndex) {
+ BuildFile("name: \"foo.proto\"");
+ BuildFileWithErrors(
+ "name: \"bar.proto\" "
+ "dependency: \"foo.proto\" "
+ "public_dependency: 1",
+ "bar.proto: bar.proto: OTHER: Invalid public dependency index.\n");
+}
+
TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) {
// Used to crash: If we depend on a non-existent file and then refer to a
// package defined in a file that we didn't import, and that package is
@@ -2558,8 +3283,8 @@ TEST_F(ValidationErrorTest, InvalidDefaults) {
" default_value: \"1\" }"
"}",
- "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value.\n"
- "foo.proto: Foo.bar: DEFAULT_VALUE: Couldn't parse default value.\n"
+ "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value \"abc\".\n"
+ "foo.proto: Foo.bar: DEFAULT_VALUE: Couldn't parse default value \"\".\n"
"foo.proto: Foo.baz: DEFAULT_VALUE: Boolean default must be true or "
"false.\n"
"foo.proto: Foo.qux: DEFAULT_VALUE: Messages can't have default values.\n"
@@ -2642,6 +3367,38 @@ TEST_F(ValidationErrorTest, NonExtensionWithExtendee) {
"non-extension field.\n");
}
+TEST_F(ValidationErrorTest, FieldOneofIndexTooLarge) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+ " oneof_index: 1 }"
+ " field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 "
+ " oneof_index: 0 }"
+ " oneof_decl { name:\"bar\" }"
+ "}",
+
+ "foo.proto: Foo.foo: OTHER: FieldDescriptorProto.oneof_index 1 is out of "
+ "range for type \"Foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, FieldOneofIndexNegative) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+ " oneof_index: -1 }"
+ " field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 "
+ " oneof_index: 0 }"
+ " oneof_decl { name:\"bar\" }"
+ "}",
+
+ "foo.proto: Foo.foo: OTHER: FieldDescriptorProto.oneof_index -1 is out of "
+ "range for type \"Foo\".\n");
+}
+
TEST_F(ValidationErrorTest, FieldNumberConflict) {
BuildFileWithErrors(
"name: \"foo.proto\" "
@@ -2802,6 +3559,28 @@ TEST_F(ValidationErrorTest, NotAnExtensionNumber) {
"number.\n");
}
+TEST_F(ValidationErrorTest, RequiredExtension) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "message_type {"
+ " name: \"Bar\""
+ " extension_range { start: 1000 end: 10000 }"
+ "}"
+ "message_type {"
+ " name: \"Foo\""
+ " extension {"
+ " name:\"foo\""
+ " number:1000"
+ " label:LABEL_REQUIRED"
+ " type:TYPE_INT32"
+ " extendee: \"Bar\""
+ " }"
+ "}",
+
+ "foo.proto: Foo.foo: TYPE: Message extensions cannot have required "
+ "fields.\n");
+}
+
TEST_F(ValidationErrorTest, UndefinedFieldType) {
BuildFileWithErrors(
"name: \"foo.proto\" "
@@ -2813,6 +3592,36 @@ TEST_F(ValidationErrorTest, UndefinedFieldType) {
"foo.proto: Foo.foo: TYPE: \"Bar\" is not defined.\n");
}
+TEST_F(ValidationErrorTest, UndefinedFieldTypeWithDefault) {
+ // See b/12533582. Previously this failed because the default value was not
+ // accepted by the parser, which assumed an enum type, leading to an unclear
+ // error message. We want this input to yield a validation error instead,
+ // since the unknown type is the primary problem.
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"int\" "
+ " default_value:\"1\" }"
+ "}",
+
+ "foo.proto: Foo.foo: TYPE: \"int\" is not defined.\n");
+}
+
+TEST_F(ValidationErrorTest, UndefinedNestedFieldType) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " nested_type { name:\"Baz\" }"
+ " field { name:\"foo\" number:1"
+ " label:LABEL_OPTIONAL"
+ " type_name:\"Foo.Baz.Bar\" }"
+ "}",
+
+ "foo.proto: Foo.foo: TYPE: \"Foo.Baz.Bar\" is not defined.\n");
+}
+
TEST_F(ValidationErrorTest, FieldTypeDefinedInUndeclaredDependency) {
BuildFile(
"name: \"bar.proto\" "
@@ -2829,8 +3638,167 @@ TEST_F(ValidationErrorTest, FieldTypeDefinedInUndeclaredDependency) {
"necessary import.\n");
}
+TEST_F(ValidationErrorTest, FieldTypeDefinedInIndirectDependency) {
+ // Test for hidden dependencies.
+ //
+ // // bar.proto
+ // message Bar{}
+ //
+ // // forward.proto
+ // import "bar.proto"
+ //
+ // // foo.proto
+ // import "forward.proto"
+ // message Foo {
+ // optional Bar foo = 1; // Error, needs to import bar.proto explicitly.
+ // }
+ //
+ BuildFile(
+ "name: \"bar.proto\" "
+ "message_type { name: \"Bar\" }");
+
+ BuildFile(
+ "name: \"forward.proto\""
+ "dependency: \"bar.proto\"");
+
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "dependency: \"forward.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+ "}",
+ "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
+ "which is not imported by \"foo.proto\". To use it here, please add the "
+ "necessary import.\n");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeDefinedInPublicDependency) {
+ // Test for public dependencies.
+ //
+ // // bar.proto
+ // message Bar{}
+ //
+ // // forward.proto
+ // import public "bar.proto"
+ //
+ // // foo.proto
+ // import "forward.proto"
+ // message Foo {
+ // optional Bar foo = 1; // Correct. "bar.proto" is public imported into
+ // // forward.proto, so when "foo.proto" imports
+ // // "forward.proto", it imports "bar.proto" too.
+ // }
+ //
+ BuildFile(
+ "name: \"bar.proto\" "
+ "message_type { name: \"Bar\" }");
+
+ BuildFile(
+ "name: \"forward.proto\""
+ "dependency: \"bar.proto\" "
+ "public_dependency: 0");
+
+ BuildFile(
+ "name: \"foo.proto\" "
+ "dependency: \"forward.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+ "}");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeDefinedInTransitivePublicDependency) {
+ // Test for public dependencies.
+ //
+ // // bar.proto
+ // message Bar{}
+ //
+ // // forward.proto
+ // import public "bar.proto"
+ //
+ // // forward2.proto
+ // import public "forward.proto"
+ //
+ // // foo.proto
+ // import "forward2.proto"
+ // message Foo {
+ // optional Bar foo = 1; // Correct, public imports are transitive.
+ // }
+ //
+ BuildFile(
+ "name: \"bar.proto\" "
+ "message_type { name: \"Bar\" }");
+
+ BuildFile(
+ "name: \"forward.proto\""
+ "dependency: \"bar.proto\" "
+ "public_dependency: 0");
+
+ BuildFile(
+ "name: \"forward2.proto\""
+ "dependency: \"forward.proto\" "
+ "public_dependency: 0");
+
+ BuildFile(
+ "name: \"foo.proto\" "
+ "dependency: \"forward2.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+ "}");
+}
+
+TEST_F(ValidationErrorTest,
+ FieldTypeDefinedInPrivateDependencyOfPublicDependency) {
+ // Test for public dependencies.
+ //
+ // // bar.proto
+ // message Bar{}
+ //
+ // // forward.proto
+ // import "bar.proto"
+ //
+ // // forward2.proto
+ // import public "forward.proto"
+ //
+ // // foo.proto
+ // import "forward2.proto"
+ // message Foo {
+ // optional Bar foo = 1; // Error, the "bar.proto" is not public imported
+ // // into "forward.proto", so will not be imported
+ // // into either "forward2.proto" or "foo.proto".
+ // }
+ //
+ BuildFile(
+ "name: \"bar.proto\" "
+ "message_type { name: \"Bar\" }");
+
+ BuildFile(
+ "name: \"forward.proto\""
+ "dependency: \"bar.proto\"");
+
+ BuildFile(
+ "name: \"forward2.proto\""
+ "dependency: \"forward.proto\" "
+ "public_dependency: 0");
+
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "dependency: \"forward2.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+ "}",
+ "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
+ "which is not imported by \"foo.proto\". To use it here, please add the "
+ "necessary import.\n");
+}
+
+
TEST_F(ValidationErrorTest, SearchMostLocalFirst) {
- // The following should produce an error that Bar.Baz is not defined:
+ // The following should produce an error that Bar.Baz is resolved but
+ // not defined:
// message Bar { message Baz {} }
// message Foo {
// message Bar {
@@ -2856,7 +3824,10 @@ TEST_F(ValidationErrorTest, SearchMostLocalFirst) {
" type_name:\"Bar.Baz\" }"
"}",
- "foo.proto: Foo.baz: TYPE: \"Bar.Baz\" is not defined.\n");
+ "foo.proto: Foo.baz: TYPE: \"Bar.Baz\" is resolved to \"Foo.Bar.Baz\","
+ " which is not defined. The innermost scope is searched first in name "
+ "resolution. Consider using a leading '.'(i.e., \".Bar.Baz\") to start "
+ "from the outermost scope.\n");
}
TEST_F(ValidationErrorTest, SearchMostLocalFirst2) {
@@ -2998,6 +3969,20 @@ TEST_F(ValidationErrorTest, BadEnumDefaultValue) {
"\"NO_SUCH_VALUE\".\n");
}
+TEST_F(ValidationErrorTest, EnumDefaultValueIsInteger) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\""
+ " default_value:\"0\" }"
+ "}",
+
+ "foo.proto: Foo.foo: DEFAULT_VALUE: Default value for an enum field must "
+ "be an identifier.\n");
+}
+
TEST_F(ValidationErrorTest, PrimitiveWithTypeName) {
BuildFileWithErrors(
"name: \"foo.proto\" "
@@ -3022,6 +4007,31 @@ TEST_F(ValidationErrorTest, NonPrimitiveWithoutTypeName) {
"type_name.\n");
}
+TEST_F(ValidationErrorTest, OneofWithNoFields) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " oneof_decl { name:\"bar\" }"
+ "}",
+
+ "foo.proto: Foo.bar: NAME: Oneof must have at least one field.\n");
+}
+
+TEST_F(ValidationErrorTest, OneofLabelMismatch) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "message_type {"
+ " name: \"Foo\""
+ " field { name:\"foo\" number:1 label:LABEL_REPEATED type:TYPE_INT32 "
+ " oneof_index:0 }"
+ " oneof_decl { name:\"bar\" }"
+ "}",
+
+ "foo.proto: Foo.foo: NAME: Fields of oneofs must themselves have label "
+ "LABEL_OPTIONAL.\n");
+}
+
TEST_F(ValidationErrorTest, InputTypeNotDefined) {
BuildFileWithErrors(
"name: \"foo.proto\" "
@@ -3031,7 +4041,8 @@ TEST_F(ValidationErrorTest, InputTypeNotDefined) {
" method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
"}",
- "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n");
+ "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n"
+ );
}
TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
@@ -3044,7 +4055,8 @@ TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
" method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
"}",
- "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n");
+ "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n"
+ );
}
TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
@@ -3056,7 +4068,8 @@ TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
" method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
"}",
- "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n");
+ "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n"
+ );
}
TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
@@ -3069,9 +4082,11 @@ TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
" method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
"}",
- "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n");
+ "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n"
+ );
}
+
TEST_F(ValidationErrorTest, IllegalPackedField) {
BuildFileWithErrors(
"name: \"foo.proto\" "
@@ -3178,20 +4193,85 @@ TEST_F(ValidationErrorTest, InvalidOptionName) {
"reserved name \"uninterpreted_option\".\n");
}
-TEST_F(ValidationErrorTest, RepeatedOption) {
+TEST_F(ValidationErrorTest, RepeatedMessageOption) {
BuildDescriptorMessagesInTestPool();
BuildFileWithErrors(
"name: \"foo.proto\" "
"dependency: \"google/protobuf/descriptor.proto\" "
- "extension { name: \"foo\" number: 7672757 label: LABEL_REPEATED "
- " type: TYPE_FLOAT extendee: \"google.protobuf.FileOptions\" }"
- "options { uninterpreted_option { name { name_part: \"foo\" "
+ "message_type: { name: \"Bar\" field: { "
+ " name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } "
+ "} "
+ "extension { name: \"bar\" number: 7672757 label: LABEL_REPEATED "
+ " type: TYPE_MESSAGE type_name: \"Bar\" "
+ " extendee: \"google.protobuf.FileOptions\" }"
+ "options { uninterpreted_option { name { name_part: \"bar\" "
+ " is_extension: true } "
+ " name { name_part: \"foo\" "
+ " is_extension: false } "
+ " positive_int_value: 1 } }",
+
+ "foo.proto: foo.proto: OPTION_NAME: Option field \"(bar)\" is a "
+ "repeated message. Repeated message options must be initialized "
+ "using an aggregate value.\n");
+}
+
+TEST_F(ValidationErrorTest, ResolveUndefinedOption) {
+ // The following should produce an eror that baz.bar is resolved but not
+ // defined.
+ // foo.proto:
+ // package baz
+ // import google/protobuf/descriptor.proto
+ // message Bar { optional int32 foo = 1; }
+ // extend FileOptions { optional Bar bar = 7672757; }
+ //
+ // qux.proto:
+ // package qux.baz
+ // option (baz.bar).foo = 1;
+ //
+ // Although "baz.bar" is already defined, the lookup code will try
+ // "qux.baz.bar", since it's the match from the innermost scope, which will
+ // cause a symbol not defined error.
+ BuildDescriptorMessagesInTestPool();
+
+ BuildFile(
+ "name: \"foo.proto\" "
+ "package: \"baz\" "
+ "dependency: \"google/protobuf/descriptor.proto\" "
+ "message_type: { name: \"Bar\" field: { "
+ " name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } "
+ "} "
+ "extension { name: \"bar\" number: 7672757 label: LABEL_OPTIONAL "
+ " type: TYPE_MESSAGE type_name: \"Bar\" "
+ " extendee: \"google.protobuf.FileOptions\" }");
+
+ BuildFileWithErrors(
+ "name: \"qux.proto\" "
+ "package: \"qux.baz\" "
+ "options { uninterpreted_option { name { name_part: \"baz.bar\" "
" is_extension: true } "
- " double_value: 1.2 } }",
+ " name { name_part: \"foo\" "
+ " is_extension: false } "
+ " positive_int_value: 1 } }",
- "foo.proto: foo.proto: OPTION_NAME: Option field \"(foo)\" is repeated. "
- "Repeated options are not supported.\n");
+ "qux.proto: qux.proto: OPTION_NAME: Option \"(baz.bar)\" is resolved to "
+ "\"(qux.baz.bar)\","
+ " which is not defined. The innermost scope is searched first in name "
+ "resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\") to start "
+ "from the outermost scope.\n");
+}
+
+TEST_F(ValidationErrorTest, UnknownOption) {
+ BuildFileWithErrors(
+ "name: \"qux.proto\" "
+ "package: \"qux.baz\" "
+ "options { uninterpreted_option { name { name_part: \"baaz.bar\" "
+ " is_extension: true } "
+ " name { name_part: \"foo\" "
+ " is_extension: false } "
+ " positive_int_value: 1 } }",
+
+ "qux.proto: qux.proto: OPTION_NAME: Option \"(baaz.bar)\" unknown.\n");
}
TEST_F(ValidationErrorTest, CustomOptionConflictingFieldNumber) {
@@ -3464,6 +4544,25 @@ TEST_F(ValidationErrorTest, StringOptionValueIsNotString) {
"string option \"foo\".\n");
}
+TEST_F(ValidationErrorTest, DuplicateExtensionFieldNumber) {
+ BuildDescriptorMessagesInTestPool();
+
+ BuildFile(
+ "name: \"foo.proto\" "
+ "dependency: \"google/protobuf/descriptor.proto\" "
+ "extension { name: \"option1\" number: 1000 label: LABEL_OPTIONAL "
+ " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }");
+
+ BuildFileWithWarnings(
+ "name: \"bar.proto\" "
+ "dependency: \"google/protobuf/descriptor.proto\" "
+ "extension { name: \"option2\" number: 1000 label: LABEL_OPTIONAL "
+ " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }",
+ "bar.proto: option2: NUMBER: Extension number 1000 has already been used "
+ "in \"google.protobuf.FileOptions\" by extension \"option1\" defined in "
+ "foo.proto.\n");
+}
+
// Helper function for tests that check for aggregate value parsing
// errors. The "value" argument is embedded inside the
// "uninterpreted_option" portion of the result.
@@ -3592,7 +4691,8 @@ TEST_F(ValidationErrorTest, RollbackAfterError) {
" }"
"}",
- "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n");
+ "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n"
+ );
// Make sure that if we build the same file again with the error fixed,
// it works. If the above rollback was incomplete, then some symbols will
@@ -3641,6 +4741,625 @@ TEST_F(ValidationErrorTest, ErrorsReportedToLogError) {
EXPECT_EQ(" Foo: \"Foo\" is already defined.", errors[1]);
}
+TEST_F(ValidationErrorTest, DisallowEnumAlias) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "enum_type {"
+ " name: \"Bar\""
+ " value { name:\"ENUM_A\" number:0 }"
+ " value { name:\"ENUM_B\" number:0 }"
+ "}",
+ "foo.proto: Bar: NUMBER: "
+ "\"ENUM_B\" uses the same enum value as \"ENUM_A\". "
+ "If this is intended, set 'option allow_alias = true;' to the enum "
+ "definition.\n");
+}
+
+TEST_F(ValidationErrorTest, AllowEnumAlias) {
+ BuildFile(
+ "name: \"foo.proto\" "
+ "enum_type {"
+ " name: \"Bar\""
+ " value { name:\"ENUM_A\" number:0 }"
+ " value { name:\"ENUM_B\" number:0 }"
+ " options { allow_alias: true }"
+ "}");
+}
+
+TEST_F(ValidationErrorTest, UnusedImportWarning) {
+
+ pool_.AddUnusedImportTrackFile("bar.proto");
+ BuildFile(
+ "name: \"bar.proto\" "
+ "message_type { name: \"Bar\" }");
+
+ pool_.AddUnusedImportTrackFile("base.proto");
+ BuildFile(
+ "name: \"base.proto\" "
+ "message_type { name: \"Base\" }");
+
+ pool_.AddUnusedImportTrackFile("baz.proto");
+ BuildFile(
+ "name: \"baz.proto\" "
+ "message_type { name: \"Baz\" }");
+
+ pool_.AddUnusedImportTrackFile("public.proto");
+ BuildFile(
+ "name: \"public.proto\" "
+ "dependency: \"bar.proto\""
+ "public_dependency: 0");
+
+ // // forward.proto
+ // import "base.proto" // No warning: Base message is used.
+ // import "bar.proto" // Will log a warning.
+ // import public "baz.proto" // No warning: Do not track import public.
+ // import "public.proto" // No warning: public.proto has import public.
+ // message Forward {
+ // optional Base base = 1;
+ // }
+ //
+ pool_.AddUnusedImportTrackFile("forward.proto");
+ BuildFile(
+ "name: \"forward.proto\""
+ "dependency: \"base.proto\""
+ "dependency: \"bar.proto\""
+ "dependency: \"baz.proto\""
+ "dependency: \"public.proto\""
+ "public_dependency: 2 "
+ "message_type {"
+ " name: \"Forward\""
+ " field { name:\"base\" number:1 label:LABEL_OPTIONAL type_name:\"Base\" }"
+ "}");
+}
+
+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<KeyType, ValueType> 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
@@ -3659,16 +5378,23 @@ class DatabaseBackedPoolTest : public testing::Test {
virtual void SetUp() {
AddToDatabase(&database_,
- "name: \"foo.proto\" "
- "message_type { name:\"Foo\" extension_range { start: 1 end: 100 } } "
- "enum_type { name:\"TestEnum\" value { name:\"DUMMY\" number:0 } } "
- "service { name:\"TestService\" } ");
+ "name: 'foo.proto' "
+ "message_type { name:'Foo' extension_range { start: 1 end: 100 } } "
+ "enum_type { name:'TestEnum' value { name:'DUMMY' number:0 } } "
+ "service { name:'TestService' } ");
AddToDatabase(&database_,
- "name: \"bar.proto\" "
- "dependency: \"foo.proto\" "
- "message_type { name:\"Bar\" } "
- "extension { name:\"foo_ext\" extendee: \".Foo\" number:5 "
+ "name: 'bar.proto' "
+ "dependency: 'foo.proto' "
+ "message_type { name:'Bar' } "
+ "extension { name:'foo_ext' extendee: '.Foo' number:5 "
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
+ // Baz has an undeclared dependency on Foo.
+ AddToDatabase(&database_,
+ "name: 'baz.proto' "
+ "message_type { "
+ " name:'Baz' "
+ " field { name:'foo' number:1 label:LABEL_OPTIONAL type_name:'Foo' } "
+ "}");
}
// We can't inject a file containing errors into a DescriptorPool, so we
@@ -3907,6 +5633,33 @@ TEST_F(DatabaseBackedPoolTest, ErrorWithErrorCollector) {
error_collector.text_);
}
+TEST_F(DatabaseBackedPoolTest, UndeclaredDependencyOnUnbuiltType) {
+ // Check that we find and report undeclared dependencies on types that exist
+ // in the descriptor database but that have not not been built yet.
+ MockErrorCollector error_collector;
+ DescriptorPool pool(&database_, &error_collector);
+ EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL);
+ EXPECT_EQ(
+ "baz.proto: Baz.foo: TYPE: \"Foo\" seems to be defined in \"foo.proto\", "
+ "which is not imported by \"baz.proto\". To use it here, please add "
+ "the necessary import.\n",
+ error_collector.text_);
+}
+
+TEST_F(DatabaseBackedPoolTest, RollbackAfterError) {
+ // Make sure that all traces of bad types are removed from the pool. This used
+ // to be b/4529436, due to the fact that a symbol resolution failure could
+ // potentially cause another file to be recursively built, which would trigger
+ // a checkpoint _past_ possibly invalid symbols.
+ // Baz is defined in the database, but the file is invalid because it is
+ // missing a necessary import.
+ DescriptorPool pool(&database_);
+ EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL);
+ // Make sure that searching again for the file or the type fails.
+ EXPECT_TRUE(pool.FindFileByName("baz.proto") == NULL);
+ EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL);
+}
+
TEST_F(DatabaseBackedPoolTest, UnittestProto) {
// Try to load all of unittest.proto from a DescriptorDatabase. This should
// thoroughly test all paths through DescriptorBuilder to insure that there
@@ -3929,6 +5682,10 @@ TEST_F(DatabaseBackedPoolTest, UnittestProto) {
EXPECT_EQ(original_file_proto.DebugString(),
file_from_database_proto.DebugString());
+
+ // Also verify that CopyTo() did not omit any information.
+ EXPECT_EQ(original_file->DebugString(),
+ file_from_database->DebugString());
}
TEST_F(DatabaseBackedPoolTest, DoesntRetryDbUnnecessarily) {
@@ -3963,6 +5720,16 @@ TEST_F(DatabaseBackedPoolTest, DoesntRetryDbUnnecessarily) {
EXPECT_TRUE(file->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
EXPECT_TRUE(file->FindServiceByName("NO_SUCH_VALUE") == NULL);
EXPECT_TRUE(file->FindExtensionByName("no_such_extension") == NULL);
+
+ EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no.such.field") == NULL);
+ EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no_such_field") == NULL);
+ EXPECT_TRUE(pool.FindMessageTypeByName("Foo.NoSuchMessageType") == NULL);
+ EXPECT_TRUE(pool.FindFieldByName("Foo.no_such_field") == NULL);
+ EXPECT_TRUE(pool.FindExtensionByName("Foo.no_such_extension") == NULL);
+ EXPECT_TRUE(pool.FindEnumTypeByName("Foo.NoSuchEnumType") == NULL);
+ EXPECT_TRUE(pool.FindEnumValueByName("Foo.NO_SUCH_VALUE") == NULL);
+ EXPECT_TRUE(pool.FindMethodByName("TestService.NoSuchMethod") == NULL);
+
EXPECT_EQ(0, call_counter.call_count_);
}
@@ -3987,15 +5754,93 @@ TEST_F(DatabaseBackedPoolTest, DoesntReloadFilesUncesessarily) {
EXPECT_EQ("", error_collector.text_);
}
+// DescriptorDatabase that attempts to induce exponentially-bad performance
+// in DescriptorPool. For every positive N, the database contains a file
+// fileN.proto, which defines a message MessageN, which contains fields of
+// type MessageK for all K in [0,N). Message0 is not defined anywhere
+// (file0.proto exists, but is empty), so every other file and message type
+// will fail to build.
+//
+// If the DescriptorPool is not careful to memoize errors, an attempt to
+// build a descriptor for MessageN can require O(2^N) time.
+class ExponentialErrorDatabase : public DescriptorDatabase {
+ public:
+ ExponentialErrorDatabase() {}
+ ~ExponentialErrorDatabase() {}
+
+ // implements DescriptorDatabase ---------------------------------
+ bool FindFileByName(const string& filename,
+ FileDescriptorProto* output) {
+ int file_num = -1;
+ FullMatch(filename, "file", ".proto", &file_num);
+ if (file_num > -1) {
+ return PopulateFile(file_num, output);
+ } else {
+ return false;
+ }
+ }
+ bool FindFileContainingSymbol(const string& symbol_name,
+ FileDescriptorProto* output) {
+ int file_num = -1;
+ FullMatch(symbol_name, "Message", "", &file_num);
+ if (file_num > 0) {
+ return PopulateFile(file_num, output);
+ } else {
+ return false;
+ }
+ }
+ bool FindFileContainingExtension(const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output) {
+ return false;
+ }
+
+ private:
+ void FullMatch(const string& name,
+ const string& begin_with,
+ const string& end_with,
+ int* file_num) {
+ int begin_size = begin_with.size();
+ int end_size = end_with.size();
+ if (name.substr(0, begin_size) != begin_with ||
+ name.substr(name.size()- end_size, end_size) != end_with) {
+ return;
+ }
+ safe_strto32(name.substr(begin_size, name.size() - end_size - begin_size),
+ file_num);
+ }
+
+ bool PopulateFile(int file_num, FileDescriptorProto* output) {
+ using strings::Substitute;
+ GOOGLE_CHECK_GE(file_num, 0);
+ output->Clear();
+ output->set_name(Substitute("file$0.proto", file_num));
+ // file0.proto doesn't define Message0
+ if (file_num > 0) {
+ DescriptorProto* message = output->add_message_type();
+ message->set_name(Substitute("Message$0", file_num));
+ for (int i = 0; i < file_num; ++i) {
+ output->add_dependency(Substitute("file$0.proto", i));
+ FieldDescriptorProto* field = message->add_field();
+ field->set_name(Substitute("field$0", i));
+ field->set_number(i);
+ field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+ field->set_type(FieldDescriptorProto::TYPE_MESSAGE);
+ field->set_type_name(Substitute("Message$0", i));
+ }
+ }
+ return true;
+ }
+};
+
TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) {
- ErrorDescriptorDatabase error_database;
- MockErrorCollector error_collector;
- DescriptorPool pool(&error_database, &error_collector);
+ ExponentialErrorDatabase error_database;
+ DescriptorPool pool(&error_database);
- EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
- error_collector.text_.clear();
- EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
- EXPECT_EQ("", error_collector.text_);
+ GOOGLE_LOG(INFO) << "A timeout in this test probably indicates a real bug.";
+
+ EXPECT_TRUE(pool.FindFileByName("file40.proto") == NULL);
+ EXPECT_TRUE(pool.FindMessageTypeByName("Message40") == NULL);
}
TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) {
@@ -4028,6 +5873,251 @@ TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) {
// ===================================================================
+class AbortingErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+ AbortingErrorCollector() {}
+
+ virtual void AddError(
+ const string &filename,
+ const string &element_name,
+ const Message *message,
+ ErrorLocation location,
+ const string &error_message) {
+ GOOGLE_LOG(FATAL) << "AddError() called unexpectedly: " << filename << " ["
+ << element_name << "]: " << error_message;
+ }
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AbortingErrorCollector);
+};
+
+// A source tree containing only one file.
+class SingletonSourceTree : public compiler::SourceTree {
+ public:
+ SingletonSourceTree(const string& filename, const string& contents)
+ : filename_(filename), contents_(contents) {}
+
+ virtual io::ZeroCopyInputStream* Open(const string& filename) {
+ return filename == filename_ ?
+ new io::ArrayInputStream(contents_.data(), contents_.size()) : NULL;
+ }
+
+ private:
+ const string filename_;
+ const string contents_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SingletonSourceTree);
+};
+
+const char *const kSourceLocationTestInput =
+ "syntax = \"proto2\";\n"
+ "message A {\n"
+ " optional int32 a = 1;\n"
+ " message B {\n"
+ " required double b = 1;\n"
+ " }\n"
+ "}\n"
+ "enum Indecision {\n"
+ " YES = 1;\n"
+ " NO = 2;\n"
+ " MAYBE = 3;\n"
+ "}\n"
+ "service S {\n"
+ " rpc Method(A) returns (A.B);\n"
+ // Put an empty line here to make the source location range match.
+ "\n"
+ "}\n"
+ "message MessageWithExtensions {\n"
+ " extensions 1000 to max;\n"
+ "}\n"
+ "extend MessageWithExtensions {\n"
+ " optional int32 int32_extension = 1001;\n"
+ "}\n"
+ "message C {\n"
+ " extend MessageWithExtensions {\n"
+ " optional C message_extension = 1002;\n"
+ " }\n"
+ "}\n";
+
+class SourceLocationTest : public testing::Test {
+ public:
+ SourceLocationTest()
+ : source_tree_("/test/test.proto", kSourceLocationTestInput),
+ db_(&source_tree_),
+ pool_(&db_, &collector_) {}
+
+ static string PrintSourceLocation(const SourceLocation &loc) {
+ return strings::Substitute("$0:$1-$2:$3",
+ 1 + loc.start_line,
+ 1 + loc.start_column,
+ 1 + loc.end_line,
+ 1 + loc.end_column);
+ }
+
+ private:
+ AbortingErrorCollector collector_;
+ SingletonSourceTree source_tree_;
+ compiler::SourceTreeDescriptorDatabase db_;
+
+ protected:
+ DescriptorPool pool_;
+};
+
+// TODO(adonovan): implement support for option fields and for
+// subparts of declarations.
+
+TEST_F(SourceLocationTest, GetSourceLocation) {
+ SourceLocation loc;
+
+ const FileDescriptor *file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+ const Descriptor *a_desc = file_desc->FindMessageTypeByName("A");
+ EXPECT_TRUE(a_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("2:1-7:2", PrintSourceLocation(loc));
+
+ const Descriptor *a_b_desc = a_desc->FindNestedTypeByName("B");
+ EXPECT_TRUE(a_b_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("4:3-6:4", PrintSourceLocation(loc));
+
+ const EnumDescriptor *e_desc = file_desc->FindEnumTypeByName("Indecision");
+ EXPECT_TRUE(e_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("8:1-12:2", PrintSourceLocation(loc));
+
+ const EnumValueDescriptor *yes_desc = e_desc->FindValueByName("YES");
+ EXPECT_TRUE(yes_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("9:3-9:13", PrintSourceLocation(loc));
+
+ const ServiceDescriptor *s_desc = file_desc->FindServiceByName("S");
+ EXPECT_TRUE(s_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("13:1-16:2", PrintSourceLocation(loc));
+
+ const MethodDescriptor *m_desc = s_desc->FindMethodByName("Method");
+ EXPECT_TRUE(m_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("14:3-14:31", PrintSourceLocation(loc));
+
+}
+
+TEST_F(SourceLocationTest, ExtensionSourceLocation) {
+ SourceLocation loc;
+
+ const FileDescriptor *file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+ const FieldDescriptor *int32_extension_desc =
+ file_desc->FindExtensionByName("int32_extension");
+ EXPECT_TRUE(int32_extension_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("21:3-21:41", PrintSourceLocation(loc));
+
+ const Descriptor *c_desc = file_desc->FindMessageTypeByName("C");
+ EXPECT_TRUE(c_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("23:1-27:2", PrintSourceLocation(loc));
+
+ const FieldDescriptor *message_extension_desc =
+ c_desc->FindExtensionByName("message_extension");
+ EXPECT_TRUE(message_extension_desc->GetSourceLocation(&loc));
+ EXPECT_EQ("25:5-25:41", PrintSourceLocation(loc));
+}
+
+// Missing SourceCodeInfo doesn't cause crash:
+TEST_F(SourceLocationTest, GetSourceLocation_MissingSourceCodeInfo) {
+ SourceLocation loc;
+
+ const FileDescriptor *file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+ FileDescriptorProto proto;
+ file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo.
+ EXPECT_FALSE(proto.has_source_code_info());
+
+ DescriptorPool bad1_pool(&pool_);
+ const FileDescriptor* bad1_file_desc =
+ GOOGLE_CHECK_NOTNULL(bad1_pool.BuildFile(proto));
+ const Descriptor *bad1_a_desc = bad1_file_desc->FindMessageTypeByName("A");
+ EXPECT_FALSE(bad1_a_desc->GetSourceLocation(&loc));
+}
+
+// Corrupt SourceCodeInfo doesn't cause crash:
+TEST_F(SourceLocationTest, GetSourceLocation_BogusSourceCodeInfo) {
+ SourceLocation loc;
+
+ const FileDescriptor *file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+ FileDescriptorProto proto;
+ file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo.
+ EXPECT_FALSE(proto.has_source_code_info());
+ SourceCodeInfo_Location *loc_msg =
+ proto.mutable_source_code_info()->add_location();
+ loc_msg->add_path(1);
+ loc_msg->add_path(2);
+ loc_msg->add_path(3);
+ loc_msg->add_span(4);
+ loc_msg->add_span(5);
+ loc_msg->add_span(6);
+
+ DescriptorPool bad2_pool(&pool_);
+ const FileDescriptor* bad2_file_desc =
+ GOOGLE_CHECK_NOTNULL(bad2_pool.BuildFile(proto));
+ const Descriptor *bad2_a_desc = bad2_file_desc->FindMessageTypeByName("A");
+ EXPECT_FALSE(bad2_a_desc->GetSourceLocation(&loc));
+}
+
+// ===================================================================
+
+const char* const kCopySourceCodeInfoToTestInput =
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n";
+
+// Required since source code information is not preserved by
+// FileDescriptorTest.
+class CopySourceCodeInfoToTest : public testing::Test {
+ public:
+ CopySourceCodeInfoToTest()
+ : source_tree_("/test/test.proto", kCopySourceCodeInfoToTestInput),
+ db_(&source_tree_),
+ pool_(&db_, &collector_) {}
+
+ private:
+ AbortingErrorCollector collector_;
+ SingletonSourceTree source_tree_;
+ compiler::SourceTreeDescriptorDatabase db_;
+
+ protected:
+ DescriptorPool pool_;
+};
+
+TEST_F(CopySourceCodeInfoToTest, CopyTo_DoesNotCopySourceCodeInfo) {
+ const FileDescriptor* file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+ FileDescriptorProto file_desc_proto;
+ ASSERT_FALSE(file_desc_proto.has_source_code_info());
+
+ file_desc->CopyTo(&file_desc_proto);
+ EXPECT_FALSE(file_desc_proto.has_source_code_info());
+}
+
+TEST_F(CopySourceCodeInfoToTest, CopySourceCodeInfoTo) {
+ const FileDescriptor* file_desc =
+ GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+ FileDescriptorProto file_desc_proto;
+ ASSERT_FALSE(file_desc_proto.has_source_code_info());
+
+ file_desc->CopySourceCodeInfoTo(&file_desc_proto);
+ const SourceCodeInfo& info = file_desc_proto.source_code_info();
+ ASSERT_EQ(4, info.location_size());
+ // Get the Foo message location
+ const SourceCodeInfo_Location& foo_location = info.location(2);
+ ASSERT_EQ(2, foo_location.path_size());
+ EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0));
+ EXPECT_EQ(0, foo_location.path(1)); // Foo is the first message defined
+ ASSERT_EQ(3, foo_location.span_size()); // Foo spans one line
+ EXPECT_EQ(1, foo_location.span(0)); // Foo is declared on line 1
+ EXPECT_EQ(0, foo_location.span(1)); // Foo starts at column 0
+ EXPECT_EQ(14, foo_location.span(2)); // Foo ends on column 14
+}
+
+// ===================================================================
+
} // namespace descriptor_unittest
} // namespace protobuf
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..6f16dc53
--- /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 <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/unittest_drop_unknown_fields.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <gtest/gtest.h>
+
+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<int>(FooWithExtraFields::QUX),
+ static_cast<int>(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;
+ google::protobuf::scoped_ptr<google::protobuf::Message> 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/duration.proto b/src/google/protobuf/duration.proto
new file mode 100644
index 00000000..868c732f
--- /dev/null
+++ b/src/google/protobuf/duration.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 google.protobuf;
+
+option java_generate_equals_and_hash = true;
+option java_multiple_files = true;
+option java_outer_classname = "DurationProto";
+option java_package = "com.google.protobuf";
+
+
+// A Duration represents a signed, fixed-length span of time represented
+// as a count of seconds and fractions of seconds at nanosecond
+// resolution. It is independent of any calendar and concepts like "day"
+// or "month". It is related to Timestamp in that the difference between
+// two Timestamp values is a Duration and it can be added or subtracted
+// from a Timestamp. Range is approximately +-10,000 years.
+//
+// Example 1: compute Duration from two Timestamps in pseudo code.
+//
+// Timestamp start = ...;
+// Timestamp end = ...;
+// Duration duration = ...;
+//
+// duration.seconds = end.seconds - start.seconds;
+// duration.nanos = end.nanos - start.nanos;
+//
+// if (duration.seconds < 0 && duration.nanos > 0) {
+// duration.seconds += 1;
+// duration.nanos -= 1000000000;
+// } else if (durations.seconds > 0 && duration.nanos < 0) {
+// duration.seconds -= 1;
+// duration.nanos += 1000000000;
+// }
+//
+// Example 2: compute Timestamp from Timestamp + Duration in pseudo code.
+//
+// Timestamp start = ...;
+// Duration duration = ...;
+// Timestamp end = ...;
+//
+// end.seconds = start.seconds + duration.seconds;
+// end.nanos = start.nanos + duration.nanos;
+//
+// if (end.nanos < 0) {
+// end.seconds -= 1;
+// end.nanos += 1000000000;
+// } else if (end.nanos >= 1000000000) {
+// end.seconds += 1;
+// end.nanos -= 1000000000;
+// }
+//
+message Duration {
+ // Signed seconds of the span of time. Must be from -315,576,000,000
+ // to +315,576,000,000 inclusive.
+ int64 seconds = 1;
+
+ // Signed fractions of a second at nanosecond resolution of the span
+ // of time. Durations less than one second are represented with a 0
+ // seconds field and a positive or negative nanos field. For durations
+ // of one second or more, a non-zero value for the nanos field must be
+ // of the same sign as the seconds field. Must be from -999,999,999
+ // to +999,999,999 inclusive.
+ int32 nanos = 2;
+}
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index c711a2da..318ce6f9 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -72,8 +72,11 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/map_field_inl.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/map_type_handler.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/wire_format.h>
@@ -83,13 +86,21 @@ namespace protobuf {
using internal::WireFormat;
using internal::ExtensionSet;
using internal::GeneratedMessageReflection;
+using internal::MapField;
+using internal::MapFieldBase;
+using internal::ArenaStringPtr;
+
// ===================================================================
// Some helper tables and functions...
namespace {
+bool IsMapFieldInApi(const FieldDescriptor* field) {
+ return field->is_map();
+}
+
// Compute the byte size of the in-memory representation of the field.
int FieldSpaceUsed(const FieldDescriptor* field) {
typedef FieldDescriptor FD; // avoid line wrapping
@@ -103,7 +114,12 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
case FD::CPPTYPE_FLOAT : return sizeof(RepeatedField<float >);
case FD::CPPTYPE_BOOL : return sizeof(RepeatedField<bool >);
case FD::CPPTYPE_ENUM : return sizeof(RepeatedField<int >);
- case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField<Message>);
+ case FD::CPPTYPE_MESSAGE:
+ if (IsMapFieldInApi(field)) {
+ return sizeof(MapFieldBase);
+ } else {
+ return sizeof(RepeatedPtrField<Message>);
+ }
case FD::CPPTYPE_STRING:
switch (field->options().ctype()) {
@@ -123,13 +139,15 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
case FD::CPPTYPE_FLOAT : return sizeof(float );
case FD::CPPTYPE_BOOL : return sizeof(bool );
case FD::CPPTYPE_ENUM : return sizeof(int );
- case FD::CPPTYPE_MESSAGE: return sizeof(Message*);
+
+ case FD::CPPTYPE_MESSAGE:
+ return sizeof(Message*);
case FD::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING:
- return sizeof(string*);
+ return sizeof(ArenaStringPtr);
}
break;
}
@@ -139,11 +157,42 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
return 0;
}
+// Compute the byte size of in-memory representation of the oneof fields
+// in default oneof instance.
+int OneofFieldSpaceUsed(const FieldDescriptor* field) {
+ typedef FieldDescriptor FD; // avoid line wrapping
+ switch (field->cpp_type()) {
+ case FD::CPPTYPE_INT32 : return sizeof(int32 );
+ case FD::CPPTYPE_INT64 : return sizeof(int64 );
+ case FD::CPPTYPE_UINT32 : return sizeof(uint32 );
+ case FD::CPPTYPE_UINT64 : return sizeof(uint64 );
+ case FD::CPPTYPE_DOUBLE : return sizeof(double );
+ case FD::CPPTYPE_FLOAT : return sizeof(float );
+ case FD::CPPTYPE_BOOL : return sizeof(bool );
+ case FD::CPPTYPE_ENUM : return sizeof(int );
+
+ case FD::CPPTYPE_MESSAGE:
+ return sizeof(Message*);
+
+ case FD::CPPTYPE_STRING:
+ switch (field->options().ctype()) {
+ default:
+ case FieldOptions::STRING:
+ return sizeof(ArenaStringPtr);
+ }
+ break;
+ }
+
+ GOOGLE_LOG(DFATAL) << "Can't get here.";
+ return 0;
+}
+
inline int DivideRoundingUp(int i, int j) {
return (i + (j - 1)) / j;
}
static const int kSafeAlignment = sizeof(uint64);
+static const int kMaxOneofUnionSize = sizeof(uint64);
inline int AlignTo(int offset, int alignment) {
return DivideRoundingUp(offset, alignment) * alignment;
@@ -166,8 +215,10 @@ class DynamicMessage : public Message {
struct TypeInfo {
int size;
int has_bits_offset;
+ int oneof_case_offset;
int unknown_fields_offset;
int extensions_offset;
+ int is_default_instance_offset;
// Not owned by the TypeInfo.
DynamicMessageFactory* factory; // The factory that created this object.
@@ -178,7 +229,19 @@ class DynamicMessage : public Message {
// important (the prototype must be deleted *before* the offsets).
scoped_array<int> offsets;
scoped_ptr<const GeneratedMessageReflection> reflection;
- scoped_ptr<const DynamicMessage> prototype;
+ // Don't use a scoped_ptr to hold the prototype: the destructor for
+ // DynamicMessage needs to know whether it is the prototype, and does so by
+ // looking back at this field. This would assume details about the
+ // implementation of scoped_ptr.
+ const DynamicMessage* prototype;
+ void* default_oneof_instance;
+
+ TypeInfo() : prototype(NULL), default_oneof_instance(NULL) {}
+
+ ~TypeInfo() {
+ delete prototype;
+ operator delete(default_oneof_instance);
+ }
};
DynamicMessage(const TypeInfo* type_info);
@@ -190,14 +253,19 @@ 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;
Metadata GetMetadata() const;
+
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 ||
@@ -214,7 +282,6 @@ class DynamicMessage : public Message {
}
const TypeInfo* type_info_;
-
// TODO(kenton): Make this an atomic<int> when C++ supports it.
mutable int cached_byte_size_;
};
@@ -222,6 +289,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
@@ -233,6 +311,17 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info)
const Descriptor* descriptor = type_info_->type;
+ // Initialize oneof cases.
+ for (int i = 0 ; i < descriptor->oneof_decl_count(); ++i) {
+ new(OffsetToPointer(type_info_->oneof_case_offset + sizeof(uint32) * i))
+ uint32(0);
+ }
+
+ if (type_info_->is_default_instance_offset != -1) {
+ *reinterpret_cast<bool*>(
+ OffsetToPointer(type_info_->is_default_instance_offset)) = false;
+ }
+
new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet;
if (type_info_->extensions_offset != -1) {
@@ -242,6 +331,9 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info)
for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
+ if (field->containing_oneof()) {
+ continue;
+ }
switch (field->cpp_type()) {
#define HANDLE_TYPE(CPPTYPE, TYPE) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
@@ -274,15 +366,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<string* const*>(
+ default_value =
+ &(reinterpret_cast<const ArenaStringPtr*>(
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<string>();
}
@@ -294,7 +388,11 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info)
if (!field->is_repeated()) {
new(field_ptr) Message*(NULL);
} else {
- new(field_ptr) RepeatedPtrField<Message>();
+ if (IsMapFieldInApi(field)) {
+ new (field_ptr) MapFieldBase();
+ } else {
+ new (field_ptr) RepeatedPtrField<Message>();
+ }
}
break;
}
@@ -315,12 +413,41 @@ DynamicMessage::~DynamicMessage() {
// We need to manually run the destructors for repeated fields and strings,
// just as we ran their constructors in the the DynamicMessage constructor.
+ // We also need to manually delete oneof fields if it is set and is string
+ // or message.
// Additionally, if any singular embedded messages have been allocated, we
// need to delete them, UNLESS we are the prototype message of this type,
// in which case any embedded messages are other prototypes and shouldn't
// be touched.
for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
+ if (field->containing_oneof()) {
+ void* field_ptr = OffsetToPointer(
+ type_info_->oneof_case_offset
+ + sizeof(uint32) * field->containing_oneof()->index());
+ if (*(reinterpret_cast<const uint32*>(field_ptr)) ==
+ field->number()) {
+ field_ptr = OffsetToPointer(type_info_->offsets[
+ descriptor->field_count() + field->containing_oneof()->index()]);
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+ switch (field->options().ctype()) {
+ default:
+ case FieldOptions::STRING: {
+ const ::std::string* default_value =
+ &(reinterpret_cast<const ArenaStringPtr*>(
+ type_info_->prototype->OffsetToPointer(
+ type_info_->offsets[i]))->Get(NULL));
+ reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(default_value,
+ NULL);
+ break;
+ }
+ }
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ delete *reinterpret_cast<Message**>(field_ptr);
+ }
+ }
+ continue;
+ }
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
if (field->is_repeated()) {
@@ -352,8 +479,12 @@ DynamicMessage::~DynamicMessage() {
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
- reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
- ->~RepeatedPtrField<Message>();
+ if (IsMapFieldInApi(field)) {
+ reinterpret_cast<MapFieldBase*>(field_ptr)->~MapFieldBase();
+ } else {
+ reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
+ ->~RepeatedPtrField<Message>();
+ }
break;
}
@@ -361,18 +492,21 @@ DynamicMessage::~DynamicMessage() {
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING: {
- string* ptr = *reinterpret_cast<string**>(field_ptr);
- if (ptr != &field->default_value_string()) {
- delete ptr;
- }
+ const ::std::string* default_value =
+ &(reinterpret_cast<const ArenaStringPtr*>(
+ type_info_->prototype->OffsetToPointer(
+ type_info_->offsets[i]))->Get(NULL));
+ reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(default_value,
+ NULL);
break;
}
}
- } else if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) &&
- !is_prototype()) {
- Message* message = *reinterpret_cast<Message**>(field_ptr);
- if (message != NULL) {
- delete message;
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (!is_prototype()) {
+ Message* message = *reinterpret_cast<Message**>(field_ptr);
+ if (message != NULL) {
+ delete message;
+ }
}
}
}
@@ -389,6 +523,10 @@ void DynamicMessage::CrossLinkPrototypes() {
for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
+ if (field->containing_oneof()) {
+ field_ptr = reinterpret_cast<uint8*>(
+ type_info_->default_oneof_instance) + type_info_->offsets[i];
+ }
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!field->is_repeated()) {
@@ -400,14 +538,32 @@ void DynamicMessage::CrossLinkPrototypes() {
factory->GetPrototypeNoLock(field->message_type());
}
}
+
+ // Set as the default instance -- this affects field-presence semantics for
+ // proto3.
+ if (type_info_->is_default_instance_offset != -1) {
+ void* is_default_instance_ptr =
+ OffsetToPointer(type_info_->is_default_instance_offset);
+ *reinterpret_cast<bool*>(is_default_instance_ptr) = true;
+ }
}
Message* DynamicMessage::New() const {
- void* new_base = reinterpret_cast<uint8*>(operator new(type_info_->size));
+ void* new_base = operator new(type_info_->size);
memset(new_base, 0, type_info_->size);
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_;
}
@@ -416,7 +572,9 @@ void DynamicMessage::SetCachedSize(int size) const {
// This is theoretically not thread-compatible, but in practice it works
// because if multiple threads write this simultaneously, they will be
// writing the exact same value.
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
cached_byte_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
Metadata DynamicMessage::GetMetadata() const {
@@ -446,6 +604,9 @@ DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool)
DynamicMessageFactory::~DynamicMessageFactory() {
for (PrototypeMap::Map::iterator iter = prototypes_->map_.begin();
iter != prototypes_->map_.end(); ++iter) {
+ DeleteDefaultOneofInstance(iter->second->type,
+ iter->second->offsets.get(),
+ iter->second->default_oneof_instance);
delete iter->second;
}
}
@@ -465,7 +626,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
const DynamicMessage::TypeInfo** target = &prototypes_->map_[type];
if (*target != NULL) {
// Already exists.
- return (*target)->prototype.get();
+ return (*target)->prototype;
}
DynamicMessage::TypeInfo* type_info = new DynamicMessage::TypeInfo;
@@ -484,7 +645,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
// or not that field is set.
// Compute size and offsets.
- int* offsets = new int[type->field_count()];
+ int* offsets = new int[type->field_count() + type->oneof_decl_count()];
type_info->offsets.reset(offsets);
// Decide all field offsets by packing in order.
@@ -494,11 +655,31 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
size = AlignOffset(size);
// Next the has_bits, which is an array of uint32s.
- type_info->has_bits_offset = size;
- int has_bits_array_size =
- DivideRoundingUp(type->field_count(), bitsizeof(uint32));
- size += has_bits_array_size * sizeof(uint32);
- size = AlignOffset(size);
+ if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+ type_info->has_bits_offset = -1;
+ } else {
+ type_info->has_bits_offset = size;
+ int has_bits_array_size =
+ DivideRoundingUp(type->field_count(), bitsizeof(uint32));
+ size += has_bits_array_size * sizeof(uint32);
+ size = AlignOffset(size);
+ }
+
+ // The is_default_instance member, if any.
+ if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+ type_info->is_default_instance_offset = size;
+ size += sizeof(bool);
+ size = AlignOffset(size);
+ } else {
+ type_info->is_default_instance_offset = -1;
+ }
+
+ // The oneof_case, if any. It is an array of uint32s.
+ if (type->oneof_decl_count() > 0) {
+ type_info->oneof_case_offset = size;
+ size += type->oneof_decl_count() * sizeof(uint32);
+ size = AlignOffset(size);
+ }
// The ExtensionSet, if any.
if (type->extension_range_count() > 0) {
@@ -513,10 +694,20 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
// All the fields.
for (int i = 0; i < type->field_count(); i++) {
// Make sure field is aligned to avoid bus errors.
- int field_size = FieldSpaceUsed(type->field(i));
- size = AlignTo(size, min(kSafeAlignment, field_size));
- offsets[i] = size;
- size += field_size;
+ // Oneof fields do not use any space.
+ if (!type->field(i)->containing_oneof()) {
+ int field_size = FieldSpaceUsed(type->field(i));
+ size = AlignTo(size, min(kSafeAlignment, field_size));
+ offsets[i] = size;
+ size += field_size;
+ }
+ }
+
+ // The oneofs.
+ for (int i = 0; i < type->oneof_decl_count(); i++) {
+ size = AlignTo(size, kSafeAlignment);
+ offsets[type->field_count() + i] = size;
+ size += kMaxOneofUnionSize;
}
// Add the UnknownFieldSet to the end.
@@ -533,26 +724,126 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
void* base = operator new(size);
memset(base, 0, size);
DynamicMessage* prototype = new(base) DynamicMessage(type_info);
- type_info->prototype.reset(prototype);
+ type_info->prototype = prototype;
// Construct the reflection object.
- type_info->reflection.reset(
- new GeneratedMessageReflection(
- type_info->type,
- type_info->prototype.get(),
- type_info->offsets.get(),
- type_info->has_bits_offset,
- type_info->unknown_fields_offset,
- type_info->extensions_offset,
- type_info->pool,
- this,
- type_info->size));
-
+ if (type->oneof_decl_count() > 0) {
+ // Compute the size of default oneof instance and offsets of default
+ // oneof fields.
+ int oneof_size = 0;
+ for (int i = 0; i < type->oneof_decl_count(); i++) {
+ for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = type->oneof_decl(i)->field(j);
+ int field_size = OneofFieldSpaceUsed(field);
+ oneof_size = AlignTo(oneof_size, min(kSafeAlignment, field_size));
+ offsets[field->index()] = oneof_size;
+ oneof_size += field_size;
+ }
+ }
+ // Construct default oneof instance.
+ type_info->default_oneof_instance = ::operator new(oneof_size);
+ ConstructDefaultOneofInstance(type_info->type,
+ type_info->offsets.get(),
+ type_info->default_oneof_instance);
+ type_info->reflection.reset(
+ new GeneratedMessageReflection(
+ type_info->type,
+ type_info->prototype,
+ type_info->offsets.get(),
+ type_info->has_bits_offset,
+ type_info->unknown_fields_offset,
+ type_info->extensions_offset,
+ type_info->default_oneof_instance,
+ type_info->oneof_case_offset,
+ type_info->pool,
+ this,
+ type_info->size,
+ -1 /* arena_offset */,
+ type_info->is_default_instance_offset));
+ } else {
+ type_info->reflection.reset(
+ new GeneratedMessageReflection(
+ type_info->type,
+ type_info->prototype,
+ type_info->offsets.get(),
+ type_info->has_bits_offset,
+ type_info->unknown_fields_offset,
+ type_info->extensions_offset,
+ type_info->pool,
+ this,
+ type_info->size,
+ -1 /* arena_offset */,
+ type_info->is_default_instance_offset));
+ }
// Cross link prototypes.
prototype->CrossLinkPrototypes();
return prototype;
}
+void DynamicMessageFactory::ConstructDefaultOneofInstance(
+ const Descriptor* type,
+ const int offsets[],
+ void* default_oneof_instance) {
+ for (int i = 0; i < type->oneof_decl_count(); i++) {
+ for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = type->oneof_decl(i)->field(j);
+ void* field_ptr = reinterpret_cast<uint8*>(
+ default_oneof_instance) + offsets[field->index()];
+ switch (field->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ new(field_ptr) TYPE(field->default_value_##TYPE()); \
+ break;
+
+ HANDLE_TYPE(INT32 , int32 );
+ HANDLE_TYPE(INT64 , int64 );
+ HANDLE_TYPE(UINT32, uint32);
+ HANDLE_TYPE(UINT64, uint64);
+ HANDLE_TYPE(DOUBLE, double);
+ HANDLE_TYPE(FLOAT , float );
+ HANDLE_TYPE(BOOL , bool );
+#undef HANDLE_TYPE
+
+ case FieldDescriptor::CPPTYPE_ENUM:
+ new(field_ptr) int(field->default_value_enum()->number());
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ switch (field->options().ctype()) {
+ default:
+ case FieldOptions::STRING:
+ ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
+ asp->UnsafeSetDefault(&field->default_value_string());
+ break;
+ }
+ break;
+
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ new(field_ptr) Message*(NULL);
+ break;
+ }
+ }
+ }
+ }
+}
+
+void DynamicMessageFactory::DeleteDefaultOneofInstance(
+ const Descriptor* type,
+ const int offsets[],
+ void* default_oneof_instance) {
+ for (int i = 0; i < type->oneof_decl_count(); i++) {
+ for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = type->oneof_decl(i)->field(j);
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+ switch (field->options().ctype()) {
+ default:
+ case FieldOptions::STRING:
+ break;
+ }
+ }
+ }
+ }
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h
index 81dd2c63..b5928a52 100644
--- a/src/google/protobuf/dynamic_message.h
+++ b/src/google/protobuf/dynamic_message.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -38,6 +38,11 @@
#ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
#define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
#include <google/protobuf/message.h>
#include <google/protobuf/stubs/common.h>
@@ -68,7 +73,7 @@ class DescriptorPool; // descriptor.h
class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
public:
// Construct a DynamicMessageFactory that will search for extensions in
- // the DescriptorPool in which the exendee is defined.
+ // the DescriptorPool in which the extendee is defined.
DynamicMessageFactory();
// Construct a DynamicMessageFactory that will search for extensions in
@@ -102,7 +107,7 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
// object. The returned object remains property of the factory and will
// be destroyed when the factory is destroyed. Also, any objects created
// by calling the prototype's New() method share some data with the
- // prototype, so these must be destoyed before the DynamicMessageFactory
+ // prototype, so these must be destroyed before the DynamicMessageFactory
// is destroyed.
//
// The given descriptor must outlive the returned message, and hence must
@@ -121,12 +126,22 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
// public header (for good reason), but dynamic_message.h is, and public
// headers may only #include other public headers.
struct PrototypeMap;
- scoped_ptr<PrototypeMap> prototypes_;
+ google::protobuf::scoped_ptr<PrototypeMap> prototypes_;
mutable Mutex prototypes_mutex_;
friend class DynamicMessage;
const Message* GetPrototypeNoLock(const Descriptor* type);
+ // Construct default oneof instance for reflection usage if oneof
+ // is defined.
+ static void ConstructDefaultOneofInstance(const Descriptor* type,
+ const int offsets[],
+ void* default_oneof_instance);
+ // Delete default oneof instance. Called by ~DynamicMessageFactory.
+ static void DeleteDefaultOneofInstance(const Descriptor* type,
+ const int offsets[],
+ void* default_oneof_instance);
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory);
};
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
index 41b89ab5..522a092a 100644
--- a/src/google/protobuf/dynamic_message_unittest.cc
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,6 +46,7 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_no_field_presence.pb.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
@@ -63,6 +64,10 @@ class DynamicMessageTest : public testing::Test {
const Message* extensions_prototype_;
const Descriptor* packed_descriptor_;
const Message* packed_prototype_;
+ const Descriptor* oneof_descriptor_;
+ const Message* oneof_prototype_;
+ const Descriptor* proto3_descriptor_;
+ const Message* proto3_prototype_;
DynamicMessageTest(): factory_(&pool_) {}
@@ -73,13 +78,21 @@ class DynamicMessageTest : public testing::Test {
// unittest_import.proto.
FileDescriptorProto unittest_file;
FileDescriptorProto unittest_import_file;
+ FileDescriptorProto unittest_import_public_file;
+ FileDescriptorProto unittest_no_field_presence_file;
unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file);
unittest_import::ImportMessage::descriptor()->file()->CopyTo(
&unittest_import_file);
+ unittest_import::PublicImportMessage::descriptor()->file()->CopyTo(
+ &unittest_import_public_file);
+ proto2_nofieldpresence_unittest::TestAllTypes::descriptor()->
+ file()->CopyTo(&unittest_no_field_presence_file);
+ ASSERT_TRUE(pool_.BuildFile(unittest_import_public_file) != NULL);
ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != NULL);
ASSERT_TRUE(pool_.BuildFile(unittest_file) != NULL);
+ ASSERT_TRUE(pool_.BuildFile(unittest_no_field_presence_file) != NULL);
descriptor_ = pool_.FindMessageTypeByName("protobuf_unittest.TestAllTypes");
ASSERT_TRUE(descriptor_ != NULL);
@@ -94,6 +107,17 @@ class DynamicMessageTest : public testing::Test {
pool_.FindMessageTypeByName("protobuf_unittest.TestPackedTypes");
ASSERT_TRUE(packed_descriptor_ != NULL);
packed_prototype_ = factory_.GetPrototype(packed_descriptor_);
+
+ oneof_descriptor_ =
+ pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2");
+ ASSERT_TRUE(oneof_descriptor_ != NULL);
+ oneof_prototype_ = factory_.GetPrototype(oneof_descriptor_);
+
+ proto3_descriptor_ =
+ pool_.FindMessageTypeByName(
+ "proto2_nofieldpresence_unittest.TestAllTypes");
+ ASSERT_TRUE(proto3_descriptor_ != NULL);
+ proto3_prototype_ = factory_.GetPrototype(proto3_descriptor_);
}
};
@@ -143,6 +167,63 @@ TEST_F(DynamicMessageTest, PackedFields) {
reflection_tester.ExpectPackedFieldsSetViaReflection(*message);
}
+TEST_F(DynamicMessageTest, Oneof) {
+ // Check that oneof fields work properly.
+ scoped_ptr<Message> message(oneof_prototype_->New());
+
+ // Check default values.
+ const Descriptor* descriptor = message->GetDescriptor();
+ const Reflection* reflection = message->GetReflection();
+ EXPECT_EQ(0, reflection->GetInt32(
+ *message, descriptor->FindFieldByName("foo_int")));
+ EXPECT_EQ("", reflection->GetString(
+ *message, descriptor->FindFieldByName("foo_string")));
+ EXPECT_EQ("", reflection->GetString(
+ *message, descriptor->FindFieldByName("foo_cord")));
+ EXPECT_EQ("", reflection->GetString(
+ *message, descriptor->FindFieldByName("foo_string_piece")));
+ EXPECT_EQ("", reflection->GetString(
+ *message, descriptor->FindFieldByName("foo_bytes")));
+ EXPECT_EQ(unittest::TestOneof2::FOO, reflection->GetEnum(
+ *message, descriptor->FindFieldByName("foo_enum"))->number());
+ const Descriptor* nested_descriptor;
+ const Message* nested_prototype;
+ nested_descriptor =
+ pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2.NestedMessage");
+ nested_prototype = factory_.GetPrototype(nested_descriptor);
+ EXPECT_EQ(nested_prototype,
+ &reflection->GetMessage(
+ *message, descriptor->FindFieldByName("foo_message")));
+ const Descriptor* foogroup_descriptor;
+ const Message* foogroup_prototype;
+ foogroup_descriptor =
+ pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2.FooGroup");
+ foogroup_prototype = factory_.GetPrototype(foogroup_descriptor);
+ EXPECT_EQ(foogroup_prototype,
+ &reflection->GetMessage(
+ *message, descriptor->FindFieldByName("foogroup")));
+ EXPECT_NE(foogroup_prototype,
+ &reflection->GetMessage(
+ *message, descriptor->FindFieldByName("foo_lazy_message")));
+ EXPECT_EQ(5, reflection->GetInt32(
+ *message, descriptor->FindFieldByName("bar_int")));
+ EXPECT_EQ("STRING", reflection->GetString(
+ *message, descriptor->FindFieldByName("bar_string")));
+ EXPECT_EQ("CORD", reflection->GetString(
+ *message, descriptor->FindFieldByName("bar_cord")));
+ EXPECT_EQ("SPIECE", reflection->GetString(
+ *message, descriptor->FindFieldByName("bar_string_piece")));
+ EXPECT_EQ("BYTES", reflection->GetString(
+ *message, descriptor->FindFieldByName("bar_bytes")));
+ EXPECT_EQ(unittest::TestOneof2::BAR, reflection->GetEnum(
+ *message, descriptor->FindFieldByName("bar_enum"))->number());
+
+ // Check set functions.
+ TestUtil::ReflectionTester reflection_tester(oneof_descriptor_);
+ reflection_tester.SetOneofViaReflection(message.get());
+ reflection_tester.ExpectOneofSetViaReflection(*message);
+}
+
TEST_F(DynamicMessageTest, SpaceUsed) {
// Test that SpaceUsed() works properly
@@ -158,5 +239,47 @@ 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.
+}
+
+TEST_F(DynamicMessageTest, Proto3) {
+ Message* message = proto3_prototype_->New();
+ const Reflection* refl = message->GetReflection();
+ const Descriptor* desc = message->GetDescriptor();
+
+ // Just test a single primtive and single message field here to make sure we
+ // are getting the no-field-presence semantics elsewhere. DynamicMessage uses
+ // GeneratedMessageReflection under the hood, so the rest should be fine as
+ // long as GMR recognizes that we're using a proto3 message.
+ const FieldDescriptor* optional_int32 =
+ desc->FindFieldByName("optional_int32");
+ const FieldDescriptor* optional_msg =
+ desc->FindFieldByName("optional_nested_message");
+ EXPECT_TRUE(optional_int32 != NULL);
+ EXPECT_TRUE(optional_msg != NULL);
+
+ EXPECT_EQ(false, refl->HasField(*message, optional_int32));
+ refl->SetInt32(message, optional_int32, 42);
+ EXPECT_EQ(true, refl->HasField(*message, optional_int32));
+ refl->SetInt32(message, optional_int32, 0);
+ EXPECT_EQ(false, refl->HasField(*message, optional_int32));
+
+ EXPECT_EQ(false, refl->HasField(*message, optional_msg));
+ refl->MutableMessage(message, optional_msg);
+ EXPECT_EQ(true, refl->HasField(*message, optional_msg));
+ delete refl->ReleaseMessage(message, optional_msg);
+ EXPECT_EQ(false, refl->HasField(*message, optional_msg));
+
+ // Also ensure that the default instance handles field presence properly.
+ EXPECT_EQ(false, refl->HasField(*proto3_prototype_, optional_msg));
+
+ delete message;
+}
+
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 1a6f5dfc..03b38dd0 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -38,10 +38,9 @@
#include <google/protobuf/extension_set.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/map_util.h>
namespace google {
namespace protobuf {
@@ -58,6 +57,24 @@ inline WireFormatLite::CppType cpp_type(FieldType type) {
return WireFormatLite::FieldTypeToCppType(real_type(type));
}
+inline bool is_packable(WireFormatLite::WireType type) {
+ switch (type) {
+ case WireFormatLite::WIRETYPE_VARINT:
+ case WireFormatLite::WIRETYPE_FIXED64:
+ case WireFormatLite::WIRETYPE_FIXED32:
+ return true;
+ case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
+ case WireFormatLite::WIRETYPE_START_GROUP:
+ case WireFormatLite::WIRETYPE_END_GROUP:
+ return false;
+
+ // Do not add a default statement. Let the compiler complain when someone
+ // adds a new wire type.
+ }
+ GOOGLE_LOG(FATAL) << "can't reach here.";
+ return false;
+}
+
// Registry stuff.
typedef hash_map<pair<const MessageLite*, int>,
ExtensionInfo> ExtensionRegistry;
@@ -71,7 +88,7 @@ void DeleteRegistry() {
void InitRegistry() {
registry_ = new ExtensionRegistry;
- internal::OnShutdown(&DeleteRegistry);
+ OnShutdown(&DeleteRegistry);
}
// This function is only called at startup, so there is no need for thread-
@@ -80,7 +97,7 @@ void Register(const MessageLite* containing_type,
int number, ExtensionInfo info) {
::google::protobuf::GoogleOnceInit(&registry_init_, &InitRegistry);
- if (!InsertIfNotPresent(registry_, make_pair(containing_type, number),
+ if (!InsertIfNotPresent(registry_, std::make_pair(containing_type, number),
info)) {
GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \""
<< containing_type->GetTypeName()
@@ -90,8 +107,9 @@ void Register(const MessageLite* containing_type,
const ExtensionInfo* FindRegisteredExtension(
const MessageLite* containing_type, int number) {
- return (registry_ == NULL) ? NULL :
- FindOrNull(*registry_, make_pair(containing_type, number));
+ return (registry_ == NULL)
+ ? NULL
+ : FindOrNull(*registry_, std::make_pair(containing_type, number));
}
} // namespace
@@ -159,12 +177,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<int, Extension>::iterator iter = extensions_.begin();
- iter != extensions_.end(); ++iter) {
- iter->second.Free();
+ // Deletes all allocated extensions.
+ if (arena_ == NULL) {
+ for (map<int, Extension>::iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ iter->second.Free();
+ }
}
}
@@ -180,6 +207,17 @@ bool ExtensionSet::Has(int number) const {
return !iter->second.is_cleared;
}
+int ExtensionSet::NumExtensions() const {
+ int result = 0;
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ if (!iter->second.is_cleared) {
+ ++result;
+ }
+ }
+ return result;
+}
+
int ExtensionSet::ExtensionSize(int number) const {
map<int, Extension>::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end()) return false;
@@ -275,7 +313,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<LOWERCASE>(); \
+ extension->repeated_##LOWERCASE##_value = \
+ Arena::Create<RepeatedField<LOWERCASE> >(arena_, arena_); \
} else { \
GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE); \
GOOGLE_DCHECK_EQ(extension->is_packed, packed); \
@@ -293,6 +332,90 @@ PRIMITIVE_ACCESSORS( BOOL, bool, Bool)
#undef PRIMITIVE_ACCESSORS
+const void* ExtensionSet::GetRawRepeatedField(int number,
+ const void* default_value) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) {
+ return default_value;
+ }
+ // We assume that all the RepeatedField<>* pointers have the same
+ // size and alignment within the anonymous union in Extension.
+ return iter->second.repeated_int32_value;
+}
+
+void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type,
+ bool packed,
+ const FieldDescriptor* desc) {
+ Extension* extension;
+
+ // We instantiate an empty Repeated{,Ptr}Field if one doesn't exist for this
+ // extension.
+ if (MaybeNewExtension(number, desc, &extension)) {
+ extension->is_repeated = true;
+ extension->type = field_type;
+ extension->is_packed = packed;
+
+ switch (WireFormatLite::FieldTypeToCppType(
+ static_cast<WireFormatLite::FieldType>(field_type))) {
+ case WireFormatLite::CPPTYPE_INT32:
+ extension->repeated_int32_value =
+ Arena::Create<RepeatedField<int32> >(arena_, arena_);
+ break;
+ case WireFormatLite::CPPTYPE_INT64:
+ extension->repeated_int64_value =
+ Arena::Create<RepeatedField<int64> >(arena_, arena_);
+ break;
+ case WireFormatLite::CPPTYPE_UINT32:
+ extension->repeated_uint32_value =
+ Arena::Create<RepeatedField<uint32> >(arena_, arena_);
+ break;
+ case WireFormatLite::CPPTYPE_UINT64:
+ extension->repeated_uint64_value =
+ Arena::Create<RepeatedField<uint64> >(arena_, arena_);
+ break;
+ case WireFormatLite::CPPTYPE_DOUBLE:
+ extension->repeated_double_value =
+ Arena::Create<RepeatedField<double> >(arena_, arena_);
+ break;
+ case WireFormatLite::CPPTYPE_FLOAT:
+ extension->repeated_float_value =
+ Arena::Create<RepeatedField<float> >(arena_, arena_);
+ break;
+ case WireFormatLite::CPPTYPE_BOOL:
+ extension->repeated_bool_value =
+ Arena::Create<RepeatedField<bool> >(arena_, arena_);
+ break;
+ case WireFormatLite::CPPTYPE_ENUM:
+ extension->repeated_enum_value =
+ Arena::Create<RepeatedField<int> >(arena_, arena_);
+ break;
+ case WireFormatLite::CPPTYPE_STRING:
+ extension->repeated_string_value =
+ Arena::Create<RepeatedPtrField< ::std::string> >(arena_, arena_);
+ break;
+ case WireFormatLite::CPPTYPE_MESSAGE:
+ extension->repeated_message_value =
+ Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+ break;
+ }
+ }
+
+ // We assume that all the RepeatedField<>* pointers have the same
+ // size and alignment within the anonymous union in Extension.
+ return extension->repeated_int32_value;
+}
+
+// Compatible version using old call signature. Does not create extensions when
+// the don't already exist; instead, just GOOGLE_CHECK-fails.
+void* ExtensionSet::MutableRawRepeatedField(int number) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter == extensions_.end()) << "Extension not found.";
+ // We assume that all the RepeatedField<>* pointers have the same
+ // size and alignment within the anonymous union in Extension.
+ return iter->second.repeated_int32_value;
+}
+
+
// -------------------------------------------------------------------
// Enums
@@ -344,7 +467,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<int>();
+ extension->repeated_enum_value =
+ Arena::Create<RepeatedField<int> >(arena_, arena_);
} else {
GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM);
GOOGLE_DCHECK_EQ(extension->is_packed, packed);
@@ -374,7 +498,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<string>(arena_);
} else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, STRING);
}
@@ -404,7 +528,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<string>();
+ extension->repeated_string_value =
+ Arena::Create<RepeatedPtrField<string> >(arena_, arena_);
} else {
GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING);
}
@@ -422,7 +547,11 @@ const MessageLite& ExtensionSet::GetMessage(
return default_value;
} else {
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
- return *iter->second.message_value;
+ if (iter->second.is_lazy) {
+ return iter->second.lazymessage_value->GetMessage(default_value);
+ } else {
+ return *iter->second.message_value;
+ }
}
}
@@ -439,12 +568,19 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
extension->type = type;
GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
extension->is_repeated = false;
- extension->message_value = prototype.New();
+ extension->is_lazy = false;
+ extension->message_value = prototype.New(arena_);
+ extension->is_cleared = false;
+ return extension->message_value;
} else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+ extension->is_cleared = false;
+ if (extension->is_lazy) {
+ return extension->lazymessage_value->MutableMessage(prototype);
+ } else {
+ return extension->message_value;
+ }
}
- extension->is_cleared = false;
- return extension->message_value;
}
// Defined in extension_set_heavy.cc.
@@ -452,6 +588,106 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
// const Descriptor* message_type,
// MessageFactory* factory)
+void ExtensionSet::SetAllocatedMessage(int number, FieldType type,
+ const FieldDescriptor* descriptor,
+ MessageLite* message) {
+ if (message == NULL) {
+ ClearExtension(number);
+ return;
+ }
+ Extension* extension;
+ if (MaybeNewExtension(number, descriptor, &extension)) {
+ extension->type = type;
+ GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+ extension->is_repeated = false;
+ extension->is_lazy = false;
+ 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 {
+ 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;
+}
+
+MessageLite* ExtensionSet::ReleaseMessage(int number,
+ const MessageLite& prototype) {
+ map<int, Extension>::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->ReleaseMessage(prototype);
+ 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<int, Extension>::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;
+ }
+ extensions_.erase(number);
+ return ret;
+ }
+}
+
+// Defined in extension_set_heavy.cc.
+// MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
+// MessageFactory* factory);
+
const MessageLite& ExtensionSet::GetRepeatedMessage(
int number, int index) const {
map<int, Extension>::const_iterator iter = extensions_.find(number);
@@ -476,7 +712,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<MessageLite>();
+ Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
} else {
GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
}
@@ -484,9 +720,9 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
// RepeatedPtrField<MessageLite> does not know how to Add() since it cannot
// allocate an abstract object, so we have to be tricky.
MessageLite* result = extension->repeated_message_value
- ->AddFromCleared<internal::GenericTypeHandler<MessageLite> >();
+ ->AddFromCleared<GenericTypeHandler<MessageLite> >();
if (result == NULL) {
- result = prototype.New();
+ result = prototype.New(arena_);
extension->repeated_message_value->AddAllocated(result);
}
return result;
@@ -540,6 +776,16 @@ void ExtensionSet::RemoveLast(int number) {
}
}
+MessageLite* ExtensionSet::ReleaseLast(int number) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+
+ Extension* extension = &iter->second;
+ GOOGLE_DCHECK(extension->is_repeated);
+ GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE);
+ return extension->repeated_message_value->ReleaseLast();
+}
+
void ExtensionSet::SwapElements(int number, int index1, int index2) {
map<int, Extension>::iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
@@ -594,93 +840,142 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) {
for (map<int, Extension>::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_repeated = true;
- } else {
- GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
- 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 = \
+ Arena::Create<REPEATED_TYPE >(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>);
+#undef HANDLE_TYPE
+
+ case WireFormatLite::CPPTYPE_MESSAGE:
+ if (is_new) {
+ extension->repeated_message_value =
+ Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+ }
+ // We can't call RepeatedPtrField<MessageLite>::MergeFrom() because
+ // it would attempt to allocate new objects.
+ RepeatedPtrField<MessageLite>* 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<GenericTypeHandler<MessageLite> >();
+ 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, 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); \
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \
+ case WireFormatLite::CPPTYPE_##UPPERCASE: \
+ Set##CAMELCASE(number, other_extension.type, \
+ other_extension.LOWERCASE##_value, \
+ other_extension.descriptor); \
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, 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_MESSAGE:
+ 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->repeated_message_value =
- new RepeatedPtrField<MessageLite>();
- }
- // We can't call RepeatedPtrField<MessageLite>::MergeFrom() because
- // it would attempt to allocate new objects.
- RepeatedPtrField<MessageLite>* 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<GenericTypeHandler<MessageLite> >();
- if (target == NULL) {
- target = other_message.New();
- extension->repeated_message_value->AddAllocated(target);
+ 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->message_value->CheckTypeAndMergeFrom(
+ other_extension.lazymessage_value->GetMessage(
+ *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);
+ }
}
- target->CheckTypeAndMergeFrom(other_message);
}
+ extension->is_cleared = false;
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);
-#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:
- MutableMessage(iter->first, other_extension.type,
- *other_extension.message_value,
- other_extension.descriptor)
- ->CheckTypeAndMergeFrom(*other_extension.message_value);
- break;
}
}
}
@@ -688,7 +983,73 @@ 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,
+ int number) {
+ if (this == other) return;
+ map<int, Extension>::iterator this_iter = extensions_.find(number);
+ map<int, Extension>::iterator other_iter = other->extensions_.find(number);
+
+ if (this_iter == extensions_.end() &&
+ other_iter == other->extensions_.end()) {
+ return;
+ }
+
+ if (this_iter != extensions_.end() &&
+ other_iter != other->extensions_.end()) {
+ 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<int, Extension>::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()) {
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ extensions_.insert(std::make_pair(number, other_iter->second));
+ } else {
+ InternalExtensionMergeFrom(number, other_iter->second);
+ }
+ other->extensions_.erase(number);
+ return;
+ }
+
+ if (other_iter == other->extensions_.end()) {
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ other->extensions_.insert(std::make_pair(number, this_iter->second));
+ } else {
+ other->InternalExtensionMergeFrom(number, this_iter->second);
+ }
+ extensions_.erase(number);
+ return;
+ }
}
bool ExtensionSet::IsInitialized() const {
@@ -706,7 +1067,11 @@ bool ExtensionSet::IsInitialized() const {
}
} else {
if (!extension.is_cleared) {
- if (!extension.message_value->IsInitialized()) return false;
+ if (extension.is_lazy) {
+ if (!extension.lazymessage_value->IsInitialized()) return false;
+ } else {
+ if (!extension.message_value->IsInitialized()) return false;
+ }
}
}
}
@@ -715,27 +1080,60 @@ bool ExtensionSet::IsInitialized() const {
return true;
}
+bool ExtensionSet::FindExtensionInfoFromTag(
+ uint32 tag, ExtensionFinder* extension_finder, int* field_number,
+ ExtensionInfo* extension, bool* was_packed_on_wire) {
+ *field_number = WireFormatLite::GetTagFieldNumber(tag);
+ WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+ return FindExtensionInfoFromFieldNumber(wire_type, *field_number,
+ extension_finder, extension,
+ was_packed_on_wire);
+}
+
+bool ExtensionSet::FindExtensionInfoFromFieldNumber(
+ int wire_type, int field_number, ExtensionFinder* extension_finder,
+ ExtensionInfo* extension, bool* was_packed_on_wire) {
+ if (!extension_finder->Find(field_number, extension)) {
+ return false;
+ }
+
+ WireFormatLite::WireType expected_wire_type =
+ WireFormatLite::WireTypeForFieldType(real_type(extension->type));
+
+ // Check if this is a packed field.
+ *was_packed_on_wire = false;
+ if (extension->is_repeated &&
+ wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED &&
+ is_packable(expected_wire_type)) {
+ *was_packed_on_wire = true;
+ return true;
+ }
+ // Otherwise the wire type must match.
+ return expected_wire_type == wire_type;
+}
+
bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
ExtensionFinder* extension_finder,
FieldSkipper* field_skipper) {
- int number = WireFormatLite::GetTagFieldNumber(tag);
- WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
-
+ int number;
+ bool was_packed_on_wire;
ExtensionInfo extension;
- bool is_unknown;
- if (!extension_finder->Find(number, &extension)) {
- is_unknown = true;
- } else if (extension.is_packed) {
- is_unknown = (wire_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+ if (!FindExtensionInfoFromTag(
+ tag, extension_finder, &number, &extension, &was_packed_on_wire)) {
+ return field_skipper->SkipField(input, tag);
} else {
- WireFormatLite::WireType expected_wire_type =
- WireFormatLite::WireTypeForFieldType(real_type(extension.type));
- is_unknown = (wire_type != expected_wire_type);
+ return ParseFieldWithExtensionInfo(
+ number, was_packed_on_wire, extension, input, field_skipper);
}
+}
- if (is_unknown) {
- field_skipper->SkipField(input, tag);
- } else if (extension.is_packed) {
+bool ExtensionSet::ParseFieldWithExtensionInfo(
+ int number, bool was_packed_on_wire, const ExtensionInfo& extension,
+ io::CodedInputStream* input,
+ FieldSkipper* field_skipper) {
+ // Explicitly not read extension.is_packed, instead check whether the field
+ // was encoded in packed form on the wire.
+ if (was_packed_on_wire) {
uint32 size;
if (!input->ReadVarint32(&size)) return false;
io::CodedInputStream::Limit limit = input->PushLimit(size);
@@ -749,7 +1147,8 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \
input, &value)) return false; \
Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
- true, value, extension.descriptor); \
+ extension.is_packed, value, \
+ extension.descriptor); \
} \
break
@@ -775,8 +1174,11 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
input, &value)) return false;
if (extension.enum_validity_check.func(
extension.enum_validity_check.arg, value)) {
- AddEnum(number, WireFormatLite::TYPE_ENUM, true, value,
- extension.descriptor);
+ AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed,
+ value, extension.descriptor);
+ } else {
+ // Invalid value. Treat as unknown.
+ field_skipper->SkipUnknownEnum(number, value);
}
}
break;
@@ -798,9 +1200,10 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
if (!WireFormatLite::ReadPrimitive< \
CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \
input, &value)) return false; \
- if (extension.is_repeated) { \
+ if (extension.is_repeated) { \
Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
- false, value, extension.descriptor); \
+ extension.is_packed, value, \
+ extension.descriptor); \
} else { \
Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
extension.descriptor); \
@@ -832,7 +1235,7 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
// Invalid value. Treat as unknown.
field_skipper->SkipUnknownEnum(number, value);
} else if (extension.is_repeated) {
- AddEnum(number, WireFormatLite::TYPE_ENUM, false, value,
+ AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
extension.descriptor);
} else {
SetEnum(number, WireFormatLite::TYPE_ENUM, value,
@@ -852,8 +1255,8 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
case WireFormatLite::TYPE_BYTES: {
string* value = extension.is_repeated ?
- AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) :
- MutableString(number, WireFormatLite::TYPE_STRING,
+ AddString(number, WireFormatLite::TYPE_BYTES, extension.descriptor) :
+ MutableString(number, WireFormatLite::TYPE_BYTES,
extension.descriptor);
if (!WireFormatLite::ReadBytes(input, value)) return false;
break;
@@ -891,125 +1294,24 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
return ParseField(tag, input, &finder, &skipper);
}
+bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
+ const MessageLite* containing_type,
+ io::CodedOutputStream* unknown_fields) {
+ CodedOutputStreamFieldSkipper skipper(unknown_fields);
+ GeneratedExtensionFinder finder(containing_type);
+ return ParseField(tag, input, &finder, &skipper);
+}
+
// Defined in extension_set_heavy.cc.
// bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
// const MessageLite* containing_type,
// UnknownFieldSet* unknown_fields)
-bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
- ExtensionFinder* extension_finder,
- FieldSkipper* field_skipper) {
- while (true) {
- uint32 tag = input->ReadTag();
- switch (tag) {
- case 0:
- return true;
- case WireFormatLite::kMessageSetItemStartTag:
- if (!ParseMessageSetItem(input, extension_finder, field_skipper)) {
- return false;
- }
- break;
- default:
- if (!ParseField(tag, input, extension_finder, field_skipper)) {
- return false;
- }
- break;
- }
- }
-}
-
-bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
- const MessageLite* containing_type) {
- FieldSkipper skipper;
- GeneratedExtensionFinder finder(containing_type);
- return ParseMessageSet(input, &finder, &skipper);
-}
-
// Defined in extension_set_heavy.cc.
// bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
// const MessageLite* containing_type,
// UnknownFieldSet* unknown_fields);
-bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input,
- ExtensionFinder* extension_finder,
- FieldSkipper* field_skipper) {
- // TODO(kenton): It would be nice to share code between this and
- // WireFormatLite::ParseAndMergeMessageSetItem(), but I think the
- // differences would be hard to factor out.
-
- // This method parses a group which should contain two fields:
- // required int32 type_id = 2;
- // required data message = 3;
-
- // Once we see a type_id, we'll construct a fake tag for this extension
- // which is the tag it would have had under the proto2 extensions wire
- // format.
- uint32 fake_tag = 0;
-
- // If we see message data before the type_id, we'll append it to this so
- // we can parse it later. This will probably never happen in practice,
- // as no MessageSet encoder I know of writes the message before the type ID.
- // But, it's technically valid so we should allow it.
- // TODO(kenton): Use a Cord instead? Do I care?
- string message_data;
-
- while (true) {
- uint32 tag = input->ReadTag();
- if (tag == 0) return false;
-
- switch (tag) {
- case WireFormatLite::kMessageSetTypeIdTag: {
- uint32 type_id;
- if (!input->ReadVarint32(&type_id)) return false;
- fake_tag = WireFormatLite::MakeTag(type_id,
- WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
-
- if (!message_data.empty()) {
- // We saw some message data before the type_id. Have to parse it
- // now.
- io::CodedInputStream sub_input(
- reinterpret_cast<const uint8*>(message_data.data()),
- message_data.size());
- if (!ParseField(fake_tag, &sub_input,
- extension_finder, field_skipper)) {
- return false;
- }
- message_data.clear();
- }
-
- break;
- }
-
- case WireFormatLite::kMessageSetMessageTag: {
- if (fake_tag == 0) {
- // We haven't seen a type_id yet. Append this data to message_data.
- string temp;
- uint32 length;
- if (!input->ReadVarint32(&length)) return false;
- if (!input->ReadString(&temp, length)) return false;
- message_data.append(temp);
- } else {
- // Already saw type_id, so we can parse this directly.
- if (!ParseField(fake_tag, input,
- extension_finder, field_skipper)) {
- return false;
- }
- }
-
- break;
- }
-
- case WireFormatLite::kMessageSetItemEndTag: {
- return true;
- }
-
- default: {
- if (!field_skipper->SkipField(input, tag)) return false;
- }
- }
- }
-}
-
void ExtensionSet::SerializeWithCachedSizes(
int start_field_number, int end_field_number,
io::CodedOutputStream* output) const {
@@ -1021,14 +1323,6 @@ void ExtensionSet::SerializeWithCachedSizes(
}
}
-void ExtensionSet::SerializeMessageSetWithCachedSizes(
- io::CodedOutputStream* output) const {
- map<int, Extension>::const_iterator iter;
- for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
- iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output);
- }
-}
-
int ExtensionSet::ByteSize() const {
int total_size = 0;
@@ -1040,17 +1334,6 @@ int ExtensionSet::ByteSize() const {
return total_size;
}
-int ExtensionSet::MessageSetByteSize() const {
- int total_size = 0;
-
- for (map<int, Extension>::const_iterator iter = extensions_.begin();
- iter != extensions_.end(); ++iter) {
- total_size += iter->second.MessageSetItemByteSize(iter->first);
- }
-
- return total_size;
-}
-
// Defined in extension_set_heavy.cc.
// int ExtensionSet::SpaceUsedExcludingSelf() const
@@ -1058,7 +1341,7 @@ bool ExtensionSet::MaybeNewExtension(int number,
const FieldDescriptor* descriptor,
Extension** result) {
pair<map<int, Extension>::iterator, bool> insert_result =
- extensions_.insert(make_pair(number, Extension()));
+ extensions_.insert(std::make_pair(number, Extension()));
*result = &insert_result.first->second;
(*result)->descriptor = descriptor;
return insert_result.second;
@@ -1094,7 +1377,11 @@ void ExtensionSet::Extension::Clear() {
string_value->clear();
break;
case WireFormatLite::CPPTYPE_MESSAGE:
- message_value->Clear();
+ if (is_lazy) {
+ lazymessage_value->Clear();
+ } else {
+ message_value->Clear();
+ }
break;
default:
// No need to do anything. Get*() will return the default value
@@ -1206,40 +1493,18 @@ void ExtensionSet::Extension::SerializeFieldWithCachedSizes(
HANDLE_TYPE( BYTES, Bytes, *string_value);
HANDLE_TYPE( ENUM, Enum, enum_value);
HANDLE_TYPE( GROUP, Group, *message_value);
- HANDLE_TYPE( MESSAGE, Message, *message_value);
#undef HANDLE_TYPE
+ case WireFormatLite::TYPE_MESSAGE:
+ if (is_lazy) {
+ lazymessage_value->WriteMessage(number, output);
+ } else {
+ WireFormatLite::WriteMessage(number, *message_value, output);
+ }
+ break;
}
}
}
-void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes(
- int number,
- io::CodedOutputStream* output) const {
- if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
- // Not a valid MessageSet extension, but serialize it the normal way.
- SerializeFieldWithCachedSizes(number, output);
- return;
- }
-
- if (is_cleared) return;
-
- // Start group.
- output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
-
- // Write type ID.
- WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
- number,
- output);
- // Write message.
- WireFormatLite::WriteMessageMaybeToArray(
- WireFormatLite::kMessageSetMessageNumber,
- *message_value,
- output);
-
- // End group.
- output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
-}
-
int ExtensionSet::Extension::ByteSize(int number) const {
int result = 0;
@@ -1353,8 +1618,16 @@ int ExtensionSet::Extension::ByteSize(int number) const {
HANDLE_TYPE( BYTES, Bytes, *string_value);
HANDLE_TYPE( ENUM, Enum, enum_value);
HANDLE_TYPE( GROUP, Group, *message_value);
- HANDLE_TYPE( MESSAGE, Message, *message_value);
#undef HANDLE_TYPE
+ case WireFormatLite::TYPE_MESSAGE: {
+ if (is_lazy) {
+ int size = lazymessage_value->ByteSize();
+ result += io::CodedOutputStream::VarintSize32(size) + size;
+ } else {
+ result += WireFormatLite::MessageSize(*message_value);
+ }
+ break;
+ }
// Stuff with fixed size.
#define HANDLE_TYPE(UPPERCASE, CAMELCASE) \
@@ -1375,29 +1648,6 @@ int ExtensionSet::Extension::ByteSize(int number) const {
return result;
}
-int ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
- if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
- // Not a valid MessageSet extension, but compute the byte size for it the
- // normal way.
- return ByteSize(number);
- }
-
- if (is_cleared) return 0;
-
- int our_size = WireFormatLite::kMessageSetItemTagsSize;
-
- // type_id
- our_size += io::CodedOutputStream::VarintSize32(number);
-
- // message
- int message_size = message_value->ByteSize();
-
- our_size += io::CodedOutputStream::VarintSize32(message_size);
- our_size += message_size;
-
- return our_size;
-}
-
int ExtensionSet::Extension::GetSize() const {
GOOGLE_DCHECK(is_repeated);
switch (cpp_type(type)) {
@@ -1422,6 +1672,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)) {
@@ -1448,7 +1700,11 @@ void ExtensionSet::Extension::Free() {
delete string_value;
break;
case WireFormatLite::CPPTYPE_MESSAGE:
- delete message_value;
+ if (is_lazy) {
+ delete lazymessage_value;
+ } else {
+ delete message_value;
+ }
break;
default:
break;
@@ -1459,6 +1715,69 @@ void ExtensionSet::Extension::Free() {
// Defined in extension_set_heavy.cc.
// int ExtensionSet::Extension::SpaceUsedExcludingSelf() const
+// ==================================================================
+// Default repeated field instances for iterator-compatible accessors
+
+const RepeatedStringTypeTraits::RepeatedFieldType*
+RepeatedStringTypeTraits::default_repeated_field_ = NULL;
+
+const RepeatedMessageGenericTypeTraits::RepeatedFieldType*
+RepeatedMessageGenericTypeTraits::default_repeated_field_ = NULL;
+
+#define PROTOBUF_DEFINE_DEFAULT_REPEATED(TYPE) \
+ const RepeatedField<TYPE>* \
+ RepeatedPrimitiveGenericTypeTraits::default_repeated_field_##TYPE##_ = NULL;
+
+PROTOBUF_DEFINE_DEFAULT_REPEATED(int32)
+PROTOBUF_DEFINE_DEFAULT_REPEATED(int64)
+PROTOBUF_DEFINE_DEFAULT_REPEATED(uint32)
+PROTOBUF_DEFINE_DEFAULT_REPEATED(uint64)
+PROTOBUF_DEFINE_DEFAULT_REPEATED(double)
+PROTOBUF_DEFINE_DEFAULT_REPEATED(float)
+PROTOBUF_DEFINE_DEFAULT_REPEATED(bool)
+
+#undef PROTOBUF_DEFINE_DEFAULT_REPEATED
+
+struct StaticDefaultRepeatedFieldsInitializer {
+ StaticDefaultRepeatedFieldsInitializer() {
+ InitializeDefaultRepeatedFields();
+ OnShutdown(&DestroyDefaultRepeatedFields);
+ }
+} static_repeated_fields_initializer;
+
+void InitializeDefaultRepeatedFields() {
+ RepeatedStringTypeTraits::default_repeated_field_ =
+ new RepeatedStringTypeTraits::RepeatedFieldType;
+ RepeatedMessageGenericTypeTraits::default_repeated_field_ =
+ new RepeatedMessageGenericTypeTraits::RepeatedFieldType;
+ RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int32_ =
+ new RepeatedField<int32>;
+ RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int64_ =
+ new RepeatedField<int64>;
+ RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint32_ =
+ new RepeatedField<uint32>;
+ RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint64_ =
+ new RepeatedField<uint64>;
+ RepeatedPrimitiveGenericTypeTraits::default_repeated_field_double_ =
+ new RepeatedField<double>;
+ RepeatedPrimitiveGenericTypeTraits::default_repeated_field_float_ =
+ new RepeatedField<float>;
+ RepeatedPrimitiveGenericTypeTraits::default_repeated_field_bool_ =
+ new RepeatedField<bool>;
+}
+
+void DestroyDefaultRepeatedFields() {
+ delete RepeatedStringTypeTraits::default_repeated_field_;
+ delete RepeatedMessageGenericTypeTraits::default_repeated_field_;
+ delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int32_;
+ delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int64_;
+ delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint32_;
+ delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint64_;
+ delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_double_;
+ delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_float_;
+ delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_bool_;
+}
+
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index ac1ada02..6d6702b3 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,9 +46,12 @@
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/repeated_field.h>
+
namespace google {
namespace protobuf {
+ class Arena;
class Descriptor; // descriptor.h
class FieldDescriptor; // descriptor.h
class DescriptorPool; // descriptor.h
@@ -62,10 +65,7 @@ namespace protobuf {
}
namespace internal {
class FieldSkipper; // wire_format_lite.h
- class RepeatedPtrFieldBase; // repeated_field.h
}
- template <typename Element> class RepeatedField; // repeated_field.h
- template <typename Element> class RepeatedPtrField; // repeated_field.h
}
namespace protobuf {
@@ -89,8 +89,8 @@ typedef bool EnumValidityFuncWithArg(const void* arg, int number);
// Information about a registered extension.
struct ExtensionInfo {
inline ExtensionInfo() {}
- inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed)
- : type(type), is_repeated(is_repeated), is_packed(is_packed),
+ inline ExtensionInfo(FieldType type_param, bool isrepeated, bool ispacked)
+ : type(type_param), is_repeated(isrepeated), is_packed(ispacked),
descriptor(NULL) {}
FieldType type;
@@ -138,6 +138,9 @@ class LIBPROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder {
const MessageLite* containing_type_;
};
+// A FieldSkipper used for parsing MessageSet.
+class MessageSetFieldSkipper;
+
// Note: extension_set_heavy.cc defines DescriptorPoolExtensionFinder for
// finding extensions from a DescriptorPool.
@@ -155,6 +158,7 @@ class LIBPROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder {
class LIBPROTOBUF_EXPORT ExtensionSet {
public:
ExtensionSet();
+ explicit ExtensionSet(::google::protobuf::Arena* arena);
~ExtensionSet();
// These are called at startup by protocol-compiler-generated code to
@@ -180,7 +184,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// is useful to implement Reflection::ListFields().
void AppendToList(const Descriptor* containing_type,
const DescriptorPool* pool,
- vector<const FieldDescriptor*>* output) const;
+ std::vector<const FieldDescriptor*>* output) const;
// =================================================================
// Accessors
@@ -214,6 +218,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
bool Has(int number) const;
int ExtensionSize(int number) const; // Size of a repeated extension.
+ int NumExtensions() const; // The number of extensions
FieldType ExtensionType(int number) const;
void ClearExtension(int number);
@@ -251,10 +256,39 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
const MessageLite& prototype, desc);
MessageLite* MutableMessage(const FieldDescriptor* decsriptor,
MessageFactory* factory);
+ // Adds the given message to the ExtensionSet, taking ownership of the
+ // message object. Existing message with the same number will be deleted.
+ // If "message" is NULL, this is equivalent to "ClearExtension(number)".
+ void SetAllocatedMessage(int number, FieldType type,
+ 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 -------------------------------------------------
+ // Fetches a RepeatedField extension by number; returns |default_value|
+ // if no such extension exists. User should not touch this directly; it is
+ // used by the GetRepeatedExtension() method.
+ const void* GetRawRepeatedField(int number, const void* default_value) const;
+ // Fetches a mutable version of a RepeatedField extension by number,
+ // instantiating one if none exists. Similar to above, user should not use
+ // this directly; it underlies MutableRepeatedExtension().
+ void* MutableRawRepeatedField(int number, FieldType field_type,
+ bool packed, const FieldDescriptor* desc);
+
+ // This is an overload of MutableRawRepeatedField to maintain compatibility
+ // with old code using a previous API. This version of
+ // MutableRawRepeatedField() will GOOGLE_CHECK-fail on a missing extension.
+ // (E.g.: borg/clients/internal/proto1/proto2_reflection.cc.)
+ void* MutableRawRepeatedField(int number);
+
int32 GetRepeatedInt32 (int number, int index) const;
int64 GetRepeatedInt64 (int number, int index) const;
uint32 GetRepeatedUInt32(int number, int index) const;
@@ -296,6 +330,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
#undef desc
void RemoveLast(int number);
+ MessageLite* ReleaseLast(int number);
void SwapElements(int number, int index1, int index2);
// -----------------------------------------------------------------
@@ -310,31 +345,35 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
void Clear();
void MergeFrom(const ExtensionSet& other);
void Swap(ExtensionSet* other);
+ void SwapExtension(ExtensionSet* other, int number);
bool IsInitialized() const;
- // Parses a single extension from the input. The input should start out
- // positioned immediately after the tag. |containing_type| is the default
- // instance for the containing message; it is used only to look up the
- // extension by number. See RegisterExtension(), above. Unlike the other
- // methods of ExtensionSet, this only works for generated message types --
- // it looks up extensions registered using RegisterExtension().
+ // Parses a single extension from the input. The input should start out
+ // positioned immediately after the tag.
bool ParseField(uint32 tag, io::CodedInputStream* input,
ExtensionFinder* extension_finder,
FieldSkipper* field_skipper);
// Specific versions for lite or full messages (constructs the appropriate
- // FieldSkipper automatically).
+ // FieldSkipper automatically). |containing_type| is the default
+ // instance for the containing message; it is used only to look up the
+ // extension by number. See RegisterExtension(), above. Unlike the other
+ // methods of ExtensionSet, this only works for generated message types --
+ // it looks up extensions registered using RegisterExtension().
bool ParseField(uint32 tag, io::CodedInputStream* input,
const MessageLite* containing_type);
bool ParseField(uint32 tag, io::CodedInputStream* input,
const Message* containing_type,
UnknownFieldSet* unknown_fields);
+ bool ParseField(uint32 tag, io::CodedInputStream* input,
+ const MessageLite* containing_type,
+ io::CodedOutputStream* unknown_fields);
// Parse an entire message in MessageSet format. Such messages have no
// fields, only extensions.
bool ParseMessageSet(io::CodedInputStream* input,
ExtensionFinder* extension_finder,
- FieldSkipper* field_skipper);
+ MessageSetFieldSkipper* field_skipper);
// Specific versions for lite or full messages (constructs the appropriate
// FieldSkipper automatically).
@@ -382,18 +421,51 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
private:
+ // Interface of a lazily parsed singular message extension.
+ class LIBPROTOBUF_EXPORT LazyMessageExtension {
+ public:
+ LazyMessageExtension() {}
+ virtual ~LazyMessageExtension() {}
+
+ 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;
+ virtual int SpaceUsed() const = 0;
+
+ virtual void MergeFrom(const LazyMessageExtension& other) = 0;
+ virtual void Clear() = 0;
+
+ virtual bool ReadMessage(const MessageLite& prototype,
+ io::CodedInputStream* input) = 0;
+ virtual void WriteMessage(int number,
+ io::CodedOutputStream* output) const = 0;
+ virtual uint8* WriteMessageToArray(int number, uint8* target) const = 0;
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension);
+ };
struct Extension {
+ // The order of these fields packs Extension into 24 bytes when using 8
+ // byte alignment. Consider this when adding or removing fields here.
union {
- int32 int32_value;
- int64 int64_value;
- uint32 uint32_value;
- uint64 uint64_value;
- float float_value;
- double double_value;
- bool bool_value;
- int enum_value;
- string* string_value;
- MessageLite* message_value;
+ int32 int32_value;
+ int64 int64_value;
+ uint32 uint32_value;
+ uint64 uint64_value;
+ float float_value;
+ double double_value;
+ bool bool_value;
+ int enum_value;
+ string* string_value;
+ MessageLite* message_value;
+ LazyMessageExtension* lazymessage_value;
RepeatedField <int32 >* repeated_int32_value;
RepeatedField <int64 >* repeated_int64_value;
@@ -416,21 +488,28 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// removing it from the map, we just set is_cleared = true. This has no
// meaning for repeated types; for those, the size of the RepeatedField
// simply becomes zero when cleared.
- bool is_cleared;
+ bool is_cleared : 4;
+
+ // For singular message types, indicates whether lazy parsing is enabled
+ // for this extension. This field is only valid when type == TYPE_MESSAGE
+ // and !is_repeated because we only support lazy parsing for singular
+ // message types currently. If is_lazy = true, the extension is stored in
+ // lazymessage_value. Otherwise, the extension will be message_value.
+ bool is_lazy : 4;
// For repeated types, this indicates if the [packed=true] option is set.
bool is_packed;
- // The descriptor for this extension, if one exists and is known. May be
- // NULL. Must not be NULL if the descriptor for the extension does not
- // live in the same pool as the descriptor for the containing type.
- const FieldDescriptor* descriptor;
-
// For packed fields, the size of the packed data is recorded here when
// ByteSize() is called then used during serialization.
// TODO(kenton): Use atomic<int> when C++ supports it.
mutable int cached_size;
+ // The descriptor for this extension, if one exists and is known. May be
+ // NULL. Must not be NULL if the descriptor for the extension does not
+ // live in the same pool as the descriptor for the containing type.
+ const FieldDescriptor* descriptor;
+
// Some helper methods for operations on a single Extension.
void SerializeFieldWithCachedSizes(
int number,
@@ -453,6 +532,43 @@ 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
+ // extension->is_packed (whether packed=true is specified).
+ bool FindExtensionInfoFromTag(uint32 tag, ExtensionFinder* extension_finder,
+ int* field_number, ExtensionInfo* extension,
+ bool* was_packed_on_wire);
+
+ // Returns true and fills 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
+ // extension->is_packed (whether packed=true is specified).
+ bool FindExtensionInfoFromFieldNumber(int wire_type, int field_number,
+ ExtensionFinder* extension_finder,
+ ExtensionInfo* extension,
+ bool* was_packed_on_wire);
+
+ // Parses a single extension from the input. The input should start out
+ // positioned immediately after the wire tag. This method is called in
+ // ParseField() after field number and was_packed_on_wire is extracted from
+ // the wire tag and ExtensionInfo is found by the field number.
+ bool ParseFieldWithExtensionInfo(int field_number,
+ bool was_packed_on_wire,
+ const ExtensionInfo& extension,
+ io::CodedInputStream* input,
+ FieldSkipper* field_skipper);
+
+ // Like ParseField(), but this method may parse singular message extensions
+ // lazily depending on the value of FLAGS_eagerly_parse_message_sets.
+ bool ParseFieldMaybeLazily(int wire_type, int field_number,
+ io::CodedInputStream* input,
+ ExtensionFinder* extension_finder,
+ MessageSetFieldSkipper* field_skipper);
+
// Gets the extension with the given number, creating it if it does not
// already exist. Returns true if the extension did not already exist.
bool MaybeNewExtension(int number, const FieldDescriptor* descriptor,
@@ -462,8 +578,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// tag has been read.
bool ParseMessageSetItem(io::CodedInputStream* input,
ExtensionFinder* extension_finder,
- FieldSkipper* field_skipper);
-
+ MessageSetFieldSkipper* field_skipper);
// Hack: RepeatedPtrFieldBase declares ExtensionSet as a friend. This
// friendship should automatically extend to ExtensionSet::Extension, but
@@ -481,8 +596,8 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// only contain a small number of extensions whereas hash_map is optimized
// for 100 elements or more. Also, we want AppendToList() to order fields
// by field number.
- map<int, Extension> extensions_;
-
+ std::map<int, Extension> extensions_;
+ ::google::protobuf::Arena* arena_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
};
@@ -517,6 +632,16 @@ inline void ExtensionSet::AddString(int number, FieldType type,
// public:
// typedef ? ConstType;
// typedef ? MutableType;
+// // TypeTraits for singular fields and repeated fields will define the
+// // symbol "Singular" or "Repeated" respectively. These two symbols will
+// // be used in extension accessors to distinguish between singular
+// // extensions and repeated extensions. If the TypeTraits for the passed
+// // in extension doesn't have the expected symbol defined, it means the
+// // user is passing a repeated extension to a singular accessor, or the
+// // opposite. In that case the C++ compiler will generate an error
+// // message "no matching member function" to inform the user.
+// typedef ? Singular
+// typedef ? Repeated
//
// static inline ConstType Get(int number, const ExtensionSet& set);
// static inline void Set(int number, ConstType value, ExtensionSet* set);
@@ -555,6 +680,8 @@ template <typename Type>
class PrimitiveTypeTraits {
public:
typedef Type ConstType;
+ typedef Type MutableType;
+ typedef PrimitiveTypeTraits<Type> Singular;
static inline ConstType Get(int number, const ExtensionSet& set,
ConstType default_value);
@@ -566,11 +693,41 @@ template <typename Type>
class RepeatedPrimitiveTypeTraits {
public:
typedef Type ConstType;
+ typedef Type MutableType;
+ typedef RepeatedPrimitiveTypeTraits<Type> Repeated;
+
+ typedef RepeatedField<Type> RepeatedFieldType;
static inline Type Get(int number, const ExtensionSet& set, int index);
static inline void Set(int number, int index, Type value, ExtensionSet* set);
static inline void Add(int number, FieldType field_type,
bool is_packed, Type value, ExtensionSet* set);
+
+ static inline const RepeatedField<ConstType>&
+ GetRepeated(int number, const ExtensionSet& set);
+ static inline RepeatedField<Type>*
+ MutableRepeated(int number, FieldType field_type,
+ bool is_packed, ExtensionSet* set);
+
+ static const RepeatedFieldType* GetDefaultRepeatedField();
+};
+
+// Declared here so that this can be friended below.
+void InitializeDefaultRepeatedFields();
+void DestroyDefaultRepeatedFields();
+
+class LIBPROTOBUF_EXPORT RepeatedPrimitiveGenericTypeTraits {
+ private:
+ template<typename Type> friend class RepeatedPrimitiveTypeTraits;
+ friend void InitializeDefaultRepeatedFields();
+ friend void DestroyDefaultRepeatedFields();
+ static const RepeatedField<int32>* default_repeated_field_int32_;
+ static const RepeatedField<int64>* default_repeated_field_int64_;
+ static const RepeatedField<uint32>* default_repeated_field_uint32_;
+ static const RepeatedField<uint64>* default_repeated_field_uint64_;
+ static const RepeatedField<double>* default_repeated_field_double_;
+ static const RepeatedField<float>* default_repeated_field_float_;
+ static const RepeatedField<bool>* default_repeated_field_bool_;
};
#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \
@@ -595,6 +752,26 @@ template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Add( \
int number, FieldType field_type, bool is_packed, \
TYPE value, ExtensionSet* set) { \
set->Add##METHOD(number, field_type, is_packed, value, NULL); \
+} \
+template<> inline const RepeatedField<TYPE>* \
+ RepeatedPrimitiveTypeTraits<TYPE>::GetDefaultRepeatedField() { \
+ return RepeatedPrimitiveGenericTypeTraits:: \
+ default_repeated_field_##TYPE##_; \
+} \
+template<> inline const RepeatedField<TYPE>& \
+ RepeatedPrimitiveTypeTraits<TYPE>::GetRepeated(int number, \
+ const ExtensionSet& set) { \
+ return *reinterpret_cast<const RepeatedField<TYPE>*>( \
+ set.GetRawRepeatedField( \
+ number, GetDefaultRepeatedField())); \
+} \
+template<> inline RepeatedField<TYPE>* \
+ RepeatedPrimitiveTypeTraits<TYPE>::MutableRepeated(int number, \
+ FieldType field_type, \
+ bool is_packed, \
+ ExtensionSet* set) { \
+ return reinterpret_cast<RepeatedField<TYPE>*>( \
+ set->MutableRawRepeatedField(number, field_type, is_packed, NULL)); \
}
PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32)
@@ -615,6 +792,7 @@ class LIBPROTOBUF_EXPORT StringTypeTraits {
public:
typedef const string& ConstType;
typedef string* MutableType;
+ typedef StringTypeTraits Singular;
static inline const string& Get(int number, const ExtensionSet& set,
ConstType default_value) {
@@ -634,6 +812,9 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
public:
typedef const string& ConstType;
typedef string* MutableType;
+ typedef RepeatedStringTypeTraits Repeated;
+
+ typedef RepeatedPtrField<string> RepeatedFieldType;
static inline const string& Get(int number, const ExtensionSet& set,
int index) {
@@ -655,6 +836,28 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
ExtensionSet* set) {
return set->AddString(number, field_type, NULL);
}
+ static inline const RepeatedPtrField<string>&
+ GetRepeated(int number, const ExtensionSet& set) {
+ return *reinterpret_cast<const RepeatedPtrField<string>*>(
+ set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
+ }
+
+ static inline RepeatedPtrField<string>*
+ MutableRepeated(int number, FieldType field_type,
+ bool is_packed, ExtensionSet* set) {
+ return reinterpret_cast<RepeatedPtrField<string>*>(
+ set->MutableRawRepeatedField(number, field_type,
+ is_packed, NULL));
+ }
+
+ static const RepeatedFieldType* GetDefaultRepeatedField() {
+ return default_repeated_field_;
+ }
+
+ private:
+ friend void InitializeDefaultRepeatedFields();
+ friend void DestroyDefaultRepeatedFields();
+ static const RepeatedFieldType *default_repeated_field_;
};
// -------------------------------------------------------------------
@@ -666,6 +869,8 @@ template <typename Type, bool IsValid(int)>
class EnumTypeTraits {
public:
typedef Type ConstType;
+ typedef Type MutableType;
+ typedef EnumTypeTraits<Type, IsValid> Singular;
static inline ConstType Get(int number, const ExtensionSet& set,
ConstType default_value) {
@@ -682,6 +887,10 @@ template <typename Type, bool IsValid(int)>
class RepeatedEnumTypeTraits {
public:
typedef Type ConstType;
+ typedef Type MutableType;
+ typedef RepeatedEnumTypeTraits<Type, IsValid> Repeated;
+
+ typedef RepeatedField<Type> RepeatedFieldType;
static inline ConstType Get(int number, const ExtensionSet& set, int index) {
return static_cast<Type>(set.GetRepeatedEnum(number, index));
@@ -696,6 +905,35 @@ class RepeatedEnumTypeTraits {
GOOGLE_DCHECK(IsValid(value));
set->AddEnum(number, field_type, is_packed, value, NULL);
}
+ static inline const RepeatedField<Type>& GetRepeated(int number,
+ const ExtensionSet&
+ set) {
+ // Hack: the `Extension` struct stores a RepeatedField<int> for enums.
+ // RepeatedField<int> cannot implicitly convert to RepeatedField<EnumType>
+ // so we need to do some casting magic. See message.h for similar
+ // contortions for non-extension fields.
+ return *reinterpret_cast<const RepeatedField<Type>*>(
+ set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
+ }
+
+ static inline RepeatedField<Type>* MutableRepeated(int number,
+ FieldType field_type,
+ bool is_packed,
+ ExtensionSet* set) {
+ return reinterpret_cast<RepeatedField<Type>*>(
+ set->MutableRawRepeatedField(number, field_type, is_packed, NULL));
+ }
+
+ static const RepeatedFieldType* GetDefaultRepeatedField() {
+ // Hack: as noted above, repeated enum fields are internally stored as a
+ // RepeatedField<int>. We need to be able to instantiate global static
+ // objects to return as default (empty) repeated fields on non-existent
+ // extensions. We would not be able to know a-priori all of the enum types
+ // (values of |Type|) to instantiate all of these, so we just re-use int32's
+ // default repeated field object.
+ return reinterpret_cast<const RepeatedField<Type>*>(
+ RepeatedPrimitiveTypeTraits<int32>::GetDefaultRepeatedField());
+ }
};
// -------------------------------------------------------------------
@@ -709,6 +947,7 @@ class MessageTypeTraits {
public:
typedef const Type& ConstType;
typedef Type* MutableType;
+ typedef MessageTypeTraits<Type> Singular;
static inline ConstType Get(int number, const ExtensionSet& set,
ConstType default_value) {
@@ -720,13 +959,28 @@ class MessageTypeTraits {
return static_cast<Type*>(
set->MutableMessage(number, field_type, Type::default_instance(), NULL));
}
+ static inline void SetAllocated(int number, FieldType field_type,
+ MutableType message, ExtensionSet* set) {
+ set->SetAllocatedMessage(number, field_type, NULL, message);
+ }
+ static inline MutableType Release(int number, FieldType /* field_type */,
+ ExtensionSet* set) {
+ return static_cast<Type*>(set->ReleaseMessage(
+ number, Type::default_instance()));
+ }
};
+// forward declaration
+class RepeatedMessageGenericTypeTraits;
+
template <typename Type>
class RepeatedMessageTypeTraits {
public:
typedef const Type& ConstType;
typedef Type* MutableType;
+ typedef RepeatedMessageTypeTraits<Type> Repeated;
+
+ typedef RepeatedPtrField<Type> RepeatedFieldType;
static inline ConstType Get(int number, const ExtensionSet& set, int index) {
return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
@@ -739,8 +993,47 @@ class RepeatedMessageTypeTraits {
return static_cast<Type*>(
set->AddMessage(number, field_type, Type::default_instance(), NULL));
}
+ static inline const RepeatedPtrField<Type>& GetRepeated(int number,
+ const ExtensionSet&
+ set) {
+ // See notes above in RepeatedEnumTypeTraits::GetRepeated(): same
+ // casting hack applies here, because a RepeatedPtrField<MessageLite>
+ // cannot naturally become a RepeatedPtrType<Type> even though Type is
+ // presumably a message. google::protobuf::Message goes through similar contortions
+ // with a reinterpret_cast<>.
+ return *reinterpret_cast<const RepeatedPtrField<Type>*>(
+ set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
+ }
+ static inline RepeatedPtrField<Type>* MutableRepeated(int number,
+ FieldType field_type,
+ bool is_packed,
+ ExtensionSet* set) {
+ return reinterpret_cast<RepeatedPtrField<Type>*>(
+ set->MutableRawRepeatedField(number, field_type, is_packed, NULL));
+ }
+
+ static const RepeatedFieldType* GetDefaultRepeatedField();
};
+// This class exists only to hold a generic default empty repeated field for all
+// message-type repeated field extensions.
+class LIBPROTOBUF_EXPORT RepeatedMessageGenericTypeTraits {
+ public:
+ typedef RepeatedPtrField< ::google::protobuf::MessageLite*> RepeatedFieldType;
+ private:
+ template<typename Type> friend class RepeatedMessageTypeTraits;
+ friend void InitializeDefaultRepeatedFields();
+ friend void DestroyDefaultRepeatedFields();
+ static const RepeatedFieldType* default_repeated_field_;
+};
+
+template<typename Type> inline
+ const typename RepeatedMessageTypeTraits<Type>::RepeatedFieldType*
+ RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() {
+ return reinterpret_cast<const RepeatedFieldType*>(
+ RepeatedMessageGenericTypeTraits::default_repeated_field_);
+}
+
// -------------------------------------------------------------------
// ExtensionIdentifier
@@ -787,114 +1080,161 @@ class ExtensionIdentifier {
// causes problems if the class has a nested message or enum type with that
// name and "_TypeTraits" is technically reserved for the C++ library since
// it starts with an underscore followed by a capital letter.
+//
+// For similar reason, we use "_field_type" and "_is_packed" as parameter names
+// below, so that "field_type" and "is_packed" can be used as field names.
#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME) \
/* Has, Size, Clear */ \
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline bool HasExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
return _extensions_.Has(id.number()); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline void ClearExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
_extensions_.ClearExtension(id.number()); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline int ExtensionSize( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
return _extensions_.ExtensionSize(id.number()); \
} \
\
/* Singular accessors */ \
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
- inline typename _proto_TypeTraits::ConstType GetExtension( \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline typename _proto_TypeTraits::Singular::ConstType GetExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
return _proto_TypeTraits::Get(id.number(), _extensions_, \
id.default_value()); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
- inline typename _proto_TypeTraits::MutableType MutableExtension( \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline typename _proto_TypeTraits::Singular::MutableType MutableExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
- return _proto_TypeTraits::Mutable(id.number(), field_type, &_extensions_);\
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
+ return _proto_TypeTraits::Mutable(id.number(), _field_type, \
+ &_extensions_); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline void SetExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
- typename _proto_TypeTraits::ConstType value) { \
- _proto_TypeTraits::Set(id.number(), field_type, value, &_extensions_); \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
+ typename _proto_TypeTraits::Singular::ConstType value) { \
+ _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_); \
+ } \
+ \
+ template <typename _proto_TypeTraits, \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline void SetAllocatedExtension( \
+ const ::google::protobuf::internal::ExtensionIdentifier< \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
+ typename _proto_TypeTraits::Singular::MutableType value) { \
+ _proto_TypeTraits::SetAllocated(id.number(), _field_type, \
+ value, &_extensions_); \
+ } \
+ template <typename _proto_TypeTraits, \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline typename _proto_TypeTraits::Singular::MutableType ReleaseExtension( \
+ const ::google::protobuf::internal::ExtensionIdentifier< \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
+ return _proto_TypeTraits::Release(id.number(), _field_type, \
+ &_extensions_); \
} \
\
/* Repeated accessors */ \
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
- inline typename _proto_TypeTraits::ConstType GetExtension( \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline typename _proto_TypeTraits::Repeated::ConstType GetExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
int index) const { \
return _proto_TypeTraits::Get(id.number(), _extensions_, index); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
- inline typename _proto_TypeTraits::MutableType MutableExtension( \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
int index) { \
return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline void SetExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
- int index, typename _proto_TypeTraits::ConstType value) { \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
+ int index, typename _proto_TypeTraits::Repeated::ConstType value) { \
_proto_TypeTraits::Set(id.number(), index, value, &_extensions_); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
- inline typename _proto_TypeTraits::MutableType AddExtension( \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline typename _proto_TypeTraits::Repeated::MutableType AddExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
- return _proto_TypeTraits::Add(id.number(), field_type, &_extensions_); \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
+ return _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_); \
} \
\
template <typename _proto_TypeTraits, \
- ::google::protobuf::internal::FieldType field_type, \
- bool is_packed> \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline void AddExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
- CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
- typename _proto_TypeTraits::ConstType value) { \
- _proto_TypeTraits::Add(id.number(), field_type, is_packed, \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
+ typename _proto_TypeTraits::Repeated::ConstType value) { \
+ _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, \
value, &_extensions_); \
+ } \
+ \
+ template <typename _proto_TypeTraits, \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType& \
+ GetRepeatedExtension( \
+ const ::google::protobuf::internal::ExtensionIdentifier< \
+ CLASSNAME, _proto_TypeTraits, _field_type, \
+ _is_packed>& id) const { \
+ return _proto_TypeTraits::GetRepeated(id.number(), _extensions_); \
+ } \
+ \
+ template <typename _proto_TypeTraits, \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline typename _proto_TypeTraits::Repeated::RepeatedFieldType* \
+ MutableRepeatedExtension( \
+ const ::google::protobuf::internal::ExtensionIdentifier< \
+ CLASSNAME, _proto_TypeTraits, _field_type, \
+ _is_packed>& id) { \
+ return _proto_TypeTraits::MutableRepeated(id.number(), _field_type, \
+ _is_packed, &_extensions_); \
}
} // namespace internal
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 2721f15d..796e7a5f 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,17 +35,43 @@
// Contains methods defined in extension_set.h which cannot be part of the
// lite library because they use descriptors or reflection.
-#include <google/protobuf/extension_set.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/extension_set.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
+
namespace protobuf {
namespace internal {
+// A FieldSkipper used to store unknown MessageSet fields into UnknownFieldSet.
+class MessageSetFieldSkipper
+ : public UnknownFieldSetFieldSkipper {
+ public:
+ explicit MessageSetFieldSkipper(UnknownFieldSet* unknown_fields)
+ : UnknownFieldSetFieldSkipper(unknown_fields) {}
+ virtual ~MessageSetFieldSkipper() {}
+
+ virtual bool SkipMessageSetField(io::CodedInputStream* input,
+ int field_number);
+};
+bool MessageSetFieldSkipper::SkipMessageSetField(
+ io::CodedInputStream* input, int field_number) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ if (unknown_fields_ == NULL) {
+ return input->Skip(length);
+ } else {
+ return input->ReadString(
+ unknown_fields_->AddLengthDelimited(field_number), length);
+ }
+}
+
+
// Implementation of ExtensionFinder which finds extensions in a given
// DescriptorPool, using the given MessageFactory to construct sub-objects.
// This class is implemented in extension_set_heavy.cc.
@@ -65,9 +91,10 @@ class DescriptorPoolExtensionFinder : public ExtensionFinder {
const Descriptor* containing_type_;
};
-void ExtensionSet::AppendToList(const Descriptor* containing_type,
- const DescriptorPool* pool,
- vector<const FieldDescriptor*>* output) const {
+void ExtensionSet::AppendToList(
+ const Descriptor* containing_type,
+ const DescriptorPool* pool,
+ std::vector<const FieldDescriptor*>* output) const {
for (map<int, Extension>::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
bool has = false;
@@ -103,6 +130,11 @@ inline FieldDescriptor::CppType cpp_type(FieldType type) {
static_cast<FieldDescriptor::Type>(type));
}
+inline WireFormatLite::FieldType field_type(FieldType type) {
+ GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE);
+ return static_cast<WireFormatLite::FieldType>(type);
+}
+
#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \
GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \
: FieldDescriptor::LABEL_OPTIONAL, \
@@ -118,7 +150,12 @@ const MessageLite& ExtensionSet::GetMessage(int number,
return *factory->GetPrototype(message_type);
} else {
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
- return *iter->second.message_value;
+ if (iter->second.is_lazy) {
+ return iter->second.lazymessage_value->GetMessage(
+ *factory->GetPrototype(message_type));
+ } else {
+ return *iter->second.message_value;
+ }
}
}
@@ -132,13 +169,48 @@ MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
extension->is_packed = false;
const MessageLite* prototype =
factory->GetPrototype(descriptor->message_type());
- GOOGLE_CHECK(prototype != NULL);
- extension->message_value = prototype->New();
+ extension->is_lazy = false;
+ extension->message_value = prototype->New(arena_);
+ extension->is_cleared = false;
+ return extension->message_value;
} else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+ extension->is_cleared = false;
+ if (extension->is_lazy) {
+ return extension->lazymessage_value->MutableMessage(
+ *factory->GetPrototype(descriptor->message_type()));
+ } else {
+ return extension->message_value;
+ }
+ }
+}
+
+MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
+ MessageFactory* factory) {
+ map<int, Extension>::iterator iter = extensions_.find(descriptor->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->ReleaseMessage(
+ *factory->GetPrototype(descriptor->message_type()));
+ if (arena_ == NULL) {
+ delete iter->second.lazymessage_value;
+ }
+ } else {
+ 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;
}
- extension->is_cleared = false;
- return extension->message_value;
}
MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
@@ -149,7 +221,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<MessageLite>();
+ ::google::protobuf::Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
} else {
GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
}
@@ -157,7 +229,7 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
// RepeatedPtrField<Message> does not know how to Add() since it cannot
// allocate an abstract object, so we have to be tricky.
MessageLite* result = extension->repeated_message_value
- ->AddFromCleared<internal::GenericTypeHandler<MessageLite> >();
+ ->AddFromCleared<GenericTypeHandler<MessageLite> >();
if (result == NULL) {
const MessageLite* prototype;
if (extension->repeated_message_value->size() == 0) {
@@ -166,7 +238,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;
@@ -220,7 +292,7 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
const Message* containing_type,
UnknownFieldSet* unknown_fields) {
- UnknownFieldSetFieldSkipper skipper(unknown_fields);
+ MessageSetFieldSkipper skipper(unknown_fields);
if (input->GetExtensionPool() == NULL) {
GeneratedExtensionFinder finder(containing_type);
return ParseMessageSet(input, &finder, &skipper);
@@ -286,7 +358,11 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const {
StringSpaceUsedExcludingSelf(*string_value);
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
- total_size += down_cast<Message*>(message_value)->SpaceUsed();
+ if (is_lazy) {
+ total_size += lazymessage_value->SpaceUsed();
+ } else {
+ total_size += down_cast<Message*>(message_value)->SpaceUsed();
+ }
break;
default:
// No extra storage costs for primitive types.
@@ -419,8 +495,15 @@ uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
HANDLE_TYPE( BYTES, Bytes, *string_value);
HANDLE_TYPE( ENUM, Enum, enum_value);
HANDLE_TYPE( GROUP, Group, *message_value);
- HANDLE_TYPE( MESSAGE, Message, *message_value);
#undef HANDLE_TYPE
+ case FieldDescriptor::TYPE_MESSAGE:
+ if (is_lazy) {
+ target = lazymessage_value->WriteMessageToArray(number, target);
+ } else {
+ target = WireFormatLite::WriteMessageToArray(
+ number, *message_value, target);
+ }
+ break;
}
}
return target;
@@ -444,14 +527,216 @@ uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray(
target = WireFormatLite::WriteUInt32ToArray(
WireFormatLite::kMessageSetTypeIdNumber, number, target);
// Write message.
- target = WireFormatLite::WriteMessageToArray(
- WireFormatLite::kMessageSetMessageNumber, *message_value, target);
+ if (is_lazy) {
+ target = lazymessage_value->WriteMessageToArray(
+ WireFormatLite::kMessageSetMessageNumber, target);
+ } else {
+ target = WireFormatLite::WriteMessageToArray(
+ WireFormatLite::kMessageSetMessageNumber, *message_value, target);
+ }
// End group.
target = io::CodedOutputStream::WriteTagToArray(
WireFormatLite::kMessageSetItemEndTag, target);
return target;
}
+
+bool ExtensionSet::ParseFieldMaybeLazily(
+ int wire_type, int field_number, io::CodedInputStream* input,
+ ExtensionFinder* extension_finder,
+ MessageSetFieldSkipper* field_skipper) {
+ return ParseField(WireFormatLite::MakeTag(
+ field_number, static_cast<WireFormatLite::WireType>(wire_type)),
+ input, extension_finder, field_skipper);
+}
+
+bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
+ ExtensionFinder* extension_finder,
+ MessageSetFieldSkipper* field_skipper) {
+ while (true) {
+ const uint32 tag = input->ReadTag();
+ switch (tag) {
+ case 0:
+ return true;
+ case WireFormatLite::kMessageSetItemStartTag:
+ if (!ParseMessageSetItem(input, extension_finder, field_skipper)) {
+ return false;
+ }
+ break;
+ default:
+ if (!ParseField(tag, input, extension_finder, field_skipper)) {
+ return false;
+ }
+ break;
+ }
+ }
+}
+
+bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
+ const MessageLite* containing_type) {
+ MessageSetFieldSkipper skipper(NULL);
+ GeneratedExtensionFinder finder(containing_type);
+ return ParseMessageSet(input, &finder, &skipper);
+}
+
+bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input,
+ ExtensionFinder* extension_finder,
+ MessageSetFieldSkipper* field_skipper) {
+ // TODO(kenton): It would be nice to share code between this and
+ // WireFormatLite::ParseAndMergeMessageSetItem(), but I think the
+ // differences would be hard to factor out.
+
+ // This method parses a group which should contain two fields:
+ // required int32 type_id = 2;
+ // required data message = 3;
+
+ uint32 last_type_id = 0;
+
+ // If we see message data before the type_id, we'll append it to this so
+ // we can parse it later.
+ string message_data;
+
+ while (true) {
+ const uint32 tag = input->ReadTag();
+ if (tag == 0) return false;
+
+ switch (tag) {
+ case WireFormatLite::kMessageSetTypeIdTag: {
+ uint32 type_id;
+ if (!input->ReadVarint32(&type_id)) return false;
+ last_type_id = type_id;
+
+ if (!message_data.empty()) {
+ // We saw some message data before the type_id. Have to parse it
+ // now.
+ io::CodedInputStream sub_input(
+ reinterpret_cast<const uint8*>(message_data.data()),
+ message_data.size());
+ if (!ParseFieldMaybeLazily(WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+ last_type_id, &sub_input,
+ extension_finder, field_skipper)) {
+ return false;
+ }
+ message_data.clear();
+ }
+
+ break;
+ }
+
+ case WireFormatLite::kMessageSetMessageTag: {
+ if (last_type_id == 0) {
+ // We haven't seen a type_id yet. Append this data to message_data.
+ string temp;
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ if (!input->ReadString(&temp, length)) return false;
+ io::StringOutputStream output_stream(&message_data);
+ io::CodedOutputStream coded_output(&output_stream);
+ coded_output.WriteVarint32(length);
+ coded_output.WriteString(temp);
+ } else {
+ // Already saw type_id, so we can parse this directly.
+ if (!ParseFieldMaybeLazily(WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+ last_type_id, input,
+ extension_finder, field_skipper)) {
+ return false;
+ }
+ }
+
+ break;
+ }
+
+ case WireFormatLite::kMessageSetItemEndTag: {
+ return true;
+ }
+
+ default: {
+ if (!field_skipper->SkipField(input, tag)) return false;
+ }
+ }
+ }
+}
+
+void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes(
+ int number,
+ io::CodedOutputStream* output) const {
+ if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
+ // Not a valid MessageSet extension, but serialize it the normal way.
+ SerializeFieldWithCachedSizes(number, output);
+ return;
+ }
+
+ if (is_cleared) return;
+
+ // Start group.
+ output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
+
+ // Write type ID.
+ WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
+ number,
+ output);
+ // Write message.
+ if (is_lazy) {
+ lazymessage_value->WriteMessage(
+ WireFormatLite::kMessageSetMessageNumber, output);
+ } else {
+ WireFormatLite::WriteMessageMaybeToArray(
+ WireFormatLite::kMessageSetMessageNumber,
+ *message_value,
+ output);
+ }
+
+ // End group.
+ output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
+}
+
+int ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
+ if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
+ // Not a valid MessageSet extension, but compute the byte size for it the
+ // normal way.
+ return ByteSize(number);
+ }
+
+ if (is_cleared) return 0;
+
+ int our_size = WireFormatLite::kMessageSetItemTagsSize;
+
+ // type_id
+ our_size += io::CodedOutputStream::VarintSize32(number);
+
+ // message
+ int message_size = 0;
+ if (is_lazy) {
+ message_size = lazymessage_value->ByteSize();
+ } else {
+ message_size = message_value->ByteSize();
+ }
+
+ our_size += io::CodedOutputStream::VarintSize32(message_size);
+ our_size += message_size;
+
+ return our_size;
+}
+
+void ExtensionSet::SerializeMessageSetWithCachedSizes(
+ io::CodedOutputStream* output) const {
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output);
+ }
+}
+
+int ExtensionSet::MessageSetByteSize() const {
+ int total_size = 0;
+
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ total_size += iter->second.MessageSetItemByteSize(iter->first);
+ }
+
+ return total_size;
+}
+
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
index 000f846c..684ce002 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,8 +34,10 @@
#include <google/protobuf/extension_set.h>
#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_mset.pb.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/arena.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/wire_format.h>
@@ -46,9 +48,10 @@
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
+
namespace protobuf {
namespace internal {
namespace {
@@ -140,23 +143,98 @@ TEST(ExtensionSetTest, ClearOneField) {
TestUtil::ExpectAllExtensionsSet(message);
}
+TEST(ExtensionSetTest, SetAllocatedExtension) {
+ unittest::TestAllExtensions message;
+ 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);
+ EXPECT_TRUE(message.HasExtension(
+ unittest::optional_foreign_message_extension));
+ EXPECT_EQ(foreign_message,
+ message.MutableExtension(
+ unittest::optional_foreign_message_extension));
+ EXPECT_EQ(foreign_message,
+ &message.GetExtension(
+ unittest::optional_foreign_message_extension));
+
+ // SetAllocatedExtension should delete the previously existing extension.
+ // (We reply on unittest to check memory leaks for this case)
+ message.SetAllocatedExtension(unittest::optional_foreign_message_extension,
+ new unittest::ForeignMessage());
+
+ // SetAllocatedExtension with a NULL parameter is equivalent to ClearExtenion.
+ message.SetAllocatedExtension(unittest::optional_foreign_message_extension,
+ NULL);
+ EXPECT_FALSE(message.HasExtension(
+ unittest::optional_foreign_message_extension));
+}
+
+TEST(ExtensionSetTest, ReleaseExtension) {
+ unittest::TestMessageSet message;
+ EXPECT_FALSE(message.HasExtension(
+ unittest::TestMessageSetExtension1::message_set_extension));
+ // Add a extension using SetAllocatedExtension
+ unittest::TestMessageSetExtension1* extension =
+ new unittest::TestMessageSetExtension1();
+ message.SetAllocatedExtension(
+ unittest::TestMessageSetExtension1::message_set_extension,
+ extension);
+ EXPECT_TRUE(message.HasExtension(
+ unittest::TestMessageSetExtension1::message_set_extension));
+ // Release the extension using ReleaseExtension
+ unittest::TestMessageSetExtension1* released_extension =
+ message.ReleaseExtension(
+ unittest::TestMessageSetExtension1::message_set_extension);
+ EXPECT_EQ(extension, released_extension);
+ EXPECT_FALSE(message.HasExtension(
+ unittest::TestMessageSetExtension1::message_set_extension));
+ // ReleaseExtension will return the underlying object even after
+ // ClearExtension is called.
+ message.SetAllocatedExtension(
+ unittest::TestMessageSetExtension1::message_set_extension,
+ extension);
+ message.ClearExtension(
+ unittest::TestMessageSetExtension1::message_set_extension);
+ released_extension = message.ReleaseExtension(
+ unittest::TestMessageSetExtension1::message_set_extension);
+ EXPECT_TRUE(released_extension != NULL);
+ delete released_extension;
+}
+
+
TEST(ExtensionSetTest, CopyFrom) {
unittest::TestAllExtensions message1, message2;
- string data;
TestUtil::SetAllExtensions(&message1);
message2.CopyFrom(message1);
TestUtil::ExpectAllExtensionsSet(message2);
+ message2.CopyFrom(message1); // exercise copy when fields already exist
+ TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensioSetTest, CopyFromPacked) {
+ unittest::TestPackedExtensions message1, message2;
+
+ TestUtil::SetPackedExtensions(&message1);
+ message2.CopyFrom(message1);
+ TestUtil::ExpectPackedExtensionsSet(message2);
+ message2.CopyFrom(message1); // exercise copy when fields already exist
+ TestUtil::ExpectPackedExtensionsSet(message2);
}
TEST(ExtensionSetTest, CopyFromUpcasted) {
unittest::TestAllExtensions message1, message2;
- string data;
const Message& upcasted_message = message1;
TestUtil::SetAllExtensions(&message1);
message2.CopyFrom(upcasted_message);
TestUtil::ExpectAllExtensionsSet(message2);
+ // exercise copy when fields already exist
+ message2.CopyFrom(upcasted_message);
+ TestUtil::ExpectAllExtensionsSet(message2);
}
TEST(ExtensionSetTest, SwapWithEmpty) {
@@ -179,6 +257,193 @@ TEST(ExtensionSetTest, SwapWithSelf) {
TestUtil::ExpectAllExtensionsSet(message);
}
+TEST(ExtensionSetTest, SwapExtension) {
+ unittest::TestAllExtensions message1;
+ unittest::TestAllExtensions message2;
+
+ TestUtil::SetAllExtensions(&message1);
+ vector<const FieldDescriptor*> fields;
+
+ // Swap empty fields.
+ const Reflection* reflection = message1.GetReflection();
+ reflection->SwapFields(&message1, &message2, fields);
+ TestUtil::ExpectAllExtensionsSet(message1);
+ TestUtil::ExpectExtensionsClear(message2);
+
+ // Swap two extensions.
+ fields.push_back(
+ reflection->FindKnownExtensionByNumber(12));
+ fields.push_back(
+ reflection->FindKnownExtensionByNumber(25));
+ reflection->SwapFields(&message1, &message2, fields);
+
+ EXPECT_TRUE(message1.HasExtension(unittest::optional_int32_extension));
+ EXPECT_FALSE(message1.HasExtension(unittest::optional_double_extension));
+ EXPECT_FALSE(message1.HasExtension(unittest::optional_cord_extension));
+
+ EXPECT_FALSE(message2.HasExtension(unittest::optional_int32_extension));
+ EXPECT_TRUE(message2.HasExtension(unittest::optional_double_extension));
+ EXPECT_TRUE(message2.HasExtension(unittest::optional_cord_extension));
+}
+
+TEST(ExtensionSetTest, SwapExtensionWithEmpty) {
+ unittest::TestAllExtensions message1;
+ unittest::TestAllExtensions message2;
+ unittest::TestAllExtensions message3;
+
+ TestUtil::SetAllExtensions(&message3);
+
+ const Reflection* reflection = message3.GetReflection();
+ vector<const FieldDescriptor*> fields;
+ reflection->ListFields(message3, &fields);
+
+ reflection->SwapFields(&message1, &message2, fields);
+
+ TestUtil::ExpectExtensionsClear(message1);
+ TestUtil::ExpectExtensionsClear(message2);
+}
+
+TEST(ExtensionSetTest, SwapExtensionBothFull) {
+ unittest::TestAllExtensions message1;
+ unittest::TestAllExtensions message2;
+
+ TestUtil::SetAllExtensions(&message1);
+ TestUtil::SetAllExtensions(&message2);
+
+ const Reflection* reflection = message1.GetReflection();
+ vector<const FieldDescriptor*> fields;
+ reflection->ListFields(message1, &fields);
+
+ reflection->SwapFields(&message1, &message2, fields);
+
+ TestUtil::ExpectAllExtensionsSet(message1);
+ TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, ArenaSetAllExtension) {
+ ::google::protobuf::Arena arena1;
+ unittest::TestAllExtensions* message1 =
+ ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+ TestUtil::SetAllExtensions(message1);
+ TestUtil::ExpectAllExtensionsSet(*message1);
+}
+
+TEST(ExtensionSetTest, ArenaCopyConstructor) {
+ ::google::protobuf::Arena arena1;
+ unittest::TestAllExtensions* message1 =
+ ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&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<unittest::TestAllExtensions>(&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<unittest::TestAllExtensions>(&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;
+ google::protobuf::scoped_ptr<google::protobuf::Arena> arena2(new ::google::protobuf::Arena());
+
+ unittest::TestAllExtensions* message1 =
+ Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+ unittest::TestAllExtensions* message2 =
+ Arena::CreateMessage<unittest::TestAllExtensions>(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<unittest::TestAllExtensions>(&arena3);
+ unittest::TestAllExtensions* message4 =
+ Arena::CreateMessage<unittest::TestAllExtensions>(&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<unittest::TestAllExtensions>(&arena1);
+ unittest::TestAllExtensions* message2 =
+ Arena::CreateMessage<unittest::TestAllExtensions>(arena2);
+
+ TestUtil::SetAllExtensions(message1);
+ TestUtil::SetAllExtensions(message2);
+
+ const Reflection* reflection = message1->GetReflection();
+ vector<const FieldDescriptor*> 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;
+
+ TestUtil::SetAllExtensions(&message1);
+
+ vector<const FieldDescriptor*> fields;
+ const Reflection* reflection = message1.GetReflection();
+ reflection->ListFields(message1, &fields);
+ reflection->SwapFields(&message1, &message1, fields);
+
+ TestUtil::ExpectAllExtensionsSet(message1);
+}
+
TEST(ExtensionSetTest, SerializationToArray) {
// Serialize as TestAllExtensions and parse as TestAllTypes to insure wire
// compatibility of extensions.
@@ -276,6 +541,7 @@ TEST(ExtensionSetTest, Parsing) {
TestUtil::SetAllFields(&source);
source.SerializeToString(&data);
EXPECT_TRUE(destination.ParseFromString(data));
+ TestUtil::SetOneofFields(&destination);
TestUtil::ExpectAllExtensionsSet(destination);
}
@@ -291,6 +557,48 @@ TEST(ExtensionSetTest, PackedParsing) {
TestUtil::ExpectPackedExtensionsSet(destination);
}
+TEST(ExtensionSetTest, PackedToUnpackedParsing) {
+ unittest::TestPackedTypes source;
+ unittest::TestUnpackedExtensions destination;
+ string data;
+
+ TestUtil::SetPackedFields(&source);
+ source.SerializeToString(&data);
+ EXPECT_TRUE(destination.ParseFromString(data));
+ TestUtil::ExpectUnpackedExtensionsSet(destination);
+
+ // Reserialize
+ unittest::TestUnpackedTypes unpacked;
+ TestUtil::SetUnpackedFields(&unpacked);
+ EXPECT_TRUE(unpacked.SerializeAsString() == destination.SerializeAsString());
+
+ // Make sure we can add extensions.
+ destination.AddExtension(unittest::unpacked_int32_extension, 1);
+ destination.AddExtension(unittest::unpacked_enum_extension,
+ protobuf_unittest::FOREIGN_BAR);
+}
+
+TEST(ExtensionSetTest, UnpackedToPackedParsing) {
+ unittest::TestUnpackedTypes source;
+ unittest::TestPackedExtensions destination;
+ string data;
+
+ TestUtil::SetUnpackedFields(&source);
+ source.SerializeToString(&data);
+ EXPECT_TRUE(destination.ParseFromString(data));
+ TestUtil::ExpectPackedExtensionsSet(destination);
+
+ // Reserialize
+ unittest::TestPackedTypes packed;
+ TestUtil::SetPackedFields(&packed);
+ EXPECT_TRUE(packed.SerializeAsString() == destination.SerializeAsString());
+
+ // Make sure we can add extensions.
+ destination.AddExtension(unittest::packed_int32_extension, 1);
+ destination.AddExtension(unittest::packed_enum_extension,
+ protobuf_unittest::FOREIGN_BAR);
+}
+
TEST(ExtensionSetTest, IsInitialized) {
// Test that IsInitialized() returns false if required fields in nested
// extensions are missing.
@@ -418,7 +726,8 @@ TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
for (int i = 0; i < 16; ++i) { \
message.AddExtension(unittest::repeated_##type##_extension, value); \
} \
- int expected_size = sizeof(cpptype) * 16 + empty_repeated_field_size; \
+ int expected_size = sizeof(cpptype) * (16 - \
+ kMinRepeatedFieldAllocationSize) + empty_repeated_field_size; \
EXPECT_EQ(expected_size, message.SpaceUsed()) << #type; \
} while (0)
@@ -450,7 +759,8 @@ TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
for (int i = 0; i < 16; ++i) {
message.AddExtension(unittest::repeated_string_extension, value);
}
- min_expected_size += (sizeof(value) + value.size()) * 16;
+ min_expected_size += (sizeof(value) + value.size()) *
+ (16 - kMinRepeatedFieldAllocationSize);
EXPECT_LE(min_expected_size, message.SpaceUsed());
}
// Repeated messages
@@ -465,12 +775,263 @@ TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
message.AddExtension(unittest::repeated_foreign_message_extension)->
CopyFrom(prototype);
}
- min_expected_size += 16 * prototype.SpaceUsed();
+ min_expected_size +=
+ (16 - kMinRepeatedFieldAllocationSize) * prototype.SpaceUsed();
EXPECT_LE(min_expected_size, message.SpaceUsed());
}
}
-#ifdef GTEST_HAS_DEATH_TEST
+// N.B.: We do not test range-based for here because we remain C++03 compatible.
+template<typename T, typename M, typename ID>
+inline T SumAllExtensions(const M& message, ID extension, T zero) {
+ T sum = zero;
+ typename RepeatedField<T>::const_iterator iter =
+ message.GetRepeatedExtension(extension).begin();
+ typename RepeatedField<T>::const_iterator end =
+ message.GetRepeatedExtension(extension).end();
+ for (; iter != end; ++iter) {
+ sum += *iter;
+ }
+ return sum;
+}
+
+template<typename T, typename M, typename ID>
+inline void IncAllExtensions(M* message, ID extension,
+ T val) {
+ typename RepeatedField<T>::iterator iter =
+ message->MutableRepeatedExtension(extension)->begin();
+ typename RepeatedField<T>::iterator end =
+ message->MutableRepeatedExtension(extension)->end();
+ for (; iter != end; ++iter) {
+ *iter += val;
+ }
+}
+
+TEST(ExtensionSetTest, RepeatedFields) {
+ unittest::TestAllExtensions message;
+
+ // Test empty repeated-field case (b/12926163)
+ ASSERT_EQ(0, message.GetRepeatedExtension(
+ unittest::repeated_int32_extension).size());
+ ASSERT_EQ(0, message.GetRepeatedExtension(
+ unittest::repeated_nested_enum_extension).size());
+ ASSERT_EQ(0, message.GetRepeatedExtension(
+ unittest::repeated_string_extension).size());
+ ASSERT_EQ(0, message.GetRepeatedExtension(
+ unittest::repeated_nested_message_extension).size());
+
+ unittest::TestAllTypes::NestedMessage nested_message;
+ nested_message.set_bb(42);
+ unittest::TestAllTypes::NestedEnum nested_enum =
+ unittest::TestAllTypes::NestedEnum_MIN;
+
+ for (int i = 0; i < 10; ++i) {
+ message.AddExtension(unittest::repeated_int32_extension, 1);
+ message.AddExtension(unittest::repeated_int64_extension, 2);
+ message.AddExtension(unittest::repeated_uint32_extension, 3);
+ message.AddExtension(unittest::repeated_uint64_extension, 4);
+ message.AddExtension(unittest::repeated_sint32_extension, 5);
+ message.AddExtension(unittest::repeated_sint64_extension, 6);
+ message.AddExtension(unittest::repeated_fixed32_extension, 7);
+ message.AddExtension(unittest::repeated_fixed64_extension, 8);
+ message.AddExtension(unittest::repeated_sfixed32_extension, 7);
+ message.AddExtension(unittest::repeated_sfixed64_extension, 8);
+ message.AddExtension(unittest::repeated_float_extension, 9.0);
+ message.AddExtension(unittest::repeated_double_extension, 10.0);
+ message.AddExtension(unittest::repeated_bool_extension, true);
+ message.AddExtension(unittest::repeated_nested_enum_extension, nested_enum);
+ message.AddExtension(unittest::repeated_string_extension,
+ ::std::string("test"));
+ message.AddExtension(unittest::repeated_bytes_extension,
+ ::std::string("test\xFF"));
+ message.AddExtension(
+ unittest::repeated_nested_message_extension)->CopyFrom(nested_message);
+ message.AddExtension(unittest::repeated_nested_enum_extension,
+ nested_enum);
+ }
+
+ ASSERT_EQ(10, SumAllExtensions<int32>(
+ message, unittest::repeated_int32_extension, 0));
+ IncAllExtensions<int32>(
+ &message, unittest::repeated_int32_extension, 1);
+ ASSERT_EQ(20, SumAllExtensions<int32>(
+ message, unittest::repeated_int32_extension, 0));
+
+ ASSERT_EQ(20, SumAllExtensions<int64>(
+ message, unittest::repeated_int64_extension, 0));
+ IncAllExtensions<int64>(
+ &message, unittest::repeated_int64_extension, 1);
+ ASSERT_EQ(30, SumAllExtensions<int64>(
+ message, unittest::repeated_int64_extension, 0));
+
+ ASSERT_EQ(30, SumAllExtensions<uint32>(
+ message, unittest::repeated_uint32_extension, 0));
+ IncAllExtensions<uint32>(
+ &message, unittest::repeated_uint32_extension, 1);
+ ASSERT_EQ(40, SumAllExtensions<uint32>(
+ message, unittest::repeated_uint32_extension, 0));
+
+ ASSERT_EQ(40, SumAllExtensions<uint64>(
+ message, unittest::repeated_uint64_extension, 0));
+ IncAllExtensions<uint64>(
+ &message, unittest::repeated_uint64_extension, 1);
+ ASSERT_EQ(50, SumAllExtensions<uint64>(
+ message, unittest::repeated_uint64_extension, 0));
+
+ ASSERT_EQ(50, SumAllExtensions<int32>(
+ message, unittest::repeated_sint32_extension, 0));
+ IncAllExtensions<int32>(
+ &message, unittest::repeated_sint32_extension, 1);
+ ASSERT_EQ(60, SumAllExtensions<int32>(
+ message, unittest::repeated_sint32_extension, 0));
+
+ ASSERT_EQ(60, SumAllExtensions<int64>(
+ message, unittest::repeated_sint64_extension, 0));
+ IncAllExtensions<int64>(
+ &message, unittest::repeated_sint64_extension, 1);
+ ASSERT_EQ(70, SumAllExtensions<int64>(
+ message, unittest::repeated_sint64_extension, 0));
+
+ ASSERT_EQ(70, SumAllExtensions<uint32>(
+ message, unittest::repeated_fixed32_extension, 0));
+ IncAllExtensions<uint32>(
+ &message, unittest::repeated_fixed32_extension, 1);
+ ASSERT_EQ(80, SumAllExtensions<uint32>(
+ message, unittest::repeated_fixed32_extension, 0));
+
+ ASSERT_EQ(80, SumAllExtensions<uint64>(
+ message, unittest::repeated_fixed64_extension, 0));
+ IncAllExtensions<uint64>(
+ &message, unittest::repeated_fixed64_extension, 1);
+ ASSERT_EQ(90, SumAllExtensions<uint64>(
+ message, unittest::repeated_fixed64_extension, 0));
+
+ // Usually, floating-point arithmetic cannot be trusted to be exact, so it is
+ // a Bad Idea to assert equality in a test like this. However, we're dealing
+ // with integers with a small number of significant mantissa bits, so we
+ // should actually have exact precision here.
+ ASSERT_EQ(90, SumAllExtensions<float>(
+ message, unittest::repeated_float_extension, 0));
+ IncAllExtensions<float>(
+ &message, unittest::repeated_float_extension, 1);
+ ASSERT_EQ(100, SumAllExtensions<float>(
+ message, unittest::repeated_float_extension, 0));
+
+ ASSERT_EQ(100, SumAllExtensions<double>(
+ message, unittest::repeated_double_extension, 0));
+ IncAllExtensions<double>(
+ &message, unittest::repeated_double_extension, 1);
+ ASSERT_EQ(110, SumAllExtensions<double>(
+ message, unittest::repeated_double_extension, 0));
+
+ RepeatedPtrField< ::std::string>::iterator string_iter;
+ RepeatedPtrField< ::std::string>::iterator string_end;
+ for (string_iter = message.MutableRepeatedExtension(
+ unittest::repeated_string_extension)->begin(),
+ string_end = message.MutableRepeatedExtension(
+ unittest::repeated_string_extension)->end();
+ string_iter != string_end; ++string_iter) {
+ *string_iter += "test";
+ }
+ RepeatedPtrField< ::std::string>::const_iterator string_const_iter;
+ RepeatedPtrField< ::std::string>::const_iterator string_const_end;
+ for (string_const_iter = message.GetRepeatedExtension(
+ unittest::repeated_string_extension).begin(),
+ string_const_end = message.GetRepeatedExtension(
+ unittest::repeated_string_extension).end();
+ string_iter != string_end; ++string_iter) {
+ ASSERT_TRUE(*string_iter == "testtest");
+ }
+
+ RepeatedField<unittest::TestAllTypes_NestedEnum>::iterator enum_iter;
+ RepeatedField<unittest::TestAllTypes_NestedEnum>::iterator enum_end;
+ for (enum_iter = message.MutableRepeatedExtension(
+ unittest::repeated_nested_enum_extension)->begin(),
+ enum_end = message.MutableRepeatedExtension(
+ unittest::repeated_nested_enum_extension)->end();
+ enum_iter != enum_end; ++enum_iter) {
+ *enum_iter = unittest::TestAllTypes::NestedEnum_MAX;
+ }
+ RepeatedField<unittest::TestAllTypes_NestedEnum>::const_iterator
+ enum_const_iter;
+ RepeatedField<unittest::TestAllTypes_NestedEnum>::const_iterator
+ enum_const_end;
+ for (enum_const_iter = message.GetRepeatedExtension(
+ unittest::repeated_nested_enum_extension).begin(),
+ enum_const_end = message.GetRepeatedExtension(
+ unittest::repeated_nested_enum_extension).end();
+ enum_iter != enum_end; ++enum_iter) {
+ ASSERT_EQ(*enum_const_iter, unittest::TestAllTypes::NestedEnum_MAX);
+ }
+
+ RepeatedPtrField<unittest::TestAllTypes_NestedMessage>::iterator
+ msg_iter;
+ RepeatedPtrField<unittest::TestAllTypes_NestedMessage>::iterator
+ msg_end;
+ for (msg_iter = message.MutableRepeatedExtension(
+ unittest::repeated_nested_message_extension)->begin(),
+ msg_end = message.MutableRepeatedExtension(
+ unittest::repeated_nested_message_extension)->end();
+ msg_iter != msg_end; ++msg_iter) {
+ msg_iter->set_bb(1234);
+ }
+ RepeatedPtrField<unittest::TestAllTypes_NestedMessage>::
+ const_iterator msg_const_iter;
+ RepeatedPtrField<unittest::TestAllTypes_NestedMessage>::
+ const_iterator msg_const_end;
+ for (msg_const_iter = message.GetRepeatedExtension(
+ unittest::repeated_nested_message_extension).begin(),
+ msg_const_end = message.GetRepeatedExtension(
+ unittest::repeated_nested_message_extension).end();
+ msg_const_iter != msg_const_end; ++msg_const_iter) {
+ ASSERT_EQ(msg_const_iter->bb(), 1234);
+ }
+
+ // Test range-based for as well, but only if compiled as C++11.
+#if __cplusplus >= 201103L
+ // Test one primitive field.
+ for (auto& x : *message.MutableRepeatedExtension(
+ unittest::repeated_int32_extension)) {
+ x = 4321;
+ }
+ for (const auto& x : message.GetRepeatedExtension(
+ unittest::repeated_int32_extension)) {
+ ASSERT_EQ(x, 4321);
+ }
+ // Test one string field.
+ for (auto& x : *message.MutableRepeatedExtension(
+ unittest::repeated_string_extension)) {
+ x = "test_range_based_for";
+ }
+ for (const auto& x : message.GetRepeatedExtension(
+ unittest::repeated_string_extension)) {
+ ASSERT_TRUE(x == "test_range_based_for");
+ }
+ // Test one message field.
+ for (auto& x : *message.MutableRepeatedExtension(
+ unittest::repeated_nested_message_extension)) {
+ x.set_bb(4321);
+ }
+ for (const auto& x : *message.MutableRepeatedExtension(
+ unittest::repeated_nested_message_extension)) {
+ ASSERT_EQ(x.bb(), 4321);
+ }
+#endif
+}
+
+// From b/12926163
+TEST(ExtensionSetTest, AbsentExtension) {
+ unittest::TestAllExtensions message;
+ message.MutableRepeatedExtension(unittest::repeated_nested_message_extension)
+ ->Add()->set_bb(123);
+ ASSERT_EQ(1, message.ExtensionSize(
+ unittest::repeated_nested_message_extension));
+ EXPECT_EQ(
+ 123, message.GetExtension(
+ unittest::repeated_nested_message_extension, 0).bb());
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
TEST(ExtensionSetTest, InvalidEnumDeath) {
unittest::TestAllExtensions message;
@@ -480,7 +1041,7 @@ TEST(ExtensionSetTest, InvalidEnumDeath) {
"IsValid");
}
-#endif // GTEST_HAS_DEATH_TEST
+#endif // PROTOBUF_HAS_DEATH_TEST
TEST(ExtensionSetTest, DynamicExtensions) {
// Test adding a dynamic extension to a compiled-in message object.
@@ -615,7 +1176,11 @@ TEST(ExtensionSetTest, DynamicExtensions) {
const Message& sub_message =
message.GetReflection()->GetMessage(message, message_extension);
const unittest::ForeignMessage* typed_sub_message =
+#ifdef GOOGLE_PROTOBUF_NO_RTTI
+ static_cast<const unittest::ForeignMessage*>(&sub_message);
+#else
dynamic_cast<const unittest::ForeignMessage*>(&sub_message);
+#endif
ASSERT_TRUE(typed_sub_message != NULL);
EXPECT_EQ(456, typed_sub_message->c());
}
diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto
new file mode 100644
index 00000000..492d4b06
--- /dev/null
+++ b/src/google/protobuf/field_mask.proto
@@ -0,0 +1,161 @@
+// 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 google.protobuf;
+
+option java_multiple_files = true;
+option java_outer_classname = "FieldMaskProto";
+option java_package = "com.google.protobuf";
+
+
+// `FieldMask` represents a set of symbolic field paths, for example:
+//
+// paths: "f.a"
+// paths: "f.b.d"
+//
+// Here `f` represents a field in some root message, `a` and `b`
+// fields in the message found in `f`, and `d` a field found in the
+// message in `f.b`.
+//
+// Field masks are used to specify a subset of fields that should be
+// returned by a get operation or modified by an update operation.
+// Field masks also have a custom JSON encoding (see below).
+//
+// # Field Masks in Projections
+// When used in the context of a projection, a response message or
+// sub-message is filtered by the API to only contain those fields as
+// specified in the mask. For example, if the mask in the previous
+// example is applied to a response message as follows:
+//
+// f {
+// a : 22
+// b {
+// d : 1
+// x : 2
+// }
+// y : 13
+// }
+// z: 8
+//
+// The result will not contain specific values for fields x,y and z
+// (there value will be set to the default, and omitted in proto text
+// output):
+//
+//
+// f {
+// a : 22
+// b {
+// d : 1
+// }
+// }
+//
+// A repeated field is not allowed except at the last position of a
+// field mask.
+//
+// If a FieldMask object is not present in a get operation, the
+// operation applies to all fields (as if a FieldMask of all fields
+// had been specified).
+//
+// Note that a field mask does not necessarily applies to the
+// top-level response message. In case of a REST get operation, the
+// field mask applies directly to the response, but in case of a REST
+// list operation, the mask instead applies to each individual message
+// in the returned resource list. In case of a REST custom method,
+// other definitions may be used. Where the mask applies will be
+// clearly documented together with its declaration in the API. In
+// any case, the effect on the returned resource/resources is required
+// behavior for APIs.
+//
+// # Field Masks in Update Operations
+// A field mask in update operations specifies which fields of the
+// targeted resource are going to be updated. The API is required
+// to only change the values of the fields as specified in the mask
+// and leave the others untouched. If a resource is passed in to
+// describe the updated values, the API ignores the values of all
+// fields not covered by the mask.
+//
+// In order to reset a field's value to the default, the field must
+// be in the mask and set to the default value in the provided resource.
+// Hence, in order to reset all fields of a resource, provide a default
+// instance of the resource and set all fields in the mask, or do
+// not provide a mask as described below.
+//
+// If a field mask is not present on update, the operation applies to
+// all fields (as if a field mask of all fields has been specified).
+// Note that in the presence of schema evolution, this may mean that
+// fields the client does not know and has therefore not filled into
+// the request will be reset to their default. If this is unwanted
+// behavior, a specific service may require a client to always specify
+// a field mask, producing an error if not.
+//
+// As with get operations, the location of the resource which
+// describes the updated values in the request message depends on the
+// operation kind. In any case, the effect of the field mask is
+// required to be honored by the API.
+//
+// ## Considerations for HTTP REST
+// The HTTP kind of an update operation which uses a field mask must
+// be set to PATCH instead of PUT in order to satisfy HTTP semantics
+// (PUT must only be used for full updates).
+//
+// # JSON Encoding of Field Masks
+// In JSON, a field mask is encoded as a single string where paths are
+// separated by a comma. Fields name in each path are converted
+// to/from lower-camel naming conventions.
+//
+// As an example, consider the following message declarations:
+//
+// message Profile {
+// User user = 1;
+// Photo photo = 2;
+// }
+// message User {
+// string display_name = 1;
+// string address = 2;
+// }
+//
+// In proto a field mask for `Profile` may look as such:
+//
+// mask {
+// paths: "user.display_name"
+// paths: "photo"
+// }
+//
+// In JSON, the same mask is represented as below:
+//
+// {
+// mask: "user.displayName,photo"
+// }
+//
+message FieldMask {
+ // The set of field mask paths.
+ repeated string paths = 1;
+}
diff --git a/src/google/protobuf/generated_enum_reflection.h b/src/google/protobuf/generated_enum_reflection.h
new file mode 100644
index 00000000..fdcdc277
--- /dev/null
+++ b/src/google/protobuf/generated_enum_reflection.h
@@ -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.
+
+// Author: jasonh@google.com (Jason Hsueh)
+//
+// This header is logically internal, but is made public because it is used
+// from protocol-compiler-generated code, which may reside in other components.
+// It provides reflection support for generated enums, and is included in
+// generated .pb.h files and should have minimal dependencies. The methods are
+// implemented in generated_message_reflection.cc.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
+#define GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/template_util.h>
+#include <google/protobuf/generated_enum_util.h>
+
+namespace google {
+namespace protobuf {
+ class EnumDescriptor;
+} // namespace protobuf
+
+namespace protobuf {
+
+// Returns the EnumDescriptor for enum type E, which must be a
+// proto-declared enum type. Code generated by the protocol compiler
+// will include specializations of this template for each enum type declared.
+template <typename E>
+const EnumDescriptor* GetEnumDescriptor();
+
+namespace internal {
+
+// Helper for EnumType_Parse functions: try to parse the string 'name' as an
+// enum name of the given type, returning true and filling in value on success,
+// or returning false and leaving value unchanged on failure.
+LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
+ const string& name,
+ int* value);
+
+template<typename EnumType>
+bool ParseNamedEnum(const EnumDescriptor* descriptor,
+ const string& name,
+ EnumType* value) {
+ int tmp;
+ if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
+ *value = static_cast<EnumType>(tmp);
+ return true;
+}
+
+// Just a wrapper around printing the name of a value. The main point of this
+// function is not to be inlined, so that you can do this without including
+// descriptor.h.
+LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
diff --git a/src/google/protobuf/generated_enum_util.h b/src/google/protobuf/generated_enum_util.h
new file mode 100644
index 00000000..e4242055
--- /dev/null
+++ b/src/google/protobuf/generated_enum_util.h
@@ -0,0 +1,46 @@
+// 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_GENERATED_ENUM_UTIL_H__
+#define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
+
+#include <google/protobuf/stubs/template_util.h>
+
+namespace google {
+namespace protobuf {
+
+// This type trait can be used to cause templates to only match proto2 enum
+// types.
+template <typename T> struct is_proto_enum : ::google::protobuf::internal::false_type {};
+
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index a0dd75c6..412c48a1 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,23 +33,35 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <algorithm>
-#include <google/protobuf/generated_message_reflection.h>
-#include <google/protobuf/descriptor.h>
+#include <set>
+
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/descriptor.h>
#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/generated_message_util.h>
-#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/repeated_field.h>
+
+
+#define GOOGLE_PROTOBUF_HAS_ONEOF
namespace google {
namespace protobuf {
namespace internal {
+namespace {
+bool IsMapFieldInApi(const FieldDescriptor* field) {
+ return field->is_map();
+}
+} // anonymous namespace
+
int StringSpaceUsedExcludingSelf(const string& str) {
const void* start = &str;
const void* end = &str + 1;
- if (start <= str.data() && str.data() <= end) {
+ if (start <= str.data() && str.data() < end) {
// The string's data is stored inside the string object itself.
return 0;
} else {
@@ -68,9 +80,15 @@ bool ParseNamedEnum(const EnumDescriptor* descriptor,
const string& NameOfEnum(const EnumDescriptor* descriptor, int value) {
const EnumValueDescriptor* d = descriptor->FindValueByNumber(value);
- return (d == NULL ? kEmptyString : d->name());
+ return (d == NULL ? GetEmptyString() : d->name());
}
+namespace {
+inline bool SupportsArenas(const Descriptor* descriptor) {
+ return descriptor->file()->options().cc_enable_arenas();
+}
+} // anonymous namespace
+
// ===================================================================
// Helpers for reporting usage errors (e.g. trying to use GetInt32() on
// a string field).
@@ -174,13 +192,48 @@ GeneratedMessageReflection::GeneratedMessageReflection(
int extensions_offset,
const DescriptorPool* descriptor_pool,
MessageFactory* factory,
- int object_size)
+ int object_size,
+ int arena_offset,
+ int is_default_instance_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),
+ is_default_instance_offset_(is_default_instance_offset),
+ object_size_ (object_size),
+ descriptor_pool_ ((descriptor_pool == NULL) ?
+ DescriptorPool::generated_pool() :
+ descriptor_pool),
+ message_factory_ (factory) {
+}
+
+GeneratedMessageReflection::GeneratedMessageReflection(
+ const Descriptor* descriptor,
+ const Message* default_instance,
+ const int offsets[],
+ int has_bits_offset,
+ int unknown_fields_offset,
+ int extensions_offset,
+ const void* default_oneof_instance,
+ int oneof_case_offset,
+ const DescriptorPool* descriptor_pool,
+ MessageFactory* factory,
+ int object_size,
+ int arena_offset,
+ int is_default_instance_offset)
+ : descriptor_ (descriptor),
+ default_instance_ (default_instance),
+ default_oneof_instance_ (default_oneof_instance),
+ offsets_ (offsets),
+ has_bits_offset_ (has_bits_offset),
+ oneof_case_offset_(oneof_case_offset),
+ unknown_fields_offset_(unknown_fields_offset),
+ extensions_offset_(extensions_offset),
+ arena_offset_ (arena_offset),
+ is_default_instance_offset_(is_default_instance_offset),
object_size_ (object_size),
descriptor_pool_ ((descriptor_pool == NULL) ?
DescriptorPool::generated_pool() :
@@ -190,14 +243,45 @@ GeneratedMessageReflection::GeneratedMessageReflection(
GeneratedMessageReflection::~GeneratedMessageReflection() {}
+namespace {
+UnknownFieldSet* empty_unknown_field_set_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(empty_unknown_field_set_once_);
+
+void DeleteEmptyUnknownFieldSet() {
+ delete empty_unknown_field_set_;
+ empty_unknown_field_set_ = NULL;
+}
+
+void InitEmptyUnknownFieldSet() {
+ empty_unknown_field_set_ = new UnknownFieldSet;
+ internal::OnShutdown(&DeleteEmptyUnknownFieldSet);
+}
+
+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<const uint8*>(&message) +
unknown_fields_offset_;
return *reinterpret_cast<const UnknownFieldSet*>(ptr);
}
+
UnknownFieldSet* GeneratedMessageReflection::MutableUnknownFields(
Message* message) const {
+ if (unknown_fields_offset_ == kUnknownFieldSetInMetadata) {
+ return MutableInternalMetadataWithArena(message)->
+ mutable_unknown_fields();
+ }
void* ptr = reinterpret_cast<uint8*>(message) + unknown_fields_offset_;
return reinterpret_cast<UnknownFieldSet*>(ptr);
}
@@ -246,14 +330,23 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const {
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
- // We don't know which subclass of RepeatedPtrFieldBase the type is,
- // so we use RepeatedPtrFieldBase directly.
- total_size +=
- GetRaw<RepeatedPtrFieldBase>(message, field)
- .SpaceUsedExcludingSelf<GenericTypeHandler<Message> >();
+ if (IsMapFieldInApi(field)) {
+ total_size +=
+ GetRaw<MapFieldBase>(message, field).SpaceUsedExcludingSelf();
+ } else {
+ // We don't know which subclass of RepeatedPtrFieldBase the type is,
+ // so we use RepeatedPtrFieldBase directly.
+ total_size +=
+ GetRaw<RepeatedPtrFieldBase>(message, field)
+ .SpaceUsedExcludingSelf<GenericTypeHandler<Message> >();
+ }
+
break;
}
} else {
+ if (field->containing_oneof() && !HasOneofField(message, field)) {
+ continue;
+ }
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32 :
case FieldDescriptor::CPPTYPE_INT64 :
@@ -270,12 +363,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<const string*>(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<const string*>(field);
+ const string* default_ptr =
+ &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+ const string* ptr =
+ &GetField<ArenaStringPtr>(message, field).Get(default_ptr);
if (ptr != default_ptr) {
// string fields are represented by just a pointer, so also
@@ -306,6 +400,204 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const {
return total_size;
}
+void GeneratedMessageReflection::SwapField(
+ Message* message1,
+ Message* message2,
+ const FieldDescriptor* field) const {
+ if (field->is_repeated()) {
+ switch (field->cpp_type()) {
+#define SWAP_ARRAYS(CPPTYPE, TYPE) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ MutableRaw<RepeatedField<TYPE> >(message1, field)->Swap( \
+ MutableRaw<RepeatedField<TYPE> >(message2, field)); \
+ break;
+
+ SWAP_ARRAYS(INT32 , int32 );
+ SWAP_ARRAYS(INT64 , int64 );
+ SWAP_ARRAYS(UINT32, uint32);
+ SWAP_ARRAYS(UINT64, uint64);
+ SWAP_ARRAYS(FLOAT , float );
+ SWAP_ARRAYS(DOUBLE, double);
+ SWAP_ARRAYS(BOOL , bool );
+ SWAP_ARRAYS(ENUM , int );
+#undef SWAP_ARRAYS
+
+ case FieldDescriptor::CPPTYPE_STRING:
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ if (IsMapFieldInApi(field)) {
+ MutableRaw<MapFieldBase>(message1, field)->
+ MutableRepeatedField()->
+ Swap<GenericTypeHandler<google::protobuf::Message> >(
+ MutableRaw<MapFieldBase>(message2, field)->
+ MutableRepeatedField());
+ } else {
+ MutableRaw<RepeatedPtrFieldBase>(message1, field)->
+ Swap<GenericTypeHandler<google::protobuf::Message> >(
+ MutableRaw<RepeatedPtrFieldBase>(message2, field));
+ }
+ break;
+
+ default:
+ GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+ }
+ } else {
+ switch (field->cpp_type()) {
+#define SWAP_VALUES(CPPTYPE, TYPE) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ std::swap(*MutableRaw<TYPE>(message1, field), \
+ *MutableRaw<TYPE>(message2, field)); \
+ break;
+
+ SWAP_VALUES(INT32 , int32 );
+ SWAP_VALUES(INT64 , int64 );
+ SWAP_VALUES(UINT32, uint32);
+ SWAP_VALUES(UINT64, uint64);
+ SWAP_VALUES(FLOAT , float );
+ SWAP_VALUES(DOUBLE, double);
+ SWAP_VALUES(BOOL , bool );
+ SWAP_VALUES(ENUM , int );
+#undef SWAP_VALUES
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ std::swap(*MutableRaw<Message*>(message1, field),
+ *MutableRaw<Message*>(message2, field));
+ break;
+
+ case FieldDescriptor::CPPTYPE_STRING:
+ switch (field->options().ctype()) {
+ default: // TODO(kenton): Support other string reps.
+ case FieldOptions::STRING:
+ MutableRaw<ArenaStringPtr>(message1, field)->Swap(
+ MutableRaw<ArenaStringPtr>(message2, field));
+ break;
+ }
+ break;
+
+ default:
+ GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+ }
+ }
+}
+
+void GeneratedMessageReflection::SwapOneofField(
+ Message* message1,
+ Message* message2,
+ const OneofDescriptor* oneof_descriptor) const {
+ uint32 oneof_case1 = GetOneofCase(*message1, oneof_descriptor);
+ uint32 oneof_case2 = GetOneofCase(*message2, oneof_descriptor);
+
+ int32 temp_int32;
+ int64 temp_int64;
+ uint32 temp_uint32;
+ uint64 temp_uint64;
+ float temp_float;
+ double temp_double;
+ bool temp_bool;
+ int temp_int;
+ Message* temp_message = NULL;
+ string temp_string;
+
+ // Stores message1's oneof field to a temp variable.
+ const FieldDescriptor* field1 = NULL;
+ if (oneof_case1 > 0) {
+ field1 = descriptor_->FindFieldByNumber(oneof_case1);
+ //oneof_descriptor->field(oneof_case1);
+ switch (field1->cpp_type()) {
+#define GET_TEMP_VALUE(CPPTYPE, TYPE) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ temp_##TYPE = GetField<TYPE>(*message1, field1); \
+ break;
+
+ GET_TEMP_VALUE(INT32 , int32 );
+ GET_TEMP_VALUE(INT64 , int64 );
+ GET_TEMP_VALUE(UINT32, uint32);
+ GET_TEMP_VALUE(UINT64, uint64);
+ GET_TEMP_VALUE(FLOAT , float );
+ GET_TEMP_VALUE(DOUBLE, double);
+ GET_TEMP_VALUE(BOOL , bool );
+ GET_TEMP_VALUE(ENUM , int );
+#undef GET_TEMP_VALUE
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ temp_message = ReleaseMessage(message1, field1);
+ break;
+
+ case FieldDescriptor::CPPTYPE_STRING:
+ temp_string = GetString(*message1, field1);
+ break;
+
+ default:
+ GOOGLE_LOG(FATAL) << "Unimplemented type: " << field1->cpp_type();
+ }
+ }
+
+ // Sets message1's oneof field from the message2's oneof field.
+ if (oneof_case2 > 0) {
+ const FieldDescriptor* field2 =
+ descriptor_->FindFieldByNumber(oneof_case2);
+ switch (field2->cpp_type()) {
+#define SET_ONEOF_VALUE1(CPPTYPE, TYPE) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ SetField<TYPE>(message1, field2, GetField<TYPE>(*message2, field2)); \
+ break;
+
+ SET_ONEOF_VALUE1(INT32 , int32 );
+ SET_ONEOF_VALUE1(INT64 , int64 );
+ SET_ONEOF_VALUE1(UINT32, uint32);
+ SET_ONEOF_VALUE1(UINT64, uint64);
+ SET_ONEOF_VALUE1(FLOAT , float );
+ SET_ONEOF_VALUE1(DOUBLE, double);
+ SET_ONEOF_VALUE1(BOOL , bool );
+ SET_ONEOF_VALUE1(ENUM , int );
+#undef SET_ONEOF_VALUE1
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ SetAllocatedMessage(message1,
+ ReleaseMessage(message2, field2),
+ field2);
+ break;
+
+ case FieldDescriptor::CPPTYPE_STRING:
+ SetString(message1, field2, GetString(*message2, field2));
+ break;
+
+ default:
+ GOOGLE_LOG(FATAL) << "Unimplemented type: " << field2->cpp_type();
+ }
+ } else {
+ ClearOneof(message1, oneof_descriptor);
+ }
+
+ // Sets message2's oneof field from the temp variable.
+ if (oneof_case1 > 0) {
+ switch (field1->cpp_type()) {
+#define SET_ONEOF_VALUE2(CPPTYPE, TYPE) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ SetField<TYPE>(message2, field1, temp_##TYPE); \
+ break;
+
+ SET_ONEOF_VALUE2(INT32 , int32 );
+ SET_ONEOF_VALUE2(INT64 , int64 );
+ SET_ONEOF_VALUE2(UINT32, uint32);
+ SET_ONEOF_VALUE2(UINT64, uint64);
+ SET_ONEOF_VALUE2(FLOAT , float );
+ SET_ONEOF_VALUE2(DOUBLE, double);
+ SET_ONEOF_VALUE2(BOOL , bool );
+ SET_ONEOF_VALUE2(ENUM , int );
+#undef SET_ONEOF_VALUE2
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ SetAllocatedMessage(message2, temp_message, field1);
+ break;
+
+ case FieldDescriptor::CPPTYPE_STRING:
+ SetString(message2, field1, temp_string);
+ break;
+
+ default:
+ GOOGLE_LOG(FATAL) << "Unimplemented type: " << field1->cpp_type();
+ }
+ } else {
+ ClearOneof(message2, oneof_descriptor);
+ }
+}
+
void GeneratedMessageReflection::Swap(
Message* message1,
Message* message2) const {
@@ -321,89 +613,102 @@ void GeneratedMessageReflection::Swap(
"descriptor.";
GOOGLE_CHECK_EQ(message2->GetReflection(), this)
<< "Second argument to Swap() (of type \""
- << message1->GetDescriptor()->full_name()
+ << message2->GetDescriptor()->full_name()
<< "\") is not compatible with this reflection object (which is for type \""
<< descriptor_->full_name()
<< "\"). 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++) {
const FieldDescriptor* field = descriptor_->field(i);
- if (field->is_repeated()) {
- switch (field->cpp_type()) {
-#define SWAP_ARRAYS(CPPTYPE, TYPE) \
- case FieldDescriptor::CPPTYPE_##CPPTYPE: \
- MutableRaw<RepeatedField<TYPE> >(message1, field)->Swap( \
- MutableRaw<RepeatedField<TYPE> >(message2, field)); \
- break;
+ if (!field->containing_oneof()) {
+ SwapField(message1, message2, field);
+ }
+ }
- SWAP_ARRAYS(INT32 , int32 );
- SWAP_ARRAYS(INT64 , int64 );
- SWAP_ARRAYS(UINT32, uint32);
- SWAP_ARRAYS(UINT64, uint64);
- SWAP_ARRAYS(FLOAT , float );
- SWAP_ARRAYS(DOUBLE, double);
- SWAP_ARRAYS(BOOL , bool );
- SWAP_ARRAYS(ENUM , int );
-#undef SWAP_ARRAYS
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ SwapOneofField(message1, message2, descriptor_->oneof_decl(i));
+ }
- case FieldDescriptor::CPPTYPE_STRING:
- case FieldDescriptor::CPPTYPE_MESSAGE:
- MutableRaw<RepeatedPtrFieldBase>(message1, field)->Swap(
- MutableRaw<RepeatedPtrFieldBase>(message2, field));
- break;
+ if (extensions_offset_ != -1) {
+ MutableExtensionSet(message1)->Swap(MutableExtensionSet(message2));
+ }
- default:
- GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
- }
- } else {
- switch (field->cpp_type()) {
-#define SWAP_VALUES(CPPTYPE, TYPE) \
- case FieldDescriptor::CPPTYPE_##CPPTYPE: \
- std::swap(*MutableRaw<TYPE>(message1, field), \
- *MutableRaw<TYPE>(message2, field)); \
- break;
+ MutableUnknownFields(message1)->Swap(MutableUnknownFields(message2));
+}
- SWAP_VALUES(INT32 , int32 );
- SWAP_VALUES(INT64 , int64 );
- SWAP_VALUES(UINT32, uint32);
- SWAP_VALUES(UINT64, uint64);
- SWAP_VALUES(FLOAT , float );
- SWAP_VALUES(DOUBLE, double);
- SWAP_VALUES(BOOL , bool );
- SWAP_VALUES(ENUM , int );
- SWAP_VALUES(MESSAGE, Message*);
-#undef SWAP_VALUES
+void GeneratedMessageReflection::SwapFields(
+ Message* message1,
+ Message* message2,
+ const vector<const FieldDescriptor*>& fields) const {
+ if (message1 == message2) return;
- case FieldDescriptor::CPPTYPE_STRING:
- switch (field->options().ctype()) {
- default: // TODO(kenton): Support other string reps.
- case FieldOptions::STRING:
- std::swap(*MutableRaw<string*>(message1, field),
- *MutableRaw<string*>(message2, field));
- break;
- }
- break;
+ // TODO(kenton): Other Reflection methods should probably check this too.
+ GOOGLE_CHECK_EQ(message1->GetReflection(), this)
+ << "First argument to SwapFields() (of type \""
+ << message1->GetDescriptor()->full_name()
+ << "\") is not compatible with this reflection object (which is for type \""
+ << descriptor_->full_name()
+ << "\"). Note that the exact same class is required; not just the same "
+ "descriptor.";
+ GOOGLE_CHECK_EQ(message2->GetReflection(), this)
+ << "Second argument to SwapFields() (of type \""
+ << message2->GetDescriptor()->full_name()
+ << "\") is not compatible with this reflection object (which is for type \""
+ << descriptor_->full_name()
+ << "\"). Note that the exact same class is required; not just the same "
+ "descriptor.";
- default:
- GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+ std::set<int> swapped_oneof;
+
+ for (int i = 0; i < fields.size(); i++) {
+ const FieldDescriptor* field = fields[i];
+ if (field->is_extension()) {
+ MutableExtensionSet(message1)->SwapExtension(
+ MutableExtensionSet(message2),
+ field->number());
+ } else {
+ if (field->containing_oneof()) {
+ int oneof_index = field->containing_oneof()->index();
+ // Only swap the oneof field once.
+ if (swapped_oneof.find(oneof_index) != swapped_oneof.end()) {
+ continue;
+ }
+ swapped_oneof.insert(oneof_index);
+ SwapOneofField(message1, message2, field->containing_oneof());
+ } else {
+ // Swap has bit.
+ SwapBit(message1, message2, field);
+ // Swap field.
+ SwapField(message1, message2, field);
}
}
}
-
- if (extensions_offset_ != -1) {
- MutableExtensionSet(message1)->Swap(MutableExtensionSet(message2));
- }
-
- MutableUnknownFields(message1)->Swap(MutableUnknownFields(message2));
}
// -------------------------------------------------------------------
@@ -416,7 +721,11 @@ bool GeneratedMessageReflection::HasField(const Message& message,
if (field->is_extension()) {
return GetExtensionSet(message).Has(field->number());
} else {
- return HasBit(message, field);
+ if (field->containing_oneof()) {
+ return HasOneofField(message, field);
+ } else {
+ return HasBit(message, field);
+ }
}
}
@@ -445,7 +754,11 @@ int GeneratedMessageReflection::FieldSize(const Message& message,
case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
- return GetRaw<RepeatedPtrFieldBase>(message, field).size();
+ if (IsMapFieldInApi(field)) {
+ return GetRaw<MapFieldBase>(message, field).GetRepeatedField().size();
+ } else {
+ return GetRaw<RepeatedPtrFieldBase>(message, field).size();
+ }
}
GOOGLE_LOG(FATAL) << "Can't get here.";
@@ -460,6 +773,11 @@ void GeneratedMessageReflection::ClearField(
if (field->is_extension()) {
MutableExtensionSet(message)->ClearExtension(field->number());
} else if (!field->is_repeated()) {
+ if (field->containing_oneof()) {
+ ClearOneofField(message, field);
+ return;
+ }
+
if (HasBit(*message, field)) {
ClearBit(message, field);
@@ -488,17 +806,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<const string*>(field);
- string** value = MutableRaw<string*>(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<ArenaStringPtr>(field).Get(NULL);
+ MutableRaw<ArenaStringPtr>(message, field)->Destroy(default_ptr,
+ GetArena(message));
break;
+ }
}
break;
}
@@ -536,10 +850,16 @@ void GeneratedMessageReflection::ClearField(
}
case FieldDescriptor::CPPTYPE_MESSAGE: {
- // We don't know which subclass of RepeatedPtrFieldBase the type is,
- // so we use RepeatedPtrFieldBase directly.
- MutableRaw<RepeatedPtrFieldBase>(message, field)
- ->Clear<GenericTypeHandler<Message> >();
+ if (IsMapFieldInApi(field)) {
+ MutableRaw<MapFieldBase>(message, field)
+ ->MutableRepeatedField()
+ ->Clear<GenericTypeHandler<Message> >();
+ } else {
+ // We don't know which subclass of RepeatedPtrFieldBase the type is,
+ // so we use RepeatedPtrFieldBase directly.
+ MutableRaw<RepeatedPtrFieldBase>(message, field)
+ ->Clear<GenericTypeHandler<Message> >();
+ }
break;
}
}
@@ -581,13 +901,39 @@ void GeneratedMessageReflection::RemoveLast(
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
- MutableRaw<RepeatedPtrFieldBase>(message, field)
+ if (IsMapFieldInApi(field)) {
+ MutableRaw<MapFieldBase>(message, field)
+ ->MutableRepeatedField()
+ ->RemoveLast<GenericTypeHandler<Message> >();
+ } else {
+ MutableRaw<RepeatedPtrFieldBase>(message, field)
->RemoveLast<GenericTypeHandler<Message> >();
+ }
break;
}
}
}
+Message* GeneratedMessageReflection::ReleaseLast(
+ Message* message,
+ const FieldDescriptor* field) const {
+ USAGE_CHECK_ALL(ReleaseLast, REPEATED, MESSAGE);
+
+ if (field->is_extension()) {
+ return static_cast<Message*>(
+ MutableExtensionSet(message)->ReleaseLast(field->number()));
+ } else {
+ if (IsMapFieldInApi(field)) {
+ return MutableRaw<MapFieldBase>(message, field)
+ ->MutableRepeatedField()
+ ->ReleaseLast<GenericTypeHandler<Message> >();
+ } else {
+ return MutableRaw<RepeatedPtrFieldBase>(message, field)
+ ->ReleaseLast<GenericTypeHandler<Message> >();
+ }
+ }
+}
+
void GeneratedMessageReflection::SwapElements(
Message* message,
const FieldDescriptor* field,
@@ -618,8 +964,14 @@ void GeneratedMessageReflection::SwapElements(
case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
- MutableRaw<RepeatedPtrFieldBase>(message, field)
+ if (IsMapFieldInApi(field)) {
+ MutableRaw<MapFieldBase>(message, field)
+ ->MutableRepeatedField()
+ ->SwapElements(index1, index2);
+ } else {
+ MutableRaw<RepeatedPtrFieldBase>(message, field)
->SwapElements(index1, index2);
+ }
break;
}
}
@@ -643,6 +995,7 @@ void GeneratedMessageReflection::ListFields(
// Optimization: The default instance never has any fields set.
if (&message == default_instance_) return;
+ output->reserve(descriptor_->field_count());
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (field->is_repeated()) {
@@ -650,7 +1003,11 @@ void GeneratedMessageReflection::ListFields(
output->push_back(field);
}
} else {
- if (HasBit(message, field)) {
+ if (field->containing_oneof()) {
+ if (HasOneofField(message, field)) {
+ output->push_back(field);
+ }
+ } else if (HasBit(message, field)) {
output->push_back(field);
}
}
@@ -662,7 +1019,7 @@ void GeneratedMessageReflection::ListFields(
}
// ListFields() must sort output by field number.
- sort(output->begin(), output->end(), FieldNumberSorter());
+ std::sort(output->begin(), output->end(), FieldNumberSorter());
}
// -------------------------------------------------------------------
@@ -749,12 +1106,15 @@ string GeneratedMessageReflection::GetString(
} else {
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
- case FieldOptions::STRING:
- return *GetField<const string*>(message, field);
+ case FieldOptions::STRING: {
+ const string* default_ptr =
+ &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+ return GetField<ArenaStringPtr>(message, field).Get(default_ptr);
+ }
}
GOOGLE_LOG(FATAL) << "Can't get here.";
- return kEmptyString; // Make compiler happy.
+ return GetEmptyString(); // Make compiler happy.
}
}
@@ -768,12 +1128,15 @@ const string& GeneratedMessageReflection::GetStringReference(
} else {
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
- case FieldOptions::STRING:
- return *GetField<const string*>(message, field);
+ case FieldOptions::STRING: {
+ const string* default_ptr =
+ &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+ return GetField<ArenaStringPtr>(message, field).Get(default_ptr);
+ }
}
GOOGLE_LOG(FATAL) << "Can't get here.";
- return kEmptyString; // Make compiler happy.
+ return GetEmptyString(); // Make compiler happy.
}
}
@@ -789,12 +1152,15 @@ void GeneratedMessageReflection::SetString(
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING: {
- string** ptr = MutableField<string*>(message, field);
- if (*ptr == DefaultRaw<const string*>(field)) {
- *ptr = new string(value);
- } else {
- (*ptr)->assign(value);
+ const string* default_ptr =
+ &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+ if (field->containing_oneof() && !HasOneofField(*message, field)) {
+ ClearOneof(message, field->containing_oneof());
+ MutableField<ArenaStringPtr>(message, field)->UnsafeSetDefault(
+ default_ptr);
}
+ MutableField<ArenaStringPtr>(message, field)->Set(default_ptr,
+ value, GetArena(message));
break;
}
}
@@ -815,7 +1181,7 @@ string GeneratedMessageReflection::GetRepeatedString(
}
GOOGLE_LOG(FATAL) << "Can't get here.";
- return kEmptyString; // Make compiler happy.
+ return GetEmptyString(); // Make compiler happy.
}
}
@@ -833,7 +1199,7 @@ const string& GeneratedMessageReflection::GetRepeatedStringReference(
}
GOOGLE_LOG(FATAL) << "Can't get here.";
- return kEmptyString; // Make compiler happy.
+ return GetEmptyString(); // Make compiler happy.
}
}
@@ -876,40 +1242,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 value;
+int GeneratedMessageReflection::GetEnumValue(
+ const Message& message, const FieldDescriptor* field) const {
+ USAGE_CHECK_ALL(GetEnumValue, SINGULAR, ENUM);
+
+ int32 value;
if (field->is_extension()) {
value = GetExtensionSet(message).GetEnum(
field->number(), field->default_value_enum()->number());
} else {
value = GetField<int>(message, field);
}
- const EnumValueDescriptor* result =
- field->enum_type()->FindValueByNumber(value);
- GOOGLE_CHECK(result != NULL);
- 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<int>(message, field, value->number());
+ SetField<int>(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()) {
@@ -917,39 +1323,89 @@ const EnumValueDescriptor* GeneratedMessageReflection::GetRepeatedEnum(
} else {
value = GetRepeatedField<int>(message, field, index);
}
- const EnumValueDescriptor* result =
- field->enum_type()->FindValueByNumber(value);
- GOOGLE_CHECK(result != NULL);
- 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<int>(message, field, index, value->number());
+ SetRepeatedField<int>(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<int>(message, field, value->number());
+ AddField<int>(message, field, value);
}
}
@@ -960,13 +1416,15 @@ const Message& GeneratedMessageReflection::GetMessage(
MessageFactory* factory) const {
USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE);
+ if (factory == NULL) factory = message_factory_;
+
if (field->is_extension()) {
return static_cast<const Message&>(
GetExtensionSet(message).GetMessage(
- field->number(), field->message_type(),
- factory == NULL ? message_factory_ : factory));
+ field->number(), field->message_type(), factory));
} else {
- const Message* result = GetRaw<const Message*>(message, field);
+ const Message* result;
+ result = GetRaw<const Message*>(message, field);
if (result == NULL) {
result = DefaultRaw<const Message*>(field);
}
@@ -979,20 +1437,137 @@ Message* GeneratedMessageReflection::MutableMessage(
MessageFactory* factory) const {
USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE);
+ if (factory == NULL) factory = message_factory_;
+
if (field->is_extension()) {
return static_cast<Message*>(
- MutableExtensionSet(message)->MutableMessage(field,
- factory == NULL ? message_factory_ : factory));
+ MutableExtensionSet(message)->MutableMessage(field, factory));
} else {
- Message** result = MutableField<Message*>(message, field);
- if (*result == NULL) {
+ Message* result;
+ Message** result_holder = MutableRaw<Message*>(message, field);
+
+ if (field->containing_oneof()) {
+ if (!HasOneofField(*message, field)) {
+ ClearOneof(message, field->containing_oneof());
+ result_holder = MutableField<Message*>(message, field);
+ const Message* default_message = DefaultRaw<const Message*>(field);
+ *result_holder = default_message->New(message->GetArena());
+ }
+ } else {
+ SetBit(message, field);
+ }
+
+ if (*result_holder == NULL) {
const Message* default_message = DefaultRaw<const Message*>(field);
- *result = default_message->New();
+ *result_holder = default_message->New(message->GetArena());
}
- return *result;
+ result = *result_holder;
+ return result;
}
}
+void GeneratedMessageReflection::UnsafeArenaSetAllocatedMessage(
+ Message* message,
+ Message* sub_message,
+ const FieldDescriptor* field) const {
+ USAGE_CHECK_ALL(SetAllocatedMessage, SINGULAR, MESSAGE);
+
+ if (field->is_extension()) {
+ MutableExtensionSet(message)->SetAllocatedMessage(
+ field->number(), field->type(), field, sub_message);
+ } else {
+ if (field->containing_oneof()) {
+ if (sub_message == NULL) {
+ ClearOneof(message, field->containing_oneof());
+ return;
+ }
+ ClearOneof(message, field->containing_oneof());
+ *MutableRaw<Message*>(message, field) = sub_message;
+ SetOneofCase(message, field);
+ return;
+ }
+
+ if (sub_message == NULL) {
+ ClearBit(message, field);
+ } else {
+ SetBit(message, field);
+ }
+ Message** sub_message_holder = MutableRaw<Message*>(message, field);
+ if (GetArena(message) == NULL) {
+ delete *sub_message_holder;
+ }
+ *sub_message_holder = sub_message;
+ }
+}
+
+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 {
+ USAGE_CHECK_ALL(ReleaseMessage, SINGULAR, MESSAGE);
+
+ if (factory == NULL) factory = message_factory_;
+
+ if (field->is_extension()) {
+ return static_cast<Message*>(
+ MutableExtensionSet(message)->ReleaseMessage(field, factory));
+ } else {
+ ClearBit(message, field);
+ if (field->containing_oneof()) {
+ if (HasOneofField(*message, field)) {
+ *MutableOneofCase(message, field->containing_oneof()) = 0;
+ } else {
+ return NULL;
+ }
+ }
+ Message** result = MutableRaw<Message*>(message, field);
+ Message* ret = *result;
+ *result = NULL;
+ return ret;
+ }
+}
+
+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);
@@ -1001,8 +1576,14 @@ const Message& GeneratedMessageReflection::GetRepeatedMessage(
return static_cast<const Message&>(
GetExtensionSet(message).GetRepeatedMessage(field->number(), index));
} else {
- return GetRaw<RepeatedPtrFieldBase>(message, field)
- .Get<GenericTypeHandler<Message> >(index);
+ if (IsMapFieldInApi(field)) {
+ return GetRaw<MapFieldBase>(message, field)
+ .GetRepeatedField()
+ .Get<GenericTypeHandler<Message> >(index);
+ } else {
+ return GetRaw<RepeatedPtrFieldBase>(message, field)
+ .Get<GenericTypeHandler<Message> >(index);
+ }
}
}
@@ -1015,8 +1596,14 @@ Message* GeneratedMessageReflection::MutableRepeatedMessage(
MutableExtensionSet(message)->MutableRepeatedMessage(
field->number(), index));
} else {
- return MutableRaw<RepeatedPtrFieldBase>(message, field)
+ if (IsMapFieldInApi(field)) {
+ return MutableRaw<MapFieldBase>(message, field)
+ ->MutableRepeatedField()
+ ->Mutable<GenericTypeHandler<Message> >(index);
+ } else {
+ return MutableRaw<RepeatedPtrFieldBase>(message, field)
->Mutable<GenericTypeHandler<Message> >(index);
+ }
}
}
@@ -1031,11 +1618,18 @@ Message* GeneratedMessageReflection::AddMessage(
return static_cast<Message*>(
MutableExtensionSet(message)->AddMessage(field, factory));
} else {
+ Message* result = NULL;
+
// We can't use AddField<Message>() because RepeatedPtrFieldBase doesn't
// know how to allocate one.
- RepeatedPtrFieldBase* repeated =
- MutableRaw<RepeatedPtrFieldBase>(message, field);
- Message* result = repeated->AddFromCleared<GenericTypeHandler<Message> >();
+ RepeatedPtrFieldBase* repeated = NULL;
+ if (IsMapFieldInApi(field)) {
+ repeated =
+ MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+ } else {
+ repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+ }
+ result = repeated->AddFromCleared<GenericTypeHandler<Message> >();
if (result == NULL) {
// We must allocate a new object.
const Message* prototype;
@@ -1044,14 +1638,54 @@ Message* GeneratedMessageReflection::AddMessage(
} else {
prototype = &repeated->Get<GenericTypeHandler<Message> >(0);
}
- result = prototype->New();
- repeated->AddAllocated<GenericTypeHandler<Message> >(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<GenericTypeHandler<Message> >(result);
}
+
return result;
}
}
-// -------------------------------------------------------------------
+void* GeneratedMessageReflection::MutableRawRepeatedField(
+ Message* message, const FieldDescriptor* field,
+ FieldDescriptor::CppType cpptype,
+ int ctype, const Descriptor* desc) const {
+ USAGE_CHECK_REPEATED("MutableRawRepeatedField");
+ if (field->cpp_type() != cpptype)
+ ReportReflectionUsageTypeError(descriptor_,
+ field, "MutableRawRepeatedField", cpptype);
+ if (ctype >= 0)
+ GOOGLE_CHECK_EQ(field->options().ctype(), ctype) << "subtype mismatch";
+ if (desc != NULL)
+ GOOGLE_CHECK_EQ(field->message_type(), desc) << "wrong submessage type";
+ if (field->is_extension()) {
+ return MutableExtensionSet(message)->MutableRawRepeatedField(
+ field->number(), field->type(), field->is_packed(), field);
+ } else {
+ // Trigger transform for MapField
+ if (IsMapFieldInApi(field)) {
+ return reinterpret_cast<MapFieldBase*>(reinterpret_cast<uint8*>(message) +
+ offsets_[field->index()])
+ ->MutableRepeatedField();
+ }
+ return reinterpret_cast<uint8*>(message) + offsets_[field->index()];
+ }
+}
+
+const FieldDescriptor* GeneratedMessageReflection::GetOneofFieldDescriptor(
+ const Message& message,
+ const OneofDescriptor* oneof_descriptor) const {
+ uint32 field_number = GetOneofCase(message, oneof_descriptor);
+ if (field_number == 0) {
+ return NULL;
+ }
+ return descriptor_->FindFieldByNumber(field_number);
+}
+
+// -----------------------------------------------------------------------------
const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByName(
const string& name) const {
@@ -1089,6 +1723,10 @@ const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByNumber(
return descriptor_pool_->FindExtensionByNumber(descriptor_, number);
}
+bool GeneratedMessageReflection::SupportsUnknownEnumValues() const {
+ return CreateUnknownEnumValues(descriptor_->file());
+}
+
// ===================================================================
// Some private helpers.
@@ -1097,37 +1735,70 @@ const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByNumber(
template <typename Type>
inline const Type& GeneratedMessageReflection::GetRaw(
const Message& message, const FieldDescriptor* field) const {
+ if (field->containing_oneof() && !HasOneofField(message, field)) {
+ return DefaultRaw<Type>(field);
+ }
+ int index = field->containing_oneof() ?
+ descriptor_->field_count() + field->containing_oneof()->index() :
+ field->index();
const void* ptr = reinterpret_cast<const uint8*>(&message) +
- offsets_[field->index()];
+ offsets_[index];
return *reinterpret_cast<const Type*>(ptr);
}
template <typename Type>
inline Type* GeneratedMessageReflection::MutableRaw(
Message* message, const FieldDescriptor* field) const {
- void* ptr = reinterpret_cast<uint8*>(message) + offsets_[field->index()];
+ int index = field->containing_oneof() ?
+ descriptor_->field_count() + field->containing_oneof()->index() :
+ field->index();
+ void* ptr = reinterpret_cast<uint8*>(message) + offsets_[index];
return reinterpret_cast<Type*>(ptr);
}
template <typename Type>
inline const Type& GeneratedMessageReflection::DefaultRaw(
const FieldDescriptor* field) const {
- const void* ptr = reinterpret_cast<const uint8*>(default_instance_) +
- offsets_[field->index()];
+ const void* ptr = field->containing_oneof() ?
+ reinterpret_cast<const uint8*>(default_oneof_instance_) +
+ offsets_[field->index()] :
+ reinterpret_cast<const uint8*>(default_instance_) +
+ offsets_[field->index()];
return *reinterpret_cast<const Type*>(ptr);
}
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<const uint8*>(&message) + has_bits_offset_;
return reinterpret_cast<const uint32*>(ptr);
}
inline uint32* GeneratedMessageReflection::MutableHasBits(
Message* message) const {
+ if (has_bits_offset_ == -1) {
+ return NULL;
+ }
void* ptr = reinterpret_cast<uint8*>(message) + has_bits_offset_;
return reinterpret_cast<uint32*>(ptr);
}
+inline uint32 GeneratedMessageReflection::GetOneofCase(
+ const Message& message,
+ const OneofDescriptor* oneof_descriptor) const {
+ const void* ptr = reinterpret_cast<const uint8*>(&message)
+ + oneof_case_offset_;
+ return reinterpret_cast<const uint32*>(ptr)[oneof_descriptor->index()];
+}
+
+inline uint32* GeneratedMessageReflection::MutableOneofCase(
+ Message* message,
+ const OneofDescriptor* oneof_descriptor) const {
+ void* ptr = reinterpret_cast<uint8*>(message) + oneof_case_offset_;
+ return &(reinterpret_cast<uint32*>(ptr)[oneof_descriptor->index()]);
+}
+
inline const ExtensionSet& GeneratedMessageReflection::GetExtensionSet(
const Message& message) const {
GOOGLE_DCHECK_NE(extensions_offset_, -1);
@@ -1142,23 +1813,196 @@ inline ExtensionSet* GeneratedMessageReflection::MutableExtensionSet(
return reinterpret_cast<ExtensionSet*>(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<uint8*>(message) + arena_offset_;
+ return *reinterpret_cast<Arena**>(ptr);
+}
+
+inline const InternalMetadataWithArena&
+GeneratedMessageReflection::GetInternalMetadataWithArena(
+ const Message& message) const {
+ const void* ptr = reinterpret_cast<const uint8*>(&message) + arena_offset_;
+ return *reinterpret_cast<const InternalMetadataWithArena*>(ptr);
+}
+
+inline InternalMetadataWithArena*
+GeneratedMessageReflection::MutableInternalMetadataWithArena(
+ Message* message) const {
+ void* ptr = reinterpret_cast<uint8*>(message) + arena_offset_;
+ return reinterpret_cast<InternalMetadataWithArena*>(ptr);
+}
+
+inline bool
+GeneratedMessageReflection::GetIsDefaultInstance(
+ const Message& message) const {
+ if (is_default_instance_offset_ == kHasNoDefaultInstanceField) {
+ return false;
+ }
+ const void* ptr = reinterpret_cast<const uint8*>(&message) +
+ is_default_instance_offset_;
+ return *reinterpret_cast<const bool*>(ptr);
+}
+
// Simple accessors for manipulating has_bits_.
inline bool GeneratedMessageReflection::HasBit(
const Message& message, const FieldDescriptor* field) const {
+ 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 !GetIsDefaultInstance(message) &&
+ GetRaw<const Message*>(message, field) != NULL;
+ } else {
+ // Non-message field (and non-oneof, since that was handled in HasField()
+ // before calling us), and singular (again, checked in HasField). So, this
+ // 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<ArenaStringPtr>(field).Get(NULL);
+ return GetField<ArenaStringPtr>(message, field).Get(
+ default_ptr).size() > 0;
+ }
+ }
+ return false;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return GetRaw<bool>(message, field) != false;
+ case FieldDescriptor::CPPTYPE_INT32:
+ return GetRaw<int32>(message, field) != 0;
+ case FieldDescriptor::CPPTYPE_INT64:
+ return GetRaw<int64>(message, field) != 0;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return GetRaw<uint32>(message, field) != 0;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return GetRaw<uint64>(message, field) != 0;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return GetRaw<float>(message, field) != 0.0;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return GetRaw<double>(message, field) != 0.0;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return GetRaw<int>(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);
+ } else {
+ ClearBit(message1, field);
+ }
+ if (temp_has_bit) {
+ SetBit(message2, field);
+ } else {
+ ClearBit(message2, field);
+ }
+}
+
+inline bool GeneratedMessageReflection::HasOneof(
+ const Message& message, const OneofDescriptor* oneof_descriptor) const {
+ return (GetOneofCase(message, oneof_descriptor) > 0);
+}
+
+inline bool GeneratedMessageReflection::HasOneofField(
+ const Message& message, const FieldDescriptor* field) const {
+ return (GetOneofCase(message, field->containing_oneof()) == field->number());
+}
+
+inline void GeneratedMessageReflection::SetOneofCase(
+ Message* message, const FieldDescriptor* field) const {
+ *MutableOneofCase(message, field->containing_oneof()) = field->number();
+}
+
+inline void GeneratedMessageReflection::ClearOneofField(
+ Message* message, const FieldDescriptor* field) const {
+ if (HasOneofField(*message, field)) {
+ ClearOneof(message, field->containing_oneof());
+ }
+}
+
+inline void GeneratedMessageReflection::ClearOneof(
+ Message* message, const OneofDescriptor* oneof_descriptor) const {
+ // TODO(jieluo): Consider to cache the unused object instead of deleting
+ // it. It will be much faster if an aplication switches a lot from
+ // a few oneof fields. Time/space tradeoff
+ uint32 oneof_case = GetOneofCase(*message, oneof_descriptor);
+ if (oneof_case > 0) {
+ const FieldDescriptor* field = descriptor_->FindFieldByNumber(oneof_case);
+ if (GetArena(message) == NULL) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_STRING: {
+ switch (field->options().ctype()) {
+ default: // TODO(kenton): Support other string reps.
+ case FieldOptions::STRING: {
+ const string* default_ptr =
+ &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+ MutableField<ArenaStringPtr>(message, field)->
+ Destroy(default_ptr, GetArena(message));
+ break;
+ }
+ }
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ delete *MutableRaw<Message*>(message, field);
+ break;
+ default:
+ break;
+ }
+ }
+
+ *MutableOneofCase(message, oneof_descriptor) = 0;
+ }
+}
+
// Template implementations of basic accessors. Inline because each
// template instance is only called from one location. These are
// used for all types except messages.
@@ -1171,14 +2015,19 @@ inline const Type& GeneratedMessageReflection::GetField(
template <typename Type>
inline void GeneratedMessageReflection::SetField(
Message* message, const FieldDescriptor* field, const Type& value) const {
+ if (field->containing_oneof() && !HasOneofField(*message, field)) {
+ ClearOneof(message, field->containing_oneof());
+ }
*MutableRaw<Type>(message, field) = value;
- SetBit(message, field);
+ field->containing_oneof() ?
+ SetOneofCase(message, field) : SetBit(message, field);
}
template <typename Type>
inline Type* GeneratedMessageReflection::MutableField(
Message* message, const FieldDescriptor* field) const {
- SetBit(message, field);
+ field->containing_oneof() ?
+ SetOneofCase(message, field) : SetBit(message, field);
return MutableRaw<Type>(message, field);
}
@@ -1223,6 +2072,84 @@ 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<T> 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<uint8*>(message) + offsets_[field->index()];
+ }
+}
+
+GeneratedMessageReflection*
+GeneratedMessageReflection::NewGeneratedMessageReflection(
+ const Descriptor* descriptor,
+ const Message* default_instance,
+ const int offsets[],
+ int has_bits_offset,
+ int unknown_fields_offset,
+ int extensions_offset,
+ const void* default_oneof_instance,
+ int oneof_case_offset,
+ int object_size,
+ int arena_offset,
+ int is_default_instance_offset) {
+ return new GeneratedMessageReflection(descriptor,
+ default_instance,
+ offsets,
+ has_bits_offset,
+ unknown_fields_offset,
+ extensions_offset,
+ default_oneof_instance,
+ oneof_case_offset,
+ DescriptorPool::generated_pool(),
+ MessageFactory::generated_factory(),
+ object_size,
+ arena_offset,
+ is_default_instance_offset);
+}
+
+GeneratedMessageReflection*
+GeneratedMessageReflection::NewGeneratedMessageReflection(
+ const Descriptor* descriptor,
+ const Message* default_instance,
+ const int offsets[],
+ int has_bits_offset,
+ int unknown_fields_offset,
+ int extensions_offset,
+ int object_size,
+ int arena_offset,
+ int is_default_instance_offset) {
+ return new GeneratedMessageReflection(descriptor,
+ default_instance,
+ offsets,
+ has_bits_offset,
+ unknown_fields_offset,
+ extensions_offset,
+ DescriptorPool::generated_pool(),
+ MessageFactory::generated_factory(),
+ object_size,
+ arena_offset,
+ is_default_instance_offset);
+}
+
} // 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 b545fa1a..4dddf6c7 100644
--- a/src/google/protobuf/generated_message_reflection.h
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -40,21 +40,29 @@
#include <string>
#include <vector>
+#include <google/protobuf/stubs/common.h>
+// TODO(jasonh): Remove this once the compiler change to directly include this
+// is released to components.
+#include <google/protobuf/generated_enum_reflection.h>
#include <google/protobuf/message.h>
+#include <google/protobuf/metadata.h>
#include <google/protobuf/unknown_field_set.h>
namespace google {
+namespace upb {
+namespace google_opensource {
+class GMR_Handlers;
+} // namespace google_opensource
+} // namespace upb
+
namespace protobuf {
class DescriptorPool;
- // Generated code needs these to have been forward-declared. Easier to do it
- // here than to print them inside every .pb.h file.
- class FileDescriptor;
- class EnumDescriptor;
}
namespace protobuf {
namespace internal {
+class DefaultEmptyOneof;
// Defined in this file.
class GeneratedMessageReflection;
@@ -127,9 +135,77 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
int extensions_offset,
const DescriptorPool* pool,
MessageFactory* factory,
- int object_size);
+ int object_size,
+ int arena_offset,
+ int is_default_instance_offset = -1);
+
+ // Similar with the construction above. Call this construction if the
+ // message has oneof definition.
+ // Parameters:
+ // offsets: An array of ints giving the byte offsets.
+ // For each oneof field, the offset is relative to the
+ // default_oneof_instance. These can be computed at compile
+ // time using the
+ // PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET() macro.
+ // For each none oneof field, the offset is related to
+ // the start of the message object. These can be computed
+ // at compile time using the
+ // GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET() macro.
+ // Besides offsets for all fields, this array also contains
+ // offsets for oneof unions. The offset of the i-th oneof
+ // union is offsets[descriptor->field_count() + i].
+ // default_oneof_instance: The default instance of the oneofs. It is a
+ // struct holding the default value of all oneof fields
+ // for this message. It is only used to obtain pointers
+ // to default instances of oneof fields, which Get
+ // methods will return if the field is not set.
+ // oneof_case_offset: Offset in the message of an array of uint32s of
+ // size descriptor->oneof_decl_count(). Each uint32
+ // indicates what field is set for each oneof.
+ // other parameters are the same with the construction above.
+ GeneratedMessageReflection(const Descriptor* descriptor,
+ const Message* default_instance,
+ const int offsets[],
+ int has_bits_offset,
+ int unknown_fields_offset,
+ int extensions_offset,
+ const void* default_oneof_instance,
+ int oneof_case_offset,
+ const DescriptorPool* pool,
+ MessageFactory* factory,
+ int object_size,
+ int arena_offset,
+ int is_default_instance_offset = -1);
~GeneratedMessageReflection();
+ // Shorter-to-call helpers for the above two constructions that work if the
+ // pool and factory are the usual, namely, DescriptorPool::generated_pool()
+ // and MessageFactory::generated_factory().
+
+ static GeneratedMessageReflection* NewGeneratedMessageReflection(
+ const Descriptor* descriptor,
+ const Message* default_instance,
+ const int offsets[],
+ int has_bits_offset,
+ int unknown_fields_offset,
+ int extensions_offset,
+ const void* default_oneof_instance,
+ int oneof_case_offset,
+ int object_size,
+ int arena_offset,
+ int is_default_instance_offset = -1);
+
+ static GeneratedMessageReflection* NewGeneratedMessageReflection(
+ const Descriptor* descriptor,
+ const Message* default_instance,
+ const int offsets[],
+ int has_bits_offset,
+ int unknown_fields_offset,
+ int extensions_offset,
+ int object_size,
+ int arena_offset,
+ int is_default_instance_offset = -1);
+
// implements Reflection -------------------------------------------
const UnknownFieldSet& GetUnknownFields(const Message& message) const;
@@ -140,10 +216,16 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
bool HasField(const Message& message, const FieldDescriptor* field) const;
int FieldSize(const Message& message, const FieldDescriptor* field) const;
void ClearField(Message* message, const FieldDescriptor* field) const;
+ bool HasOneof(const Message& message,
+ const OneofDescriptor* oneof_descriptor) const;
+ void ClearOneof(Message* message, const OneofDescriptor* field) const;
void RemoveLast(Message* message, const FieldDescriptor* field) const;
+ Message* ReleaseLast(Message* message, const FieldDescriptor* field) const;
void Swap(Message* message1, Message* message2) const;
+ void SwapFields(Message* message1, Message* message2,
+ const vector<const FieldDescriptor*>& fields) const;
void SwapElements(Message* message, const FieldDescriptor* field,
- int index1, int index2) const;
+ int index1, int index2) const;
void ListFields(const Message& message,
vector<const FieldDescriptor*>* output) const;
@@ -168,10 +250,17 @@ 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;
+ const FieldDescriptor* GetOneofFieldDescriptor(
+ const Message& message,
+ const OneofDescriptor* oneof_descriptor) const;
+
+ public:
void SetInt32 (Message* message,
const FieldDescriptor* field, int32 value) const;
void SetInt64 (Message* message,
@@ -191,8 +280,15 @@ 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,
+ Message* sub_message,
+ const FieldDescriptor* field) const;
+ Message* ReleaseMessage(Message* message, const FieldDescriptor* field,
+ MessageFactory* factory = NULL) const;
int32 GetRepeatedInt32 (const Message& message,
const FieldDescriptor* field, int index) const;
@@ -216,6 +312,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;
@@ -240,6 +339,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,
@@ -264,24 +365,64 @@ 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;
+ // To parse directly into a proto2 generated class, the class GMR_Handlers
+ // needs access to member offsets and hasbits.
+ friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers;
+
const Descriptor* descriptor_;
const Message* default_instance_;
+ const void* default_oneof_instance_;
const int* offsets_;
int has_bits_offset_;
+ int oneof_case_offset_;
int unknown_fields_offset_;
int extensions_offset_;
+ int arena_offset_;
+ int is_default_instance_offset_;
int object_size_;
+ static const int kHasNoDefaultInstanceField = -1;
+
const DescriptorPool* descriptor_pool_;
MessageFactory* message_factory_;
@@ -293,12 +434,26 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
const FieldDescriptor* field) const;
template <typename Type>
inline const Type& DefaultRaw(const FieldDescriptor* field) const;
- inline const Message* GetMessagePrototype(const FieldDescriptor* field) const;
+ template <typename Type>
+ inline const Type& DefaultOneofRaw(const FieldDescriptor* field) const;
inline const uint32* GetHasBits(const Message& message) const;
inline uint32* MutableHasBits(Message* message) const;
+ inline uint32 GetOneofCase(
+ const Message& message,
+ const OneofDescriptor* oneof_descriptor) const;
+ inline uint32* MutableOneofCase(
+ Message* message,
+ 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 GetIsDefaultInstance(const Message& message) const;
inline bool HasBit(const Message& message,
const FieldDescriptor* field) const;
@@ -306,6 +461,26 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
const FieldDescriptor* field) const;
inline void ClearBit(Message* message,
const FieldDescriptor* field) const;
+ inline void SwapBit(Message* message1,
+ Message* message2,
+ const FieldDescriptor* field) const;
+
+ // This function only swaps the field. Should swap corresponding has_bit
+ // before or after using this function.
+ void SwapField(Message* message1,
+ Message* message2,
+ const FieldDescriptor* field) const;
+
+ void SwapOneofField(Message* message1,
+ Message* message2,
+ const OneofDescriptor* oneof_descriptor) const;
+
+ inline bool HasOneofField(const Message& message,
+ const FieldDescriptor* field) const;
+ inline void SetOneofCase(Message* message,
+ const FieldDescriptor* field) const;
+ inline void ClearOneofField(Message* message,
+ const FieldDescriptor* field) const;
template <typename Type>
inline const Type& GetField(const Message& message,
@@ -341,6 +516,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);
};
@@ -359,9 +556,14 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
// be confused by an unaligned pointer.
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \
static_cast<int>( \
- reinterpret_cast<const char*>( \
- &reinterpret_cast<const TYPE*>(16)->FIELD) - \
- reinterpret_cast<const char*>(16))
+ reinterpret_cast<const char*>( \
+ &reinterpret_cast<const TYPE*>(16)->FIELD) - \
+ reinterpret_cast<const char*>(16))
+
+#define PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ONEOF, FIELD) \
+ static_cast<int>( \
+ reinterpret_cast<const char*>(&(ONEOF->FIELD)) \
+ - reinterpret_cast<const char*>(ONEOF))
// There are some places in proto2 where dynamic_cast would be useful as an
// optimization. For example, take Message::MergeFrom(const Message& other).
@@ -395,28 +597,6 @@ inline To dynamic_cast_if_available(From from) {
#endif
}
-// Helper for EnumType_Parse functions: try to parse the string 'name' as an
-// enum name of the given type, returning true and filling in value on success,
-// or returning false and leaving value unchanged on failure.
-LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
- const string& name,
- int* value);
-
-template<typename EnumType>
-bool ParseNamedEnum(const EnumDescriptor* descriptor,
- const string& name,
- EnumType* value) {
- int tmp;
- if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
- *value = static_cast<EnumType>(tmp);
- return true;
-}
-
-// Just a wrapper around printing the name of a value. The main point of this
-// function is not to be inlined, so that you can do this without including
-// descriptor.h.
-LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
-
} // namespace internal
} // namespace protobuf
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index a03bcdb7..ca1a2918 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -207,6 +207,111 @@ TEST(GeneratedMessageReflectionTest, SwapUnknown) {
EXPECT_EQ(1, message2.unknown_fields().field_count());
}
+TEST(GeneratedMessageReflectionTest, SwapFields) {
+ unittest::TestAllTypes message1, message2;
+ message1.set_optional_double(12.3);
+ message1.mutable_repeated_int32()->Add(10);
+ message1.mutable_repeated_int32()->Add(20);
+
+ message2.set_optional_string("hello");
+ message2.mutable_repeated_int64()->Add(30);
+
+ vector<const FieldDescriptor*> fields;
+ const Descriptor* descriptor = message1.GetDescriptor();
+ fields.push_back(descriptor->FindFieldByName("optional_double"));
+ fields.push_back(descriptor->FindFieldByName("repeated_int32"));
+ fields.push_back(descriptor->FindFieldByName("optional_string"));
+ fields.push_back(descriptor->FindFieldByName("optional_uint64"));
+
+ const Reflection* reflection = message1.GetReflection();
+ reflection->SwapFields(&message1, &message2, fields);
+
+ EXPECT_FALSE(message1.has_optional_double());
+ EXPECT_EQ(0, message1.repeated_int32_size());
+ EXPECT_TRUE(message1.has_optional_string());
+ EXPECT_EQ("hello", message1.optional_string());
+ EXPECT_EQ(0, message1.repeated_int64_size());
+ EXPECT_FALSE(message1.has_optional_uint64());
+
+ EXPECT_TRUE(message2.has_optional_double());
+ EXPECT_EQ(12.3, message2.optional_double());
+ EXPECT_EQ(2, message2.repeated_int32_size());
+ EXPECT_EQ(10, message2.repeated_int32(0));
+ EXPECT_EQ(20, message2.repeated_int32(1));
+ EXPECT_FALSE(message2.has_optional_string());
+ EXPECT_EQ(1, message2.repeated_int64_size());
+ EXPECT_FALSE(message2.has_optional_uint64());
+}
+
+TEST(GeneratedMessageReflectionTest, SwapFieldsAll) {
+ unittest::TestAllTypes message1;
+ unittest::TestAllTypes message2;
+
+ TestUtil::SetAllFields(&message2);
+
+ vector<const FieldDescriptor*> fields;
+ const Reflection* reflection = message1.GetReflection();
+ reflection->ListFields(message2, &fields);
+ reflection->SwapFields(&message1, &message2, fields);
+
+ TestUtil::ExpectAllFieldsSet(message1);
+ TestUtil::ExpectClear(message2);
+}
+
+TEST(GeneratedMessageReflectionTest, SwapFieldsAllExtension) {
+ unittest::TestAllExtensions message1;
+ unittest::TestAllExtensions message2;
+
+ TestUtil::SetAllExtensions(&message1);
+
+ vector<const FieldDescriptor*> fields;
+ const Reflection* reflection = message1.GetReflection();
+ reflection->ListFields(message1, &fields);
+ reflection->SwapFields(&message1, &message2, fields);
+
+ TestUtil::ExpectExtensionsClear(message1);
+ TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(GeneratedMessageReflectionTest, SwapOneof) {
+ unittest::TestOneof2 message1, message2;
+ TestUtil::SetOneof1(&message1);
+
+ const Reflection* reflection = message1.GetReflection();
+ reflection->Swap(&message1, &message2);
+
+ TestUtil::ExpectOneofClear(message1);
+ TestUtil::ExpectOneofSet1(message2);
+}
+
+TEST(GeneratedMessageReflectionTest, SwapOneofBothSet) {
+ unittest::TestOneof2 message1, message2;
+ TestUtil::SetOneof1(&message1);
+ TestUtil::SetOneof2(&message2);
+
+ const Reflection* reflection = message1.GetReflection();
+ reflection->Swap(&message1, &message2);
+
+ TestUtil::ExpectOneofSet2(message1);
+ TestUtil::ExpectOneofSet1(message2);
+}
+
+TEST(GeneratedMessageReflectionTest, SwapFieldsOneof) {
+ unittest::TestOneof2 message1, message2;
+ TestUtil::SetOneof1(&message1);
+
+ vector<const FieldDescriptor*> fields;
+ const Descriptor* descriptor = message1.GetDescriptor();
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ fields.push_back(descriptor->field(i));
+ }
+ const Reflection* reflection = message1.GetReflection();
+ reflection->SwapFields(&message1, &message2, fields);
+
+ TestUtil::ExpectOneofClear(message1);
+ TestUtil::ExpectOneofSet1(message2);
+}
+
TEST(GeneratedMessageReflectionTest, RemoveLast) {
unittest::TestAllTypes message;
TestUtil::ReflectionTester reflection_tester(
@@ -225,11 +330,59 @@ TEST(GeneratedMessageReflectionTest, RemoveLastExtensions) {
unittest::TestAllExtensions::descriptor());
TestUtil::SetAllExtensions(&message);
+
reflection_tester.RemoveLastRepeatedsViaReflection(&message);
TestUtil::ExpectLastRepeatedExtensionsRemoved(message);
}
+TEST(GeneratedMessageReflectionTest, ReleaseLast) {
+ unittest::TestAllTypes message;
+ const Descriptor* descriptor = message.GetDescriptor();
+ TestUtil::ReflectionTester reflection_tester(descriptor);
+
+ TestUtil::SetAllFields(&message);
+
+ reflection_tester.ReleaseLastRepeatedsViaReflection(&message, false);
+
+ TestUtil::ExpectLastRepeatedsReleased(message);
+
+ // Now test that we actually release the right message.
+ message.Clear();
+ TestUtil::SetAllFields(&message);
+ ASSERT_EQ(2, message.repeated_foreign_message_size());
+ const protobuf_unittest::ForeignMessage* expected =
+ message.mutable_repeated_foreign_message(1);
+ scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
+ &message, descriptor->FindFieldByName("repeated_foreign_message")));
+ EXPECT_EQ(expected, released.get());
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseLastExtensions) {
+ unittest::TestAllExtensions message;
+ const Descriptor* descriptor = message.GetDescriptor();
+ TestUtil::ReflectionTester reflection_tester(descriptor);
+
+ TestUtil::SetAllExtensions(&message);
+
+ reflection_tester.ReleaseLastRepeatedsViaReflection(&message, true);
+
+ TestUtil::ExpectLastRepeatedExtensionsReleased(message);
+
+ // Now test that we actually release the right message.
+ message.Clear();
+ TestUtil::SetAllExtensions(&message);
+ ASSERT_EQ(2, message.ExtensionSize(
+ unittest::repeated_foreign_message_extension));
+ const protobuf_unittest::ForeignMessage* expected = message.MutableExtension(
+ unittest::repeated_foreign_message_extension, 1);
+ scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
+ &message, descriptor->file()->FindExtensionByName(
+ "repeated_foreign_message_extension")));
+ EXPECT_EQ(expected, released.get());
+
+}
+
TEST(GeneratedMessageReflectionTest, SwapRepeatedElements) {
unittest::TestAllTypes message;
TestUtil::ReflectionTester reflection_tester(
@@ -327,7 +480,265 @@ TEST(GeneratedMessageReflectionTest, FindKnownExtensionByName) {
FindKnownExtensionByName(extension1->full_name()) == NULL);
}
-#ifdef GTEST_HAS_DEATH_TEST
+TEST(GeneratedMessageReflectionTest, SetAllocatedMessageTest) {
+ unittest::TestAllTypes from_message1;
+ unittest::TestAllTypes from_message2;
+ unittest::TestAllTypes to_message;
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllTypes::descriptor());
+ reflection_tester.SetAllFieldsViaReflection(&from_message1);
+ reflection_tester.SetAllFieldsViaReflection(&from_message2);
+
+ // Before moving fields, we expect the nested messages to be NULL.
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &to_message, TestUtil::ReflectionTester::IS_NULL);
+
+ // After fields are moved we should get non-NULL releases.
+ reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+ &from_message1, &to_message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // Another move to make sure that we can SetAllocated several times.
+ reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+ &from_message2, &to_message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // After SetAllocatedOptionalMessageFieldsToNullViaReflection() we expect the
+ // releases to be NULL again.
+ reflection_tester.SetAllocatedOptionalMessageFieldsToNullViaReflection(
+ &to_message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &to_message, TestUtil::ReflectionTester::IS_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, SetAllocatedExtensionMessageTest) {
+ unittest::TestAllExtensions from_message1;
+ unittest::TestAllExtensions from_message2;
+ unittest::TestAllExtensions to_message;
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllExtensions::descriptor());
+ reflection_tester.SetAllFieldsViaReflection(&from_message1);
+ reflection_tester.SetAllFieldsViaReflection(&from_message2);
+
+ // Before moving fields, we expect the nested messages to be NULL.
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &to_message, TestUtil::ReflectionTester::IS_NULL);
+
+ // After fields are moved we should get non-NULL releases.
+ reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+ &from_message1, &to_message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // Another move to make sure that we can SetAllocated several times.
+ reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+ &from_message2, &to_message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // After SetAllocatedOptionalMessageFieldsToNullViaReflection() we expect the
+ // releases to be NULL again.
+ reflection_tester.SetAllocatedOptionalMessageFieldsToNullViaReflection(
+ &to_message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &to_message, TestUtil::ReflectionTester::IS_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, ListFieldsOneOf) {
+ unittest::TestOneof2 message;
+ TestUtil::SetOneof1(&message);
+
+ const Reflection* reflection = message.GetReflection();
+ vector<const FieldDescriptor*> fields;
+ reflection->ListFields(message, &fields);
+ EXPECT_EQ(4, fields.size());
+}
+
+TEST(GeneratedMessageReflectionTest, Oneof) {
+ unittest::TestOneof2 message;
+ const Descriptor* descriptor = message.GetDescriptor();
+ const Reflection* reflection = message.GetReflection();
+
+ // Check default values.
+ EXPECT_EQ(0, reflection->GetInt32(
+ message, descriptor->FindFieldByName("foo_int")));
+ EXPECT_EQ("", reflection->GetString(
+ message, descriptor->FindFieldByName("foo_string")));
+ EXPECT_EQ("", reflection->GetString(
+ message, descriptor->FindFieldByName("foo_cord")));
+ EXPECT_EQ("", reflection->GetString(
+ message, descriptor->FindFieldByName("foo_string_piece")));
+ EXPECT_EQ("", reflection->GetString(
+ message, descriptor->FindFieldByName("foo_bytes")));
+ EXPECT_EQ(unittest::TestOneof2::FOO, reflection->GetEnum(
+ message, descriptor->FindFieldByName("foo_enum"))->number());
+ EXPECT_EQ(&unittest::TestOneof2::NestedMessage::default_instance(),
+ &reflection->GetMessage(
+ message, descriptor->FindFieldByName("foo_message")));
+ EXPECT_EQ(&unittest::TestOneof2::FooGroup::default_instance(),
+ &reflection->GetMessage(
+ message, descriptor->FindFieldByName("foogroup")));
+ EXPECT_NE(&unittest::TestOneof2::FooGroup::default_instance(),
+ &reflection->GetMessage(
+ message, descriptor->FindFieldByName("foo_lazy_message")));
+ EXPECT_EQ(5, reflection->GetInt32(
+ message, descriptor->FindFieldByName("bar_int")));
+ EXPECT_EQ("STRING", reflection->GetString(
+ message, descriptor->FindFieldByName("bar_string")));
+ EXPECT_EQ("CORD", reflection->GetString(
+ message, descriptor->FindFieldByName("bar_cord")));
+ EXPECT_EQ("SPIECE", reflection->GetString(
+ message, descriptor->FindFieldByName("bar_string_piece")));
+ EXPECT_EQ("BYTES", reflection->GetString(
+ message, descriptor->FindFieldByName("bar_bytes")));
+ EXPECT_EQ(unittest::TestOneof2::BAR, reflection->GetEnum(
+ message, descriptor->FindFieldByName("bar_enum"))->number());
+
+ // Check Set functions.
+ reflection->SetInt32(
+ &message, descriptor->FindFieldByName("foo_int"), 123);
+ EXPECT_EQ(123, reflection->GetInt32(
+ message, descriptor->FindFieldByName("foo_int")));
+ reflection->SetString(
+ &message, descriptor->FindFieldByName("foo_string"), "abc");
+ EXPECT_EQ("abc", reflection->GetString(
+ message, descriptor->FindFieldByName("foo_string")));
+ reflection->SetString(
+ &message, descriptor->FindFieldByName("foo_bytes"), "bytes");
+ EXPECT_EQ("bytes", reflection->GetString(
+ message, descriptor->FindFieldByName("foo_bytes")));
+ reflection->SetString(
+ &message, descriptor->FindFieldByName("bar_cord"), "change_cord");
+ EXPECT_EQ("change_cord", reflection->GetString(
+ message, descriptor->FindFieldByName("bar_cord")));
+ reflection->SetString(
+ &message, descriptor->FindFieldByName("bar_string_piece"),
+ "change_spiece");
+ EXPECT_EQ("change_spiece", reflection->GetString(
+ message, descriptor->FindFieldByName("bar_string_piece")));
+}
+
+TEST(GeneratedMessageReflectionTest, SetAllocatedOneofMessageTest) {
+ unittest::TestOneof2 from_message1;
+ unittest::TestOneof2 from_message2;
+ unittest::TestOneof2 to_message;
+ const Descriptor* descriptor = unittest::TestOneof2::descriptor();
+ const Reflection* reflection = to_message.GetReflection();
+
+ Message* released = reflection->ReleaseMessage(
+ &to_message, descriptor->FindFieldByName("foo_lazy_message"));
+ EXPECT_TRUE(released == NULL);
+ released = reflection->ReleaseMessage(
+ &to_message, descriptor->FindFieldByName("foo_message"));
+ EXPECT_TRUE(released == NULL);
+
+ TestUtil::ReflectionTester::SetOneofViaReflection(&from_message1);
+ TestUtil::ReflectionTester::ExpectOneofSetViaReflection(from_message1);
+
+ TestUtil::ReflectionTester::
+ SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+ &from_message1, &to_message);
+ const Message& sub_message = reflection->GetMessage(
+ to_message, descriptor->FindFieldByName("foo_lazy_message"));
+ released = reflection->ReleaseMessage(
+ &to_message, descriptor->FindFieldByName("foo_lazy_message"));
+ EXPECT_TRUE(released != NULL);
+ EXPECT_EQ(&sub_message, released);
+ delete released;
+
+ TestUtil::ReflectionTester::SetOneofViaReflection(&from_message2);
+
+ reflection->MutableMessage(
+ &from_message2, descriptor->FindFieldByName("foo_message"));
+
+ TestUtil::ReflectionTester::
+ SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+ &from_message2, &to_message);
+
+ const Message& sub_message2 = reflection->GetMessage(
+ to_message, descriptor->FindFieldByName("foo_message"));
+ released = reflection->ReleaseMessage(
+ &to_message, descriptor->FindFieldByName("foo_message"));
+ EXPECT_TRUE(released != NULL);
+ EXPECT_EQ(&sub_message2, released);
+ delete released;
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseMessageTest) {
+ unittest::TestAllTypes message;
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllTypes::descriptor());
+
+ // When nothing is set, we expect all released messages to be NULL.
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::IS_NULL);
+
+ // After fields are set we should get non-NULL releases.
+ reflection_tester.SetAllFieldsViaReflection(&message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // After Clear() we may or may not get a message from ReleaseMessage().
+ // This is implementation specific.
+ reflection_tester.SetAllFieldsViaReflection(&message);
+ message.Clear();
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::CAN_BE_NULL);
+
+ // Test a different code path for setting after releasing.
+ TestUtil::SetAllFields(&message);
+ TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseExtensionMessageTest) {
+ unittest::TestAllExtensions message;
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllExtensions::descriptor());
+
+ // When nothing is set, we expect all released messages to be NULL.
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::IS_NULL);
+
+ // After fields are set we should get non-NULL releases.
+ reflection_tester.SetAllFieldsViaReflection(&message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // After Clear() we may or may not get a message from ReleaseMessage().
+ // This is implementation specific.
+ reflection_tester.SetAllFieldsViaReflection(&message);
+ message.Clear();
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ &message, TestUtil::ReflectionTester::CAN_BE_NULL);
+
+ // Test a different code path for setting after releasing.
+ TestUtil::SetAllExtensions(&message);
+ TestUtil::ExpectAllExtensionsSet(message);
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseOneofMessageTest) {
+ unittest::TestOneof2 message;
+ TestUtil::ReflectionTester::SetOneofViaReflection(&message);
+
+ const Descriptor* descriptor = unittest::TestOneof2::descriptor();
+ const Reflection* reflection = message.GetReflection();
+ const Message& sub_message = reflection->GetMessage(
+ message, descriptor->FindFieldByName("foo_lazy_message"));
+ Message* released = reflection->ReleaseMessage(
+ &message, descriptor->FindFieldByName("foo_lazy_message"));
+
+ EXPECT_TRUE(released != NULL);
+ EXPECT_EQ(&sub_message, released);
+ delete released;
+
+ released = reflection->ReleaseMessage(
+ &message, descriptor->FindFieldByName("foo_lazy_message"));
+ EXPECT_TRUE(released == NULL);
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
TEST(GeneratedMessageReflectionTest, UsageErrors) {
unittest::TestAllTypes message;
@@ -376,7 +787,7 @@ TEST(GeneratedMessageReflectionTest, UsageErrors) {
#undef f
}
-#endif // GTEST_HAS_DEATH_TEST
+#endif // PROTOBUF_HAS_DEATH_TEST
} // namespace
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index 76e547bb..53cae8b5 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -36,6 +36,7 @@
#include <limits>
+
namespace google {
namespace protobuf {
namespace internal {
@@ -47,7 +48,17 @@ double NaN() {
return std::numeric_limits<double>::quiet_NaN();
}
-const ::std::string kEmptyString;
+const ::std::string* empty_string_;
+GOOGLE_PROTOBUF_DECLARE_ONCE(empty_string_once_init_);
+
+void DeleteEmptyString() {
+ delete empty_string_;
+}
+
+void InitEmptyString() {
+ empty_string_ = new string;
+ OnShutdown(&DeleteEmptyString);
+}
} // namespace internal
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 1a2343d4..678f92a7 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -38,21 +38,18 @@
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
+#include <assert.h>
#include <string>
-#include <google/protobuf/stubs/common.h>
-
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/common.h>
namespace google {
-namespace protobuf {
- namespace io {
- class CodedInputStream; // coded_stream.h
- }
-}
namespace protobuf {
namespace internal {
+
// Annotation for the compiler to emit a deprecation message if a field marked
// with option 'deprecated=true' is used in the code, or for other things in
// generated code which are deprecated.
@@ -60,20 +57,54 @@ namespace internal {
// For internal use in the pb.cc files, deprecation warnings are suppressed
// there.
#undef DEPRECATED_PROTOBUF_FIELD
-#if !defined(INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION)
-# define PROTOBUF_DEPRECATED GOOGLE_ATTRIBUTE_DEPRECATED
-#else
-# define PROTOBUF_DEPRECATED
-#endif
+#define PROTOBUF_DEPRECATED
// Constants for special floating point values.
-double Infinity();
-double NaN();
+LIBPROTOBUF_EXPORT double Infinity();
+LIBPROTOBUF_EXPORT double NaN();
+
+// TODO(jieluo): Change to template. We have tried to use template,
+// but it causes net/rpc/python:rpcutil_test fail (the empty string will
+// init twice). It may related to swig. Change to template after we
+// found the solution.
+
+// Default empty string object. Don't use the pointer directly. Instead, call
+// GetEmptyString() to get the reference.
+LIBPROTOBUF_EXPORT extern const ::std::string* empty_string_;
+LIBPROTOBUF_EXPORT extern ProtobufOnceType empty_string_once_init_;
+LIBPROTOBUF_EXPORT void InitEmptyString();
-// Constant used for empty default strings.
-extern const ::std::string kEmptyString;
+LIBPROTOBUF_EXPORT inline const ::std::string& GetEmptyStringAlreadyInited() {
+ assert(empty_string_ != NULL);
+ return *empty_string_;
+}
+LIBPROTOBUF_EXPORT inline const ::std::string& GetEmptyString() {
+ ::google::protobuf::GoogleOnceInit(&empty_string_once_init_, &InitEmptyString);
+ return GetEmptyStringAlreadyInited();
+}
+
+// Defined in generated_message_reflection.cc -- not actually part of the lite
+// library.
+//
+// TODO(jasonh): The various callers get this declaration from a variety of
+// places: probably in most cases repeated_field.h. Clean these up so they all
+// get the declaration from this file.
+LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str);
+
+
+// True if IsInitialized() is true for all elements of t. Type is expected
+// to be a RepeatedPtrField<some message type>. It's useful to have this
+// helper here to keep the protobuf compiler from ever having to emit loops in
+// IsInitialized() methods. We want the C++ compiler to inline this or not
+// as it sees fit.
+template <class Type> bool AllAreInitialized(const Type& t) {
+ for (int i = t.size(); --i >= 0; ) {
+ if (!t.Get(i).IsInitialized()) return false;
+ }
+ return true;
+}
} // namespace internal
} // namespace protobuf
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index 57d486f9..93e1a22e 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -40,10 +40,12 @@
#include <google/protobuf/io/coded_stream_inl.h>
#include <algorithm>
+#include <utility>
#include <limits.h>
#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/arena.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
@@ -69,6 +71,23 @@ inline bool NextNonEmpty(ZeroCopyInputStream* input,
// CodedInputStream ==================================================
+CodedInputStream::~CodedInputStream() {
+ if (input_ != NULL) {
+ BackUpInputToCurrentPosition();
+ }
+
+ if (total_bytes_warning_threshold_ == -2) {
+ GOOGLE_LOG(WARNING) << "The total number of bytes read was " << total_bytes_read_;
+ }
+}
+
+// Static.
+int CodedInputStream::default_recursion_limit_ = 100;
+
+
+void CodedOutputStream::EnableAliasing(bool enabled) {
+ aliasing_enabled_ = enabled && output_->AllowsAliasing();
+}
void CodedInputStream::BackUpInputToCurrentPosition() {
int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
@@ -98,8 +117,7 @@ inline void CodedInputStream::RecomputeBufferLimits() {
CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
// Current position relative to the beginning of the stream.
- int current_position = total_bytes_read_ -
- (BufferSize() + buffer_size_after_limit_);
+ int current_position = CurrentPosition();
Limit old_limit = current_limit_;
@@ -133,10 +151,22 @@ void CodedInputStream::PopLimit(Limit limit) {
legitimate_message_end_ = false;
}
-int CodedInputStream::BytesUntilLimit() {
+std::pair<CodedInputStream::Limit, int>
+CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
+ return std::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 = total_bytes_read_ -
- (BufferSize() + buffer_size_after_limit_);
+ int current_position = CurrentPosition();
return current_limit_ - current_position;
}
@@ -145,13 +175,22 @@ void CodedInputStream::SetTotalBytesLimit(
int total_bytes_limit, int warning_threshold) {
// Make sure the limit isn't already past, since this could confuse other
// code.
- int current_position = total_bytes_read_ -
- (BufferSize() + buffer_size_after_limit_);
+ int current_position = CurrentPosition();
total_bytes_limit_ = max(current_position, total_bytes_limit);
- total_bytes_warning_threshold_ = warning_threshold;
+ if (warning_threshold >= 0) {
+ total_bytes_warning_threshold_ = warning_threshold;
+ } else {
+ // warning_threshold is negative
+ total_bytes_warning_threshold_ = -1;
+ }
RecomputeBufferLimits();
}
+int CodedInputStream::BytesUntilTotalBytesLimit() const {
+ if (total_bytes_limit_ == INT_MAX) return -1;
+ return total_bytes_limit_ - CurrentPosition();
+}
+
void CodedInputStream::PrintTotalBytesLimitError() {
GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
"big (more than " << total_bytes_limit_
@@ -232,6 +271,14 @@ bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
buffer->clear();
}
+ int closest_limit = min(current_limit_, total_bytes_limit_);
+ if (closest_limit != INT_MAX) {
+ int bytes_to_limit = closest_limit - CurrentPosition();
+ if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) {
+ buffer->reserve(size);
+ }
+ }
+
int current_buffer_size;
while ((current_buffer_size = BufferSize()) < size) {
// Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
@@ -298,11 +345,16 @@ inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
uint32 b;
uint32 result;
- b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done;
- b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
- b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
- b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
- b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done;
+ b = *(ptr++); result = b ; if (!(b & 0x80)) goto done;
+ result -= 0x80;
+ b = *(ptr++); result += b << 7; if (!(b & 0x80)) goto done;
+ result -= 0x80 << 7;
+ b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done;
+ result -= 0x80 << 14;
+ b = *(ptr++); result += b << 21; if (!(b & 0x80)) goto done;
+ result -= 0x80 << 21;
+ b = *(ptr++); result += b << 28; if (!(b & 0x80)) goto done;
+ // "result -= 0x80 << 28" is irrevelant.
// If the input is larger than 32 bits, we still need to read it all
// and discard the high-order bits.
@@ -332,8 +384,8 @@ bool CodedInputStream::ReadVarint32Slow(uint32* value) {
bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
if (BufferSize() >= kMaxVarintBytes ||
- // Optimization: If the varint ends at exactly the end of the buffer,
- // we can detect that and still use the fast path.
+ // Optimization: We're also safe if the buffer is non-empty and it ends
+ // with a byte that would terminate a varint.
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
const uint8* end = ReadVarint32FromArray(buffer_, value);
if (end == NULL) return false;
@@ -368,16 +420,17 @@ uint32 CodedInputStream::ReadTagSlow() {
// For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
// again, since we have now refreshed the buffer.
- uint64 result;
+ uint64 result = 0;
if (!ReadVarint64(&result)) return 0;
return static_cast<uint32>(result);
}
uint32 CodedInputStream::ReadTagFallback() {
- if (BufferSize() >= kMaxVarintBytes ||
- // Optimization: If the varint ends at exactly the end of the buffer,
- // we can detect that and still use the fast path.
- (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
+ const int buf_size = BufferSize();
+ if (buf_size >= kMaxVarintBytes ||
+ // Optimization: We're also safe if the buffer is non-empty and it ends
+ // with a byte that would terminate a varint.
+ (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
uint32 tag;
const uint8* end = ReadVarint32FromArray(buffer_, &tag);
if (end == NULL) {
@@ -388,7 +441,9 @@ uint32 CodedInputStream::ReadTagFallback() {
} else {
// We are commonly at a limit when attempting to read tags. Try to quickly
// detect this case without making another function call.
- if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 &&
+ if ((buf_size == 0) &&
+ ((buffer_size_after_limit_ > 0) ||
+ (total_bytes_read_ == current_limit_)) &&
// Make sure that the limit we hit is not total_bytes_limit_, since
// in that case we still need to call Refresh() so that it prints an
// error.
@@ -426,8 +481,8 @@ bool CodedInputStream::ReadVarint64Slow(uint64* value) {
bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
if (BufferSize() >= kMaxVarintBytes ||
- // Optimization: If the varint ends at exactly the end of the buffer,
- // we can detect that and still use the fast path.
+ // Optimization: We're also safe if the buffer is non-empty and it ends
+ // with a byte that would terminate a varint.
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
// Fast path: We have enough bytes left in the buffer to guarantee that
// this read won't cross the end, so we can skip the checks.
@@ -439,20 +494,30 @@ bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
// processors.
uint32 part0 = 0, part1 = 0, part2 = 0;
- b = *(ptr++); part0 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
- b = *(ptr++); part0 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
- b = *(ptr++); part0 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
- b = *(ptr++); part0 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
- b = *(ptr++); part1 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
- b = *(ptr++); part1 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
- b = *(ptr++); part1 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
- b = *(ptr++); part1 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
- b = *(ptr++); part2 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
- b = *(ptr++); part2 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
+ part0 -= 0x80;
+ b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
+ part0 -= 0x80 << 7;
+ b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
+ part0 -= 0x80 << 14;
+ b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
+ part0 -= 0x80 << 21;
+ b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done;
+ part1 -= 0x80;
+ b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done;
+ part1 -= 0x80 << 7;
+ b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
+ part1 -= 0x80 << 14;
+ b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
+ part1 -= 0x80 << 21;
+ b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done;
+ part2 -= 0x80;
+ b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done;
+ // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
// We have overrun the maximum size of a varint (10 bytes). The data
// must be corrupt.
- return NULL;
+ return false;
done:
Advance(ptr - buffer_);
@@ -492,8 +557,8 @@ bool CodedInputStream::Refresh() {
"CodedInputStream::SetTotalBytesLimit() in "
"google/protobuf/io/coded_stream.h.";
- // Don't warn again for this stream.
- total_bytes_warning_threshold_ = -1;
+ // Don't warn again for this stream, and print total size at the end.
+ total_bytes_warning_threshold_ = -2;
}
const void* void_buffer;
@@ -537,7 +602,8 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
buffer_(NULL),
buffer_size_(0),
total_bytes_(0),
- had_error_(false) {
+ had_error_(false),
+ aliasing_enabled_(false) {
// Eagerly Refresh() so buffer space is immediately available.
Refresh();
// The Refresh() may have failed. If the client doesn't write any data,
@@ -547,8 +613,15 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
}
CodedOutputStream::~CodedOutputStream() {
+ Trim();
+}
+
+void CodedOutputStream::Trim() {
if (buffer_size_ > 0) {
output_->BackUp(buffer_size_);
+ total_bytes_ -= buffer_size_;
+ buffer_size_ = 0;
+ buffer_ = NULL;
}
}
@@ -591,6 +664,18 @@ uint8* CodedOutputStream::WriteRawToArray(
}
+void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
+ if (size < buffer_size_
+ ) {
+ WriteRaw(data, size);
+ } else {
+ Trim();
+
+ total_bytes_ += size;
+ had_error_ |= !output_->WriteAliasedRaw(data, size);
+ }
+}
+
void CodedOutputStream::WriteLittleEndian32(uint32 value) {
uint8 bytes[sizeof(value)];
@@ -621,61 +706,12 @@ void CodedOutputStream::WriteLittleEndian64(uint64 value) {
}
}
-inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
- uint32 value, uint8* target) {
- target[0] = static_cast<uint8>(value | 0x80);
- if (value >= (1 << 7)) {
- target[1] = static_cast<uint8>((value >> 7) | 0x80);
- if (value >= (1 << 14)) {
- target[2] = static_cast<uint8>((value >> 14) | 0x80);
- if (value >= (1 << 21)) {
- target[3] = static_cast<uint8>((value >> 21) | 0x80);
- if (value >= (1 << 28)) {
- target[4] = static_cast<uint8>(value >> 28);
- return target + 5;
- } else {
- target[3] &= 0x7F;
- return target + 4;
- }
- } else {
- target[2] &= 0x7F;
- return target + 3;
- }
- } else {
- target[1] &= 0x7F;
- return target + 2;
- }
- } else {
- target[0] &= 0x7F;
- return target + 1;
- }
-}
-
-void CodedOutputStream::WriteVarint32(uint32 value) {
- if (buffer_size_ >= kMaxVarint32Bytes) {
- // Fast path: We have enough bytes left in the buffer to guarantee that
- // this write won't cross the end, so we can skip the checks.
- uint8* target = buffer_;
- uint8* end = WriteVarint32FallbackToArrayInline(value, target);
- int size = end - target;
- Advance(size);
- } else {
- // Slow path: This write might cross the end of the buffer, so we
- // compose the bytes first then use WriteRaw().
- uint8 bytes[kMaxVarint32Bytes];
- int size = 0;
- while (value > 0x7F) {
- bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
- value >>= 7;
- }
- bytes[size++] = static_cast<uint8>(value) & 0x7F;
- WriteRaw(bytes, size);
- }
-}
-
-uint8* CodedOutputStream::WriteVarint32FallbackToArray(
- uint32 value, uint8* target) {
- return WriteVarint32FallbackToArrayInline(value, target);
+void CodedOutputStream::WriteVarint32SlowPath(uint32 value) {
+ uint8 bytes[kMaxVarint32Bytes];
+ uint8* target = &bytes[0];
+ uint8* end = WriteVarint32ToArray(value, target);
+ int size = end - target;
+ WriteRaw(bytes, size);
}
inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
@@ -834,6 +870,13 @@ int CodedOutputStream::VarintSize64(uint64 value) {
}
}
+uint8* CodedOutputStream::WriteStringWithSizeToArray(const string& str,
+ uint8* target) {
+ GOOGLE_DCHECK_LE(str.size(), kuint32max);
+ target = WriteVarint32ToArray(str.size(), target);
+ return WriteStringToArray(str, target);
+}
+
} // namespace io
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index 1b6b4e18..dea4b650 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -49,7 +49,7 @@
// // to identify the file type, then write a length-delimited string. The
// // string is composed of a varint giving the length followed by the raw
// // bytes.
-// int fd = open("myfile", O_WRONLY);
+// int fd = open("myfile", O_CREAT | O_WRONLY);
// ZeroCopyOutputStream* raw_output = new FileOutputStream(fd);
// CodedOutputStream* coded_output = new CodedOutputStream(raw_output);
//
@@ -110,6 +110,7 @@
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
#include <string>
+#include <utility>
#ifdef _MSC_VER
#if defined(_M_IX86) && \
!defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
@@ -122,15 +123,16 @@
#endif
#else
#include <sys/param.h> // __BYTE_ORDER
- #if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && \
+ #if ((defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) || \
+ (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN)) && \
!defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
#define PROTOBUF_LITTLE_ENDIAN 1
#endif
#endif
#include <google/protobuf/stubs/common.h>
-
namespace google {
+
namespace protobuf {
class DescriptorPool;
@@ -170,6 +172,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// successfully and the stream's byte limit.
~CodedInputStream();
+ // Return true if this CodedInputStream reads from a flat array instead of
+ // a ZeroCopyInputStream.
+ inline bool IsFlat() const;
// Skips a number of bytes. Returns false if an underlying read error
// occurs.
@@ -230,11 +235,22 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Read a tag. This calls ReadVarint32() and returns the result, or returns
// zero (which is not a valid tag) if ReadVarint32() fails. Also, it updates
// the last tag value, which can be checked with LastTagWas().
- // Always inline because this is only called in once place per parse loop
+ // Always inline because this is only called in one place per parse loop
// but it is called for every iteration of said loop, so it should be fast.
// GCC doesn't want to inline this by default.
uint32 ReadTag() GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+ // This usually a faster alternative to ReadTag() when cutoff is a manifest
+ // constant. It does particularly well for cutoff >= 127. The first part
+ // of the return value is the tag that was read, though it can also be 0 in
+ // the cases where ReadTag() would return 0. If the second part is true
+ // then the tag is known to be in [0, cutoff]. If not, the tag either is
+ // above cutoff or is 0. (There's intentional wiggle room when tag is 0,
+ // because that can arise in several ways, and for best performance we want
+ // to avoid an extra "is tag == 0?" check here.)
+ inline std::pair<uint32, bool> ReadTagWithCutoff(uint32 cutoff)
+ GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+
// Usually returns true if calling ReadVarint32() now would produce the given
// value. Will always return false if ReadVarint32() would not return the
// given value. If ExpectTag() returns true, it also advances past
@@ -261,8 +277,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// zero, and ConsumedEntireMessage() will return true.
bool ExpectAtEnd();
- // If the last call to ReadTag() returned the given value, returns true.
- // Otherwise, returns false;
+ // If the last call to ReadTag() or ReadTagWithCutoff() returned the
+ // given value, returns true. Otherwise, returns false;
//
// This is needed because parsers for some types of embedded messages
// (with field type TYPE_GROUP) don't actually know that they've reached the
@@ -311,7 +327,10 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Returns the number of bytes left until the nearest limit on the
// stack is hit, or -1 if no limits are in place.
- int BytesUntilLimit();
+ int BytesUntilLimit() const;
+
+ // Returns current position relative to the beginning of the input stream.
+ int CurrentPosition() const;
// Total Bytes Limit -----------------------------------------------
// To prevent malicious users from sending excessively large messages
@@ -327,8 +346,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// cause integer overflows is 512MB. The default limit is 64MB. Apps
// should set shorter limits if possible. If warning_threshold is not -1,
// a warning will be printed to stderr after warning_threshold bytes are
- // read. An error will always be printed to stderr if the limit is
- // reached.
+ // read. For backwards compatibility all negative values get squashed to -1,
+ // as other negative values might have special internal meanings.
+ // An error will always be printed to stderr if the limit is reached.
//
// This is unrelated to PushLimit()/PopLimit().
//
@@ -349,15 +369,20 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// something unusual.
void SetTotalBytesLimit(int total_bytes_limit, int warning_threshold);
+ // The Total Bytes Limit minus the Current Position, or -1 if there
+ // is no Total Bytes Limit.
+ int BytesUntilTotalBytesLimit() const;
+
// Recursion Limit -------------------------------------------------
// To prevent corrupt or malicious messages from causing stack overflows,
// we must keep track of the depth of recursion when parsing embedded
// messages and groups. CodedInputStream keeps track of this because it
// is the only object that is passed down the stack during parsing.
- // Sets the maximum recursion depth. The default is 64.
+ // Sets the maximum recursion depth. The default is 100.
void SetRecursionLimit(int limit);
+
// Increments the current recursion depth. Returns true if the depth is
// under the limit, false if it has gone over.
bool IncrementRecursionDepth();
@@ -365,6 +390,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<CodedInputStream::Limit, int> 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.
//
@@ -433,7 +475,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
//
// Note that this feature is ignored when parsing "lite" messages as they do
// not have descriptors.
- void SetExtensionRegistry(DescriptorPool* pool, MessageFactory* factory);
+ void SetExtensionRegistry(const DescriptorPool* pool,
+ MessageFactory* factory);
// Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool
// has been provided.
@@ -446,9 +489,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
@@ -457,7 +500,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
int overflow_bytes_;
// LastTagWas() stuff.
- uint32 last_tag_; // result of last ReadTag().
+ uint32 last_tag_; // result of last ReadTag() or ReadTagWithCutoff().
// This is set true by ReadTag{Fallback/Slow}() if it is called when exactly
// at EOF, or by ExpectAtEnd() when it returns true. This happens when we
@@ -482,11 +525,17 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Maximum number of bytes to read, period. This is unrelated to
// current_limit_. Set using SetTotalBytesLimit().
int total_bytes_limit_;
+
+ // If positive/0: Limit for bytes read after which a warning due to size
+ // should be logged.
+ // If -1: Printing of warning disabled. Can be set by client.
+ // 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_;
@@ -539,7 +588,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB
static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB
- static const int kDefaultRecursionLimit = 64;
+
+ static int default_recursion_limit_; // 100 by default.
};
// Class which encodes and writes binary data which is composed of varint-
@@ -597,6 +647,13 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
// ZeroCopyOutputStream immediately after the last byte written.
~CodedOutputStream();
+ // Trims any unused space in the underlying buffer so that its size matches
+ // the number of bytes written by this stream. The underlying buffer will
+ // automatically be trimmed when this stream is destroyed; this call is only
+ // necessary if the underlying buffer is accessed *before* the stream is
+ // destroyed.
+ void Trim();
+
// Skips a number of bytes, leaving the bytes unmodified in the underlying
// buffer. Returns false if an underlying write error occurs. This is
// mainly useful with GetDirectBufferPointer().
@@ -623,6 +680,9 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
// Write raw bytes, copying them from the given buffer.
void WriteRaw(const void* buffer, int size);
+ // Like WriteRaw() but will try to write aliased data if aliasing is
+ // turned on.
+ void WriteRawMaybeAliased(const void* data, int size);
// Like WriteRaw() but writing directly to the target array.
// This is _not_ inlined, as the compiler often optimizes memcpy into inline
// copy loops. Since this gets called by every field with string or bytes
@@ -634,8 +694,21 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
void WriteString(const string& str);
// Like WriteString() but writing directly to the target array.
static uint8* WriteStringToArray(const string& str, uint8* target);
+ // Write the varint-encoded size of str followed by str.
+ static uint8* WriteStringWithSizeToArray(const string& str, uint8* target);
+ // Instructs the CodedOutputStream to allow the underlying
+ // ZeroCopyOutputStream to hold pointers to the original structure instead of
+ // copying, if it supports it (i.e. output->AllowsAliasing() is true). If the
+ // underlying stream does not support aliasing, then enabling it has no
+ // affect. For now, this only affects the behavior of
+ // WriteRawMaybeAliased().
+ //
+ // NOTE: It is caller's responsibility to ensure that the chunk of memory
+ // remains live until all of the data has been consumed from the stream.
+ void EnableAliasing(bool enabled);
+
// Write a 32-bit little-endian integer.
void WriteLittleEndian32(uint32 value);
// Like WriteLittleEndian32() but writing directly to the target array.
@@ -680,6 +753,21 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
// If negative, 10 bytes. Otheriwse, same as VarintSize32().
static int VarintSize32SignExtended(int32 value);
+ // Compile-time equivalent of VarintSize32().
+ template <uint32 Value>
+ struct StaticVarintSize32 {
+ static const int value =
+ (Value < (1 << 7))
+ ? 1
+ : (Value < (1 << 14))
+ ? 2
+ : (Value < (1 << 21))
+ ? 3
+ : (Value < (1 << 28))
+ ? 4
+ : 5;
+ };
+
// Returns the total number of bytes written since this object was created.
inline int ByteCount() const;
@@ -695,6 +783,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
int buffer_size_;
int total_bytes_; // Sum of sizes of all buffers seen so far.
bool had_error_; // Whether an error occurred during output.
+ bool aliasing_enabled_; // See EnableAliasing().
// Advance the buffer by a given number of bytes.
void Advance(int amount);
@@ -703,7 +792,13 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
// Advance(buffer_size_).
bool Refresh();
- static uint8* WriteVarint32FallbackToArray(uint32 value, uint8* target);
+ // Like WriteRaw() but may avoid copying if the underlying
+ // ZeroCopyOutputStream supports it.
+ void WriteAliasedRaw(const void* buffer, int size);
+
+ // If this write might cross the end of the buffer, we compose the bytes first
+ // then use WriteRaw().
+ void WriteVarint32SlowPath(uint32 value);
// Always-inlined versions of WriteVarint* functions so that code can be
// reused, while still controlling size. For instance, WriteVarint32ToArray()
@@ -712,8 +807,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
// WriteVarint32FallbackToArray. Meanwhile, WriteVarint32() is already
// out-of-line, so it should just invoke this directly to avoid any extra
// function call overhead.
- static uint8* WriteVarint32FallbackToArrayInline(
- uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
static uint8* WriteVarint64ToArrayInline(
uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
@@ -820,6 +913,45 @@ inline uint32 CodedInputStream::ReadTag() {
}
}
+inline std::pair<uint32, bool> CodedInputStream::ReadTagWithCutoff(
+ uint32 cutoff) {
+ // In performance-sensitive code we can expect cutoff to be a compile-time
+ // constant, and things like "cutoff >= kMax1ByteVarint" to be evaluated at
+ // compile time.
+ if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
+ // Hot case: buffer_ non_empty, buffer_[0] in [1, 128).
+ // TODO(gpike): Is it worth rearranging this? E.g., if the number of fields
+ // is large enough then is it better to check for the two-byte case first?
+ if (static_cast<int8>(buffer_[0]) > 0) {
+ const uint32 kMax1ByteVarint = 0x7f;
+ uint32 tag = last_tag_ = buffer_[0];
+ Advance(1);
+ return std::make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
+ }
+ // Other hot case: cutoff >= 0x80, buffer_ has at least two bytes available,
+ // and tag is two bytes. The latter is tested by bitwise-and-not of the
+ // first byte and the second byte.
+ if (cutoff >= 0x80 &&
+ GOOGLE_PREDICT_TRUE(buffer_ + 1 < buffer_end_) &&
+ GOOGLE_PREDICT_TRUE((buffer_[0] & ~buffer_[1]) >= 0x80)) {
+ const uint32 kMax2ByteVarint = (0x7f << 7) + 0x7f;
+ uint32 tag = last_tag_ = (1u << 7) * buffer_[1] + (buffer_[0] - 0x80);
+ Advance(2);
+ // It might make sense to test for tag == 0 now, but it is so rare that
+ // that we don't bother. A varint-encoded 0 should be one byte unless
+ // the encoder lost its mind. The second part of the return value of
+ // this function is allowed to be either true or false if the tag is 0,
+ // so we don't have to check for tag == 0. We may need to check whether
+ // it exceeds cutoff.
+ bool at_or_below_cutoff = cutoff >= kMax2ByteVarint || tag <= cutoff;
+ return std::make_pair(tag, at_or_below_cutoff);
+ }
+ }
+ // Slow path
+ last_tag_ = ReadTagFallback();
+ return std::make_pair(last_tag_, static_cast<uint32>(last_tag_ - 1) < cutoff);
+}
+
inline bool CodedInputStream::LastTagWas(uint32 expected) {
return last_tag_ == expected;
}
@@ -876,7 +1008,9 @@ inline bool CodedInputStream::ExpectAtEnd() {
// If we are at a limit we know no more bytes can be read. Otherwise, it's
// hard to say without calling Refresh(), and we'd rather not do that.
- if (buffer_ == buffer_end_ && buffer_size_after_limit_ != 0) {
+ if (buffer_ == buffer_end_ &&
+ ((buffer_size_after_limit_ != 0) ||
+ (total_bytes_read_ == current_limit_))) {
last_tag_ = 0; // Pretend we called ReadTag()...
legitimate_message_end_ = true; // ... and it hit EOF.
return true;
@@ -885,6 +1019,10 @@ inline bool CodedInputStream::ExpectAtEnd() {
}
}
+inline int CodedInputStream::CurrentPosition() const {
+ return total_bytes_read_ - (BufferSize() + buffer_size_after_limit_);
+}
+
inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) {
if (buffer_size_ < size) {
return NULL;
@@ -896,13 +1034,14 @@ inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) {
}
inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value,
- uint8* target) {
- if (value < 0x80) {
- *target = value;
- return target + 1;
- } else {
- return WriteVarint32FallbackToArray(value, target);
+ uint8* target) {
+ while (value >= 0x80) {
+ *target = static_cast<uint8>(value | 0x80);
+ value >>= 7;
+ ++target;
}
+ *target = static_cast<uint8>(value);
+ return target + 1;
}
inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) {
@@ -955,22 +1094,26 @@ inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value,
return target + sizeof(value);
}
+inline void CodedOutputStream::WriteVarint32(uint32 value) {
+ if (buffer_size_ >= 5) {
+ // Fast path: We have enough bytes left in the buffer to guarantee that
+ // this write won't cross the end, so we can skip the checks.
+ uint8* target = buffer_;
+ uint8* end = WriteVarint32ToArray(value, target);
+ int size = end - target;
+ Advance(size);
+ } else {
+ WriteVarint32SlowPath(value);
+ }
+}
+
inline void CodedOutputStream::WriteTag(uint32 value) {
WriteVarint32(value);
}
inline uint8* CodedOutputStream::WriteTagToArray(
uint32 value, uint8* target) {
- if (value < (1 << 7)) {
- target[0] = value;
- return target + 1;
- } else if (value < (1 << 14)) {
- target[0] = static_cast<uint8>(value | 0x80);
- target[1] = static_cast<uint8>(value >> 7);
- return target + 2;
- } else {
- return WriteVarint32FallbackToArray(value, target);
- }
+ return WriteVarint32ToArray(value, target);
}
inline int CodedOutputStream::VarintSize32(uint32 value) {
@@ -993,6 +1136,15 @@ inline void CodedOutputStream::WriteString(const string& str) {
WriteRaw(str.data(), static_cast<int>(str.size()));
}
+inline void CodedOutputStream::WriteRawMaybeAliased(
+ const void* data, int size) {
+ if (aliasing_enabled_) {
+ WriteAliasedRaw(data, size);
+ } else {
+ WriteRaw(data, size);
+ }
+}
+
inline uint8* CodedOutputStream::WriteStringToArray(
const string& str, uint8* target) {
return WriteRawToArray(str.data(), static_cast<int>(str.size()), target);
@@ -1012,19 +1164,20 @@ 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(DescriptorPool* pool,
+inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool,
MessageFactory* factory) {
extension_pool_ = pool;
extension_factory_ = factory;
@@ -1043,9 +1196,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),
@@ -1055,8 +1208,8 @@ inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
buffer_size_after_limit_(0),
total_bytes_limit_(kDefaultTotalBytesLimit),
total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
- recursion_depth_(0),
- recursion_limit_(kDefaultRecursionLimit),
+ recursion_budget_(default_recursion_limit_),
+ recursion_limit_(default_recursion_limit_),
extension_pool_(NULL),
extension_factory_(NULL) {
// Eagerly Refresh() so buffer space is immediately available.
@@ -1064,9 +1217,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),
@@ -1076,18 +1229,16 @@ 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_limit_(kDefaultRecursionLimit),
+ recursion_budget_(default_recursion_limit_),
+ recursion_limit_(default_recursion_limit_),
extension_pool_(NULL),
extension_factory_(NULL) {
// Note that setting current_limit_ == size is important to prevent some
// code paths from trying to access input_ and segfaulting.
}
-inline CodedInputStream::~CodedInputStream() {
- if (input_ != NULL) {
- BackUpInputToCurrentPosition();
- }
+inline bool CodedInputStream::IsFlat() const {
+ return input_ == NULL;
}
} // namespace io
diff --git a/src/google/protobuf/io/coded_stream_inl.h b/src/google/protobuf/io/coded_stream_inl.h
index e9799d47..cd8d1746 100644
--- a/src/google/protobuf/io/coded_stream_inl.h
+++ b/src/google/protobuf/io/coded_stream_inl.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -36,9 +36,11 @@
#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <string>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -50,8 +52,14 @@ inline bool CodedInputStream::InternalReadStringInline(string* buffer,
if (BufferSize() >= size) {
STLStringResizeUninitialized(buffer, size);
- memcpy(string_as_array(buffer), buffer_, size);
- Advance(size);
+ std::pair<char*, bool> 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 ff268ab9..02d5bad3 100644
--- a/src/google/protobuf/io/coded_stream_unittest.cc
+++ b/src/google/protobuf/io/coded_stream_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -44,7 +44,6 @@
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/stubs/strutil.h>
// This declares an unsigned long long integer literal in a portable way.
@@ -125,6 +124,13 @@ namespace {
class CodedStreamTest : public testing::Test {
protected:
+ // Helper method used by tests for bytes warning. See implementation comment
+ // for further information.
+ static void SetupTotalBytesLimitWarningTest(
+ int total_bytes_limit, int warning_threshold,
+ vector<string>* out_errors, vector<string>* out_warnings);
+
+ // Buffer used during most of the tests. This assumes tests run sequentially.
static const int kBufferSize = 1024 * 64;
static uint8 buffer_[kBufferSize];
};
@@ -138,6 +144,7 @@ uint8 CodedStreamTest::buffer_[CodedStreamTest::kBufferSize];
// checks.
const int kBlockSizes[] = {1, 2, 3, 5, 7, 13, 32, 1024};
+
// -------------------------------------------------------------------
// Varint tests.
@@ -495,11 +502,11 @@ struct Fixed64Case {
};
inline std::ostream& operator<<(std::ostream& os, const Fixed32Case& c) {
- return os << "0x" << hex << c.value << dec;
+ return os << "0x" << std::hex << c.value << std::dec;
}
inline std::ostream& operator<<(std::ostream& os, const Fixed64Case& c) {
- return os << "0x" << hex << c.value << dec;
+ return os << "0x" << std::hex << c.value << std::dec;
}
Fixed32Case kFixed32Cases[] = {
@@ -676,14 +683,197 @@ TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) {
EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
}
+TEST_1D(CodedStreamTest, ReadStringReservesMemoryOnTotalLimit, kBlockSizes) {
+ memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+ ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+ {
+ CodedInputStream coded_input(&input);
+ coded_input.SetTotalBytesLimit(sizeof(kRawBytes), sizeof(kRawBytes));
+ EXPECT_EQ(sizeof(kRawBytes), coded_input.BytesUntilTotalBytesLimit());
+
+ string str;
+ EXPECT_TRUE(coded_input.ReadString(&str, strlen(kRawBytes)));
+ EXPECT_EQ(sizeof(kRawBytes) - strlen(kRawBytes),
+ coded_input.BytesUntilTotalBytesLimit());
+ EXPECT_EQ(kRawBytes, str);
+ // TODO(liujisi): Replace with a more meaningful test (see cl/60966023).
+ EXPECT_GE(str.capacity(), strlen(kRawBytes));
+ }
+
+ EXPECT_EQ(strlen(kRawBytes), input.ByteCount());
+}
+
+TEST_1D(CodedStreamTest, ReadStringReservesMemoryOnPushedLimit, kBlockSizes) {
+ memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+ ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+ {
+ CodedInputStream coded_input(&input);
+ coded_input.PushLimit(sizeof(buffer_));
+
+ string str;
+ EXPECT_TRUE(coded_input.ReadString(&str, strlen(kRawBytes)));
+ EXPECT_EQ(kRawBytes, str);
+ // TODO(liujisi): Replace with a more meaningful test (see cl/60966023).
+ EXPECT_GE(str.capacity(), strlen(kRawBytes));
+ }
+
+ EXPECT_EQ(strlen(kRawBytes), input.ByteCount());
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationIfLimitsNotSet) {
+ memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+ // Buffer size in the input must be smaller than sizeof(kRawBytes),
+ // otherwise check against capacity will fail as ReadStringInline()
+ // will handle the reading and will reserve the memory as needed.
+ ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+ {
+ CodedInputStream coded_input(&input);
+
+ string str;
+ EXPECT_TRUE(coded_input.ReadString(&str, strlen(kRawBytes)));
+ EXPECT_EQ(kRawBytes, str);
+ // Note: this check depends on string class implementation. It
+ // expects that string will allocate more than strlen(kRawBytes)
+ // if the content of kRawBytes is appended to string in small
+ // chunks.
+ // TODO(liujisi): Replace with a more meaningful test (see cl/60966023).
+ EXPECT_GE(str.capacity(), strlen(kRawBytes));
+ }
+
+ EXPECT_EQ(strlen(kRawBytes), input.ByteCount());
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationSizeIsNegative) {
+ memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+ // Buffer size in the input must be smaller than sizeof(kRawBytes),
+ // otherwise check against capacity will fail as ReadStringInline()
+ // will handle the reading and will reserve the memory as needed.
+ ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+ {
+ CodedInputStream coded_input(&input);
+ coded_input.PushLimit(sizeof(buffer_));
+
+ string str;
+ EXPECT_FALSE(coded_input.ReadString(&str, -1));
+ // Note: this check depends on string class implementation. It
+ // expects that string will always allocate the same amount of
+ // memory for an empty string.
+ EXPECT_EQ(string().capacity(), str.capacity());
+ }
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationSizeIsLarge) {
+ memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+ // Buffer size in the input must be smaller than sizeof(kRawBytes),
+ // otherwise check against capacity will fail as ReadStringInline()
+ // will handle the reading and will reserve the memory as needed.
+ ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+ {
+ CodedInputStream coded_input(&input);
+ coded_input.PushLimit(sizeof(buffer_));
+
+ string str;
+ EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
+ EXPECT_GT(1 << 30, str.capacity());
+ }
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationSizeIsOverTheLimit) {
+ memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+ // Buffer size in the input must be smaller than sizeof(kRawBytes),
+ // otherwise check against capacity will fail as ReadStringInline()
+ // will handle the reading and will reserve the memory as needed.
+ ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+ {
+ CodedInputStream coded_input(&input);
+ coded_input.PushLimit(16);
+
+ string str;
+ EXPECT_FALSE(coded_input.ReadString(&str, strlen(kRawBytes)));
+ // Note: this check depends on string class implementation. It
+ // expects that string will allocate less than strlen(kRawBytes)
+ // for an empty string.
+ EXPECT_GT(strlen(kRawBytes), str.capacity());
+ }
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationSizeIsOverTheTotalBytesLimit) {
+ memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+ // Buffer size in the input must be smaller than sizeof(kRawBytes),
+ // otherwise check against capacity will fail as ReadStringInline()
+ // will handle the reading and will reserve the memory as needed.
+ ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+ {
+ CodedInputStream coded_input(&input);
+ coded_input.SetTotalBytesLimit(16, 16);
+
+ string str;
+ EXPECT_FALSE(coded_input.ReadString(&str, strlen(kRawBytes)));
+ // Note: this check depends on string class implementation. It
+ // expects that string will allocate less than strlen(kRawBytes)
+ // for an empty string.
+ EXPECT_GT(strlen(kRawBytes), str.capacity());
+ }
+}
+
+TEST_F(CodedStreamTest,
+ ReadStringNoReservationSizeIsOverTheClosestLimit_GlobalLimitIsCloser) {
+ memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+ // Buffer size in the input must be smaller than sizeof(kRawBytes),
+ // otherwise check against capacity will fail as ReadStringInline()
+ // will handle the reading and will reserve the memory as needed.
+ ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+ {
+ CodedInputStream coded_input(&input);
+ coded_input.PushLimit(sizeof(buffer_));
+ coded_input.SetTotalBytesLimit(16, 16);
+
+ string str;
+ EXPECT_FALSE(coded_input.ReadString(&str, strlen(kRawBytes)));
+ // Note: this check depends on string class implementation. It
+ // expects that string will allocate less than strlen(kRawBytes)
+ // for an empty string.
+ EXPECT_GT(strlen(kRawBytes), str.capacity());
+ }
+}
+
+TEST_F(CodedStreamTest,
+ ReadStringNoReservationSizeIsOverTheClosestLimit_LocalLimitIsCloser) {
+ memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+ // Buffer size in the input must be smaller than sizeof(kRawBytes),
+ // otherwise check against capacity will fail as ReadStringInline()
+ // will handle the reading and will reserve the memory as needed.
+ ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+ {
+ CodedInputStream coded_input(&input);
+ coded_input.PushLimit(16);
+ coded_input.SetTotalBytesLimit(sizeof(buffer_), sizeof(buffer_));
+ EXPECT_EQ(sizeof(buffer_), coded_input.BytesUntilTotalBytesLimit());
+
+ string str;
+ EXPECT_FALSE(coded_input.ReadString(&str, strlen(kRawBytes)));
+ // Note: this check depends on string class implementation. It
+ // expects that string will allocate less than strlen(kRawBytes)
+ // for an empty string.
+ EXPECT_GT(strlen(kRawBytes), str.capacity());
+ }
+}
+
// -------------------------------------------------------------------
// Skip
const char kSkipTestBytes[] =
"<Before skipping><To be skipped><After skipping>";
-const char kSkipOutputTestBytes[] =
- "-----------------<To be skipped>----------------";
TEST_1D(CodedStreamTest, SkipInput, kBlockSizes) {
memcpy(buffer_, kSkipTestBytes, sizeof(kSkipTestBytes));
@@ -974,9 +1164,11 @@ TEST_F(CodedStreamTest, TotalBytesLimit) {
ArrayInputStream input(buffer_, sizeof(buffer_));
CodedInputStream coded_input(&input);
coded_input.SetTotalBytesLimit(16, -1);
+ EXPECT_EQ(16, coded_input.BytesUntilTotalBytesLimit());
string str;
EXPECT_TRUE(coded_input.ReadString(&str, 16));
+ EXPECT_EQ(0, coded_input.BytesUntilTotalBytesLimit());
vector<string> errors;
@@ -991,7 +1183,9 @@ TEST_F(CodedStreamTest, TotalBytesLimit) {
"A protocol message was rejected because it was too big", errors[0]);
coded_input.SetTotalBytesLimit(32, -1);
+ EXPECT_EQ(16, coded_input.BytesUntilTotalBytesLimit());
EXPECT_TRUE(coded_input.ReadString(&str, 16));
+ EXPECT_EQ(0, coded_input.BytesUntilTotalBytesLimit());
}
TEST_F(CodedStreamTest, TotalBytesLimitNotValidMessageEnd) {
@@ -1022,6 +1216,59 @@ TEST_F(CodedStreamTest, TotalBytesLimitNotValidMessageEnd) {
EXPECT_FALSE(coded_input.ConsumedEntireMessage());
}
+// This method is used by the tests below.
+// It constructs a CodedInputStream with the given limits and tries to read 2KiB
+// of data from it. Then it returns the logged errors and warnings in the given
+// vectors.
+void CodedStreamTest::SetupTotalBytesLimitWarningTest(
+ int total_bytes_limit, int warning_threshold,
+ vector<string>* out_errors, vector<string>* out_warnings) {
+ ArrayInputStream raw_input(buffer_, sizeof(buffer_), 128);
+
+ ScopedMemoryLog scoped_log;
+ {
+ CodedInputStream input(&raw_input);
+ input.SetTotalBytesLimit(total_bytes_limit, warning_threshold);
+ string str;
+ EXPECT_TRUE(input.ReadString(&str, 2048));
+ }
+
+ *out_errors = scoped_log.GetMessages(ERROR);
+ *out_warnings = scoped_log.GetMessages(WARNING);
+}
+
+TEST_F(CodedStreamTest, TotalBytesLimitWarning) {
+ vector<string> errors;
+ vector<string> warnings;
+ SetupTotalBytesLimitWarningTest(10240, 1024, &errors, &warnings);
+
+ EXPECT_EQ(0, errors.size());
+
+ ASSERT_EQ(2, warnings.size());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring,
+ "Reading dangerously large protocol message. If the message turns out to "
+ "be larger than 10240 bytes, parsing will be halted for security reasons.",
+ warnings[0]);
+ EXPECT_PRED_FORMAT2(testing::IsSubstring,
+ "The total number of bytes read was 2048",
+ warnings[1]);
+}
+
+TEST_F(CodedStreamTest, TotalBytesLimitWarningDisabled) {
+ vector<string> errors;
+ vector<string> warnings;
+
+ // Test with -1
+ SetupTotalBytesLimitWarningTest(10240, -1, &errors, &warnings);
+ EXPECT_EQ(0, errors.size());
+ EXPECT_EQ(0, warnings.size());
+
+ // Test again with -2, expecting the same result
+ SetupTotalBytesLimitWarningTest(10240, -2, &errors, &warnings);
+ EXPECT_EQ(0, errors.size());
+ EXPECT_EQ(0, warnings.size());
+}
+
TEST_F(CodedStreamTest, RecursionLimit) {
ArrayInputStream input(buffer_, sizeof(buffer_));
@@ -1060,6 +1307,7 @@ TEST_F(CodedStreamTest, RecursionLimit) {
EXPECT_FALSE(coded_input.IncrementRecursionDepth()); // 7
}
+
class ReallyBigInputStream : public ZeroCopyInputStream {
public:
ReallyBigInputStream() : backup_amount_(0), buffer_count_(0) {}
diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc
index 0f1ff872..c9f4ca7f 100644
--- a/src/google/protobuf/io/gzip_stream.cc
+++ b/src/google/protobuf/io/gzip_stream.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -48,7 +48,8 @@ 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_.state = Z_NULL;
zcontext_.zalloc = Z_NULL;
zcontext_.zfree = Z_NULL;
zcontext_.opaque = Z_NULL;
@@ -134,6 +135,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 +180,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<uintptr_t>(zcontext_.next_out) -
+ reinterpret_cast<uintptr_t>(output_position_);
+ }
+ return ret;
}
// =========================================================================
@@ -199,16 +205,6 @@ GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
Init(sub_stream, options);
}
-GzipOutputStream::GzipOutputStream(
- ZeroCopyOutputStream* sub_stream, Format format, int buffer_size) {
- Options options;
- options.format = format;
- if (buffer_size != -1) {
- options.buffer_size = buffer_size;
- }
- Init(sub_stream, options);
-}
-
void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
const Options& options) {
sub_stream_ = sub_stream;
@@ -309,10 +305,11 @@ int64 GzipOutputStream::ByteCount() const {
}
bool GzipOutputStream::Flush() {
- do {
- zerror_ = Deflate(Z_FULL_FLUSH);
- } while (zerror_ == Z_OK);
- return zerror_ == Z_OK;
+ zerror_ = Deflate(Z_FULL_FLUSH);
+ // Return true if the flush succeeded or if it was a no-op.
+ return (zerror_ == Z_OK) ||
+ (zerror_ == Z_BUF_ERROR && zcontext_.avail_in == 0 &&
+ zcontext_.avail_out != 0);
}
bool GzipOutputStream::Close() {
diff --git a/src/google/protobuf/io/gzip_stream.h b/src/google/protobuf/io/gzip_stream.h
index 65dbc5b5..82445000 100644
--- a/src/google/protobuf/io/gzip_stream.h
+++ b/src/google/protobuf/io/gzip_stream.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -45,6 +45,7 @@
#include <zlib.h>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/zero_copy_stream.h>
namespace google {
@@ -98,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);
@@ -144,12 +146,6 @@ class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
ZeroCopyOutputStream* sub_stream,
const Options& options);
- // DEPRECATED: Use one of the above constructors instead.
- GzipOutputStream(
- ZeroCopyOutputStream* sub_stream,
- Format format,
- int buffer_size = -1) GOOGLE_ATTRIBUTE_DEPRECATED;
-
virtual ~GzipOutputStream();
// Return last error message or NULL if no error.
@@ -165,6 +161,13 @@ class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
// necessary.
// Compression may be less efficient stopping and starting around flushes.
// Returns true if no error.
+ //
+ // Please ensure that block size is > 6. Here is an excerpt from the zlib
+ // doc that explains why:
+ //
+ // In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out
+ // is greater than six to avoid repeated flush markers due to
+ // avail_out == 0 on return.
bool Flush();
// Writes out all data and closes the gzip stream.
diff --git a/src/google/protobuf/io/gzip_stream_unittest.sh b/src/google/protobuf/io/gzip_stream_unittest.sh
index 6e8a0943..16251a94 100755
--- a/src/google/protobuf/io/gzip_stream_unittest.sh
+++ b/src/google/protobuf/io/gzip_stream_unittest.sh
@@ -2,7 +2,7 @@
#
# Protocol Buffers - Google's data interchange format
# Copyright 2009 Google Inc. All rights reserved.
-# http://code.google.com/p/protobuf/
+# 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
diff --git a/src/google/protobuf/io/package_info.h b/src/google/protobuf/io/package_info.h
index 7a7a4e77..dc1fc91e 100644
--- a/src/google/protobuf/io/package_info.h
+++ b/src/google/protobuf/io/package_info.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc
index 9ab90dee..e621ba1d 100644
--- a/src/google/protobuf/io/printer.cc
+++ b/src/google/protobuf/io/printer.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,7 +35,6 @@
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
@@ -51,8 +50,8 @@ Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
}
Printer::~Printer() {
- // Only BackUp() if we're sure we've successfully called Next() at least once.
- if (buffer_size_ > 0) {
+ // Only BackUp() if we have called Next() at least once and never failed.
+ if (buffer_size_ > 0 && !failed_) {
output_->BackUp(buffer_size_);
}
}
@@ -143,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<string, string> vars;
+ vars[variable1] = value1;
+ vars[variable2] = value2;
+ vars[variable3] = value3;
+ vars[variable4] = value4;
+ Print(vars, text);
+}
+
void Printer::Indent() {
indent_ += " ";
}
@@ -169,7 +181,7 @@ void Printer::WriteRaw(const char* data, int size) {
if (failed_) return;
if (size == 0) return;
- if (at_start_of_line_) {
+ if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
// Insert an indent.
at_start_of_line_ = false;
WriteRaw(indent_.data(), indent_.size());
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
index 5be48543..92ce3409 100644
--- a/src/google/protobuf/io/printer.h
+++ b/src/google/protobuf/io/printer.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc
index 580a53da..1331a8d9 100644
--- a/src/google/protobuf/io/printer_unittest.cc
+++ b/src/google/protobuf/io/printer_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -220,7 +220,7 @@ TEST(Printer, Indenting) {
}
// Death tests do not work on Windows as of yet.
-#ifdef GTEST_HAS_DEATH_TEST
+#ifdef PROTOBUF_HAS_DEATH_TEST
TEST(Printer, Death) {
char buffer[8192];
@@ -231,9 +231,33 @@ TEST(Printer, Death) {
EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
}
-#endif // GTEST_HAS_DEATH_TEST
+#endif // PROTOBUF_HAS_DEATH_TEST
-TEST(Printer, WriteFailure) {
+TEST(Printer, WriteFailurePartial) {
+ char buffer[17];
+
+ ArrayOutputStream output(buffer, sizeof(buffer));
+ Printer printer(&output, '$');
+
+ // Print 16 bytes to almost fill the buffer (should not fail).
+ printer.Print("0123456789abcdef");
+ EXPECT_FALSE(printer.failed());
+
+ // Try to print 2 chars. Only one fits.
+ printer.Print("<>");
+ EXPECT_TRUE(printer.failed());
+
+ // Anything else should fail too.
+ printer.Print(" ");
+ EXPECT_TRUE(printer.failed());
+ printer.Print("blah");
+ EXPECT_TRUE(printer.failed());
+
+ // Buffer should contain the first 17 bytes written.
+ EXPECT_EQ("0123456789abcdef<", string(buffer, sizeof(buffer)));
+}
+
+TEST(Printer, WriteFailureExact) {
char buffer[16];
ArrayOutputStream output(buffer, sizeof(buffer));
diff --git a/src/google/protobuf/io/strtod.cc b/src/google/protobuf/io/strtod.cc
new file mode 100644
index 00000000..56973439
--- /dev/null
+++ b/src/google/protobuf/io/strtod.cc
@@ -0,0 +1,113 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/io/strtod.h>
+
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// ----------------------------------------------------------------------
+// NoLocaleStrtod()
+// This code will make you cry.
+// ----------------------------------------------------------------------
+
+namespace {
+
+// Returns a string identical to *input except that the character pointed to
+// by radix_pos (which should be '.') is replaced with the locale-specific
+// radix character.
+string LocalizeRadix(const char* input, const char* radix_pos) {
+ // Determine the locale-specific radix character by calling sprintf() to
+ // print the number 1.5, then stripping off the digits. As far as I can
+ // tell, this is the only portable, thread-safe way to get the C library
+ // to divuldge the locale's radix character. No, localeconv() is NOT
+ // thread-safe.
+ char temp[16];
+ int size = sprintf(temp, "%.1f", 1.5);
+ GOOGLE_CHECK_EQ(temp[0], '1');
+ GOOGLE_CHECK_EQ(temp[size-1], '5');
+ GOOGLE_CHECK_LE(size, 6);
+
+ // Now replace the '.' in the input with it.
+ string result;
+ result.reserve(strlen(input) + size - 3);
+ result.append(input, radix_pos);
+ result.append(temp + 1, size - 2);
+ result.append(radix_pos + 1);
+ return result;
+}
+
+} // namespace
+
+double NoLocaleStrtod(const char* text, char** original_endptr) {
+ // We cannot simply set the locale to "C" temporarily with setlocale()
+ // as this is not thread-safe. Instead, we try to parse in the current
+ // locale first. If parsing stops at a '.' character, then this is a
+ // pretty good hint that we're actually in some other locale in which
+ // '.' is not the radix character.
+
+ char* temp_endptr;
+ double result = strtod(text, &temp_endptr);
+ if (original_endptr != NULL) *original_endptr = temp_endptr;
+ if (*temp_endptr != '.') return result;
+
+ // Parsing halted on a '.'. Perhaps we're in a different locale? Let's
+ // try to replace the '.' with a locale-specific radix character and
+ // try again.
+ string localized = LocalizeRadix(text, temp_endptr);
+ const char* localized_cstr = localized.c_str();
+ char* localized_endptr;
+ result = strtod(localized_cstr, &localized_endptr);
+ if ((localized_endptr - localized_cstr) >
+ (temp_endptr - text)) {
+ // This attempt got further, so replacing the decimal must have helped.
+ // Update original_endptr to point at the right location.
+ if (original_endptr != NULL) {
+ // size_diff is non-zero if the localized radix has multiple bytes.
+ int size_diff = localized.size() - strlen(text);
+ // const_cast is necessary to match the strtod() interface.
+ *original_endptr = const_cast<char*>(
+ text + (localized_endptr - localized_cstr - size_diff));
+ }
+ }
+
+ return result;
+}
+
+} // namespace io
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/io/strtod.h b/src/google/protobuf/io/strtod.h
new file mode 100644
index 00000000..c2efc8d3
--- /dev/null
+++ b/src/google/protobuf/io/strtod.h
@@ -0,0 +1,50 @@
+// 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 locale-independent version of strtod(), used to parse floating
+// point default values in .proto files, where the decimal separator
+// is always a dot.
+
+#ifndef GOOGLE_PROTOBUF_IO_STRTOD_H__
+#define GOOGLE_PROTOBUF_IO_STRTOD_H__
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// A locale-independent version of the standard strtod(), which always
+// uses a dot as the decimal separator.
+double NoLocaleStrtod(const char* str, char** endptr);
+
+} // namespace io
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_IO_STRTOD_H__
diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc
index 513831d5..ef2de300 100644
--- a/src/google/protobuf/io/tokenizer.cc
+++ b/src/google/protobuf/io/tokenizer.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -89,8 +89,12 @@
// exactly pretty.
#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/io/strtod.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -118,6 +122,8 @@ namespace {
CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' ||
c == '\r' || c == '\v' || c == '\f');
+CHARACTER_CLASS(WhitespaceNoNewline, c == ' ' || c == '\t' ||
+ c == '\r' || c == '\v' || c == '\f');
CHARACTER_CLASS(Unprintable, c < ' ' && c > '\0');
@@ -187,9 +193,12 @@ Tokenizer::Tokenizer(ZeroCopyInputStream* input,
read_error_(false),
line_(0),
column_(0),
- token_start_(-1),
+ record_target_(NULL),
+ record_start_(-1),
allow_f_after_float_(false),
- comment_style_(CPP_COMMENT_STYLE) {
+ comment_style_(CPP_COMMENT_STYLE),
+ require_space_after_number_(true),
+ allow_multiline_strings_(false) {
current_.line = 0;
current_.column = 0;
@@ -238,9 +247,9 @@ void Tokenizer::Refresh() {
}
// If we're in a token, append the rest of the buffer to it.
- if (token_start_ >= 0 && token_start_ < buffer_size_) {
- current_.text.append(buffer_ + token_start_, buffer_size_ - token_start_);
- token_start_ = 0;
+ if (record_target_ != NULL && record_start_ < buffer_size_) {
+ record_target_->append(buffer_ + record_start_, buffer_size_ - record_start_);
+ record_start_ = 0;
}
const void* data = NULL;
@@ -261,23 +270,33 @@ void Tokenizer::Refresh() {
current_char_ = buffer_[0];
}
+inline void Tokenizer::RecordTo(string* target) {
+ record_target_ = target;
+ record_start_ = buffer_pos_;
+}
+
+inline void Tokenizer::StopRecording() {
+ // Note: The if() is necessary because some STL implementations crash when
+ // you call string::append(NULL, 0), presumably because they are trying to
+ // be helpful by detecting the NULL pointer, even though there's nothing
+ // wrong with reading zero bytes from NULL.
+ if (buffer_pos_ != record_start_) {
+ record_target_->append(buffer_ + record_start_, buffer_pos_ - record_start_);
+ }
+ record_target_ = NULL;
+ record_start_ = -1;
+}
+
inline void Tokenizer::StartToken() {
- token_start_ = buffer_pos_;
current_.type = TYPE_START; // Just for the sake of initializing it.
current_.text.clear();
current_.line = line_;
current_.column = column_;
+ RecordTo(&current_.text);
}
inline void Tokenizer::EndToken() {
- // Note: The if() is necessary because some STL implementations crash when
- // you call string::append(NULL, 0), presumably because they are trying to
- // be helpful by detecting the NULL pointer, even though there's nothing
- // wrong with reading zero bytes from NULL.
- if (buffer_pos_ != token_start_) {
- current_.text.append(buffer_ + token_start_, buffer_pos_ - token_start_);
- }
- token_start_ = -1;
+ StopRecording();
current_.end_column = column_;
}
@@ -334,9 +353,16 @@ void Tokenizer::ConsumeString(char delimiter) {
while (true) {
switch (current_char_) {
case '\0':
- case '\n': {
- AddError("String literals cannot cross line boundaries.");
+ AddError("Unexpected end of string.");
return;
+
+ case '\n': {
+ if (!allow_multiline_strings_) {
+ AddError("String literals cannot cross line boundaries.");
+ return;
+ }
+ NextChar();
+ break;
}
case '\\': {
@@ -353,6 +379,27 @@ void Tokenizer::ConsumeString(char delimiter) {
AddError("Expected hex digits for escape sequence.");
}
// Possibly followed by another hex digit, but again we don't care.
+ } else if (TryConsume('u')) {
+ if (!TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>()) {
+ AddError("Expected four hex digits for \\u escape sequence.");
+ }
+ } else if (TryConsume('U')) {
+ // We expect 8 hex digits; but only the range up to 0x10ffff is
+ // legal.
+ if (!TryConsume('0') ||
+ !TryConsume('0') ||
+ !(TryConsume('0') || TryConsume('1')) ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>() ||
+ !TryConsumeOne<HexDigit>()) {
+ AddError("Expected eight hex digits up to 10ffff for \\U escape "
+ "sequence");
+ }
} else {
AddError("Invalid escape sequence in string literal.");
}
@@ -412,7 +459,7 @@ Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero,
}
}
- if (LookingAt<Letter>()) {
+ if (LookingAt<Letter>() && require_space_after_number_) {
AddError("Need space between number and identifier.");
} else if (current_char_ == '.') {
if (is_float) {
@@ -426,26 +473,51 @@ Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero,
return is_float ? TYPE_FLOAT : TYPE_INTEGER;
}
-void Tokenizer::ConsumeLineComment() {
+void Tokenizer::ConsumeLineComment(string* content) {
+ if (content != NULL) RecordTo(content);
+
while (current_char_ != '\0' && current_char_ != '\n') {
NextChar();
}
TryConsume('\n');
+
+ if (content != NULL) StopRecording();
}
-void Tokenizer::ConsumeBlockComment() {
+void Tokenizer::ConsumeBlockComment(string* content) {
int start_line = line_;
int start_column = column_ - 2;
+ if (content != NULL) RecordTo(content);
+
while (true) {
while (current_char_ != '\0' &&
current_char_ != '*' &&
- current_char_ != '/') {
+ current_char_ != '/' &&
+ current_char_ != '\n') {
NextChar();
}
- if (TryConsume('*') && TryConsume('/')) {
+ if (TryConsume('\n')) {
+ if (content != NULL) StopRecording();
+
+ // Consume leading whitespace and asterisk;
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+ if (TryConsume('*')) {
+ if (TryConsume('/')) {
+ // End of comment.
+ break;
+ }
+ }
+
+ if (content != NULL) RecordTo(content);
+ } else if (TryConsume('*') && TryConsume('/')) {
// End of comment.
+ if (content != NULL) {
+ StopRecording();
+ // Strip trailing "*/".
+ content->erase(content->size() - 2);
+ }
break;
} else if (TryConsume('/') && current_char_ == '*') {
// Note: We didn't consume the '*' because if there is a '/' after it
@@ -456,42 +528,59 @@ void Tokenizer::ConsumeBlockComment() {
AddError("End-of-file inside block comment.");
error_collector_->AddError(
start_line, start_column, " Comment started here.");
+ if (content != NULL) StopRecording();
break;
}
}
}
+Tokenizer::NextCommentStatus Tokenizer::TryConsumeCommentStart() {
+ if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) {
+ if (TryConsume('/')) {
+ return LINE_COMMENT;
+ } else if (TryConsume('*')) {
+ return BLOCK_COMMENT;
+ } else {
+ // Oops, it was just a slash. Return it.
+ current_.type = TYPE_SYMBOL;
+ current_.text = "/";
+ current_.line = line_;
+ current_.column = column_ - 1;
+ current_.end_column = column_;
+ return SLASH_NOT_COMMENT;
+ }
+ } else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) {
+ return LINE_COMMENT;
+ } else {
+ return NO_COMMENT;
+ }
+}
+
// -------------------------------------------------------------------
bool Tokenizer::Next() {
previous_ = current_;
- // Did we skip any characters after the last token?
- bool skipped_stuff = false;
-
while (!read_error_) {
- if (TryConsumeOne<Whitespace>()) {
- ConsumeZeroOrMore<Whitespace>();
-
- } else if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) {
- // Starting a comment?
- if (TryConsume('/')) {
- ConsumeLineComment();
- } else if (TryConsume('*')) {
- ConsumeBlockComment();
- } else {
- // Oops, it was just a slash. Return it.
- current_.type = TYPE_SYMBOL;
- current_.text = "/";
- current_.line = line_;
- current_.column = column_ - 1;
+ ConsumeZeroOrMore<Whitespace>();
+
+ switch (TryConsumeCommentStart()) {
+ case LINE_COMMENT:
+ ConsumeLineComment(NULL);
+ continue;
+ case BLOCK_COMMENT:
+ ConsumeBlockComment(NULL);
+ continue;
+ case SLASH_NOT_COMMENT:
return true;
- }
+ case NO_COMMENT:
+ break;
+ }
- } else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) {
- ConsumeLineComment();
+ // Check for EOF before continuing.
+ if (read_error_) break;
- } else if (LookingAt<Unprintable>() || current_char_ == '\0') {
+ if (LookingAt<Unprintable>() || current_char_ == '\0') {
AddError("Invalid control characters encountered in text.");
NextChar();
// Skip more unprintable characters, too. But, remember that '\0' is
@@ -519,7 +608,9 @@ bool Tokenizer::Next() {
if (TryConsumeOne<Digit>()) {
// It's a floating-point number.
- if (previous_.type == TYPE_IDENTIFIER && !skipped_stuff) {
+ if (previous_.type == TYPE_IDENTIFIER &&
+ current_.line == previous_.line &&
+ current_.column == previous_.end_column) {
// We don't accept syntax like "blah.123".
error_collector_->AddError(line_, column_ - 2,
"Need space between identifier and decimal point.");
@@ -537,6 +628,12 @@ bool Tokenizer::Next() {
ConsumeString('\'');
current_.type = TYPE_STRING;
} else {
+ // Check if the high order bit is set.
+ if (current_char_ & 0x80) {
+ error_collector_->AddError(line_, column_,
+ StringPrintf("Interpreting non ascii codepoint %d.",
+ static_cast<unsigned char>(current_char_)));
+ }
NextChar();
current_.type = TYPE_SYMBOL;
}
@@ -544,8 +641,6 @@ bool Tokenizer::Next() {
EndToken();
return true;
}
-
- skipped_stuff = true;
}
// EOF
@@ -557,6 +652,195 @@ bool Tokenizer::Next() {
return false;
}
+namespace {
+
+// Helper class for collecting comments and putting them in the right places.
+//
+// This basically just buffers the most recent comment until it can be decided
+// exactly where that comment should be placed. When Flush() is called, the
+// current comment goes into either prev_trailing_comments or detached_comments.
+// When the CommentCollector is destroyed, the last buffered comment goes into
+// next_leading_comments.
+class CommentCollector {
+ public:
+ CommentCollector(string* prev_trailing_comments,
+ vector<string>* detached_comments,
+ string* next_leading_comments)
+ : prev_trailing_comments_(prev_trailing_comments),
+ detached_comments_(detached_comments),
+ next_leading_comments_(next_leading_comments),
+ has_comment_(false),
+ is_line_comment_(false),
+ can_attach_to_prev_(true) {
+ if (prev_trailing_comments != NULL) prev_trailing_comments->clear();
+ if (detached_comments != NULL) detached_comments->clear();
+ if (next_leading_comments != NULL) next_leading_comments->clear();
+ }
+
+ ~CommentCollector() {
+ // Whatever is in the buffer is a leading comment.
+ if (next_leading_comments_ != NULL && has_comment_) {
+ comment_buffer_.swap(*next_leading_comments_);
+ }
+ }
+
+ // About to read a line comment. Get the comment buffer pointer in order to
+ // read into it.
+ string* GetBufferForLineComment() {
+ // We want to combine with previous line comments, but not block comments.
+ if (has_comment_ && !is_line_comment_) {
+ Flush();
+ }
+ has_comment_ = true;
+ is_line_comment_ = true;
+ return &comment_buffer_;
+ }
+
+ // About to read a block comment. Get the comment buffer pointer in order to
+ // read into it.
+ string* GetBufferForBlockComment() {
+ if (has_comment_) {
+ Flush();
+ }
+ has_comment_ = true;
+ is_line_comment_ = false;
+ return &comment_buffer_;
+ }
+
+ void ClearBuffer() {
+ comment_buffer_.clear();
+ has_comment_ = false;
+ }
+
+ // Called once we know that the comment buffer is complete and is *not*
+ // connected to the next token.
+ void Flush() {
+ if (has_comment_) {
+ if (can_attach_to_prev_) {
+ if (prev_trailing_comments_ != NULL) {
+ prev_trailing_comments_->append(comment_buffer_);
+ }
+ can_attach_to_prev_ = false;
+ } else {
+ if (detached_comments_ != NULL) {
+ detached_comments_->push_back(comment_buffer_);
+ }
+ }
+ ClearBuffer();
+ }
+ }
+
+ void DetachFromPrev() {
+ can_attach_to_prev_ = false;
+ }
+
+ private:
+ string* prev_trailing_comments_;
+ vector<string>* detached_comments_;
+ string* next_leading_comments_;
+
+ string comment_buffer_;
+
+ // True if any comments were read into comment_buffer_. This can be true even
+ // if comment_buffer_ is empty, namely if the comment was "/**/".
+ bool has_comment_;
+
+ // Is the comment in the comment buffer a line comment?
+ bool is_line_comment_;
+
+ // Is it still possible that we could be reading a comment attached to the
+ // previous token?
+ bool can_attach_to_prev_;
+};
+
+} // namespace
+
+bool Tokenizer::NextWithComments(string* prev_trailing_comments,
+ vector<string>* detached_comments,
+ string* next_leading_comments) {
+ CommentCollector collector(prev_trailing_comments, detached_comments,
+ next_leading_comments);
+
+ if (current_.type == TYPE_START) {
+ collector.DetachFromPrev();
+ } else {
+ // A comment appearing on the same line must be attached to the previous
+ // declaration.
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+ switch (TryConsumeCommentStart()) {
+ case LINE_COMMENT:
+ ConsumeLineComment(collector.GetBufferForLineComment());
+
+ // Don't allow comments on subsequent lines to be attached to a trailing
+ // comment.
+ collector.Flush();
+ break;
+ case BLOCK_COMMENT:
+ ConsumeBlockComment(collector.GetBufferForBlockComment());
+
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+ if (!TryConsume('\n')) {
+ // Oops, the next token is on the same line. If we recorded a comment
+ // we really have no idea which token it should be attached to.
+ collector.ClearBuffer();
+ return Next();
+ }
+
+ // Don't allow comments on subsequent lines to be attached to a trailing
+ // comment.
+ collector.Flush();
+ break;
+ case SLASH_NOT_COMMENT:
+ return true;
+ case NO_COMMENT:
+ if (!TryConsume('\n')) {
+ // The next token is on the same line. There are no comments.
+ return Next();
+ }
+ break;
+ }
+ }
+
+ // OK, we are now on the line *after* the previous token.
+ while (true) {
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+
+ switch (TryConsumeCommentStart()) {
+ case LINE_COMMENT:
+ ConsumeLineComment(collector.GetBufferForLineComment());
+ break;
+ case BLOCK_COMMENT:
+ ConsumeBlockComment(collector.GetBufferForBlockComment());
+
+ // Consume the rest of the line so that we don't interpret it as a
+ // blank line the next time around the loop.
+ ConsumeZeroOrMore<WhitespaceNoNewline>();
+ TryConsume('\n');
+ break;
+ case SLASH_NOT_COMMENT:
+ return true;
+ case NO_COMMENT:
+ if (TryConsume('\n')) {
+ // Completely blank line.
+ collector.Flush();
+ collector.DetachFromPrev();
+ } else {
+ bool result = Next();
+ if (!result ||
+ current_.text == "}" ||
+ current_.text == "]" ||
+ current_.text == ")") {
+ // It looks like we're at the end of a scope. In this case it
+ // makes no sense to attach a comment to the following token.
+ collector.Flush();
+ }
+ return result;
+ }
+ break;
+ }
+ }
+}
+
// -------------------------------------------------------------------
// Token-parsing helpers. Remember that these don't need to report
// errors since any errors should already have been reported while
@@ -626,17 +910,138 @@ double Tokenizer::ParseFloat(const string& text) {
return result;
}
+// Helper to append a Unicode code point to a string as UTF8, without bringing
+// in any external dependencies.
+static void AppendUTF8(uint32 code_point, string* output) {
+ uint32 tmp = 0;
+ int len = 0;
+ if (code_point <= 0x7f) {
+ tmp = code_point;
+ len = 1;
+ } else if (code_point <= 0x07ff) {
+ tmp = 0x0000c080 |
+ ((code_point & 0x07c0) << 2) |
+ (code_point & 0x003f);
+ len = 2;
+ } else if (code_point <= 0xffff) {
+ tmp = 0x00e08080 |
+ ((code_point & 0xf000) << 4) |
+ ((code_point & 0x0fc0) << 2) |
+ (code_point & 0x003f);
+ len = 3;
+ } else if (code_point <= 0x1fffff) {
+ tmp = 0xf0808080 |
+ ((code_point & 0x1c0000) << 6) |
+ ((code_point & 0x03f000) << 4) |
+ ((code_point & 0x000fc0) << 2) |
+ (code_point & 0x003f);
+ len = 4;
+ } else {
+ // UTF-16 is only defined for code points up to 0x10FFFF, and UTF-8 is
+ // normally only defined up to there as well.
+ StringAppendF(output, "\\U%08x", code_point);
+ return;
+ }
+ tmp = ghtonl(tmp);
+ output->append(reinterpret_cast<const char*>(&tmp) + sizeof(tmp) - len, len);
+}
+
+// Try to read <len> hex digits from ptr, and stuff the numeric result into
+// *result. Returns true if that many digits were successfully consumed.
+static bool ReadHexDigits(const char* ptr, int len, uint32* result) {
+ *result = 0;
+ if (len == 0) return false;
+ for (const char* end = ptr + len; ptr < end; ++ptr) {
+ if (*ptr == '\0') return false;
+ *result = (*result << 4) + DigitValue(*ptr);
+ }
+ return true;
+}
+
+// Handling UTF-16 surrogate pairs. UTF-16 encodes code points in the range
+// 0x10000...0x10ffff as a pair of numbers, a head surrogate followed by a trail
+// surrogate. These numbers are in a reserved range of Unicode code points, so
+// if we encounter such a pair we know how to parse it and convert it into a
+// single code point.
+static const uint32 kMinHeadSurrogate = 0xd800;
+static const uint32 kMaxHeadSurrogate = 0xdc00;
+static const uint32 kMinTrailSurrogate = 0xdc00;
+static const uint32 kMaxTrailSurrogate = 0xe000;
+
+static inline bool IsHeadSurrogate(uint32 code_point) {
+ return (code_point >= kMinHeadSurrogate) && (code_point < kMaxHeadSurrogate);
+}
+
+static inline bool IsTrailSurrogate(uint32 code_point) {
+ return (code_point >= kMinTrailSurrogate) &&
+ (code_point < kMaxTrailSurrogate);
+}
+
+// Combine a head and trail surrogate into a single Unicode code point.
+static uint32 AssembleUTF16(uint32 head_surrogate, uint32 trail_surrogate) {
+ GOOGLE_DCHECK(IsHeadSurrogate(head_surrogate));
+ GOOGLE_DCHECK(IsTrailSurrogate(trail_surrogate));
+ return 0x10000 + (((head_surrogate - kMinHeadSurrogate) << 10) |
+ (trail_surrogate - kMinTrailSurrogate));
+}
+
+// Convert the escape sequence parameter to a number of expected hex digits.
+static inline int UnicodeLength(char key) {
+ if (key == 'u') return 4;
+ if (key == 'U') return 8;
+ return 0;
+}
+
+// Given a pointer to the 'u' or 'U' starting a Unicode escape sequence, attempt
+// to parse that sequence. On success, returns a pointer to the first char
+// beyond that sequence, and fills in *code_point. On failure, returns ptr
+// itself.
+static const char* FetchUnicodePoint(const char* ptr, uint32* code_point) {
+ const char* p = ptr;
+ // Fetch the code point.
+ const int len = UnicodeLength(*p++);
+ if (!ReadHexDigits(p, len, code_point))
+ return ptr;
+ p += len;
+
+ // Check if the code point we read is a "head surrogate." If so, then we
+ // expect it to be immediately followed by another code point which is a valid
+ // "trail surrogate," and together they form a UTF-16 pair which decodes into
+ // a single Unicode point. Trail surrogates may only use \u, not \U.
+ if (IsHeadSurrogate(*code_point) && *p == '\\' && *(p + 1) == 'u') {
+ uint32 trail_surrogate;
+ if (ReadHexDigits(p + 2, 4, &trail_surrogate) &&
+ IsTrailSurrogate(trail_surrogate)) {
+ *code_point = AssembleUTF16(*code_point, trail_surrogate);
+ p += 6;
+ }
+ // If this failed, then we just emit the head surrogate as a code point.
+ // It's bogus, but so is the string.
+ }
+
+ return p;
+}
+
+// The text string must begin and end with single or double quote
+// characters.
void Tokenizer::ParseStringAppend(const string& text, string* output) {
- // Reminder: text[0] is always the quote character. (If text is
- // empty, it's invalid, so we'll just return.)
- if (text.empty()) {
+ // Reminder: text[0] is always a quote character. (If text is
+ // empty, it's invalid, so we'll just return).
+ const size_t text_size = text.size();
+ if (text_size == 0) {
GOOGLE_LOG(DFATAL)
<< " Tokenizer::ParseStringAppend() passed text that could not"
" have been tokenized as a string: " << CEscape(text);
return;
}
- output->reserve(output->size() + text.size());
+ // Reserve room for new string. The branch is necessary because if
+ // there is already space available the reserve() call might
+ // downsize the output.
+ const size_t new_len = text_size + output->size();
+ if (new_len > output->capacity()) {
+ output->reserve(new_len);
+ }
// Loop through the string copying characters to "output" and
// interpreting escape sequences. Note that any invalid escape
@@ -674,19 +1079,47 @@ void Tokenizer::ParseStringAppend(const string& text, string* output) {
}
output->push_back(static_cast<char>(code));
+ } else if (*ptr == 'u' || *ptr == 'U') {
+ uint32 unicode;
+ const char* end = FetchUnicodePoint(ptr, &unicode);
+ if (end == ptr) {
+ // Failure: Just dump out what we saw, don't try to parse it.
+ output->push_back(*ptr);
+ } else {
+ AppendUTF8(unicode, output);
+ ptr = end - 1; // Because we're about to ++ptr.
+ }
} else {
// Some other escape code.
output->push_back(TranslateEscape(*ptr));
}
- } else if (*ptr == text[0]) {
- // Ignore quote matching the starting quote.
+ } else if (*ptr == text[0] && ptr[1] == '\0') {
+ // Ignore final quote matching the starting quote.
} else {
output->push_back(*ptr);
}
}
+}
- return;
+template<typename CharacterClass>
+static bool AllInClass(const string& s) {
+ for (int i = 0; i < s.size(); ++i) {
+ if (!CharacterClass::InClass(s[i]))
+ return false;
+ }
+ return true;
+}
+
+bool Tokenizer::IsIdentifier(const string& text) {
+ // Mirrors IDENTIFIER definition in Tokenizer::Next() above.
+ if (text.size() == 0)
+ return false;
+ if (!Letter::InClass(text.at(0)))
+ return false;
+ if (!AllInClass<Alphanumeric>(text.substr(1)))
+ return false;
+ return true;
}
} // namespace io
diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h
index 8f759abb..98576f56 100644
--- a/src/google/protobuf/io/tokenizer.h
+++ b/src/google/protobuf/io/tokenizer.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -38,6 +38,7 @@
#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__
#include <string>
+#include <vector>
#include <google/protobuf/stubs/common.h>
namespace google {
@@ -66,7 +67,8 @@ class LIBPROTOBUF_EXPORT ErrorCollector {
// Indicates that there was a warning in the input at the given line and
// column numbers. The numbers are zero-based, so you may want to add
// 1 to each before printing them.
- virtual void AddWarning(int line, int column, const string& message) { }
+ virtual void AddWarning(int /* line */, int /* column */,
+ const string& /* message */) { }
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
@@ -137,6 +139,53 @@ class LIBPROTOBUF_EXPORT Tokenizer {
// reached.
bool Next();
+ // Like Next(), but also collects comments which appear between the previous
+ // and next tokens.
+ //
+ // Comments which appear to be attached to the previous token are stored
+ // in *prev_tailing_comments. Comments which appear to be attached to the
+ // next token are stored in *next_leading_comments. Comments appearing in
+ // between which do not appear to be attached to either will be added to
+ // detached_comments. Any of these parameters can be NULL to simply discard
+ // the comments.
+ //
+ // A series of line comments appearing on consecutive lines, with no other
+ // tokens appearing on those lines, will be treated as a single comment.
+ //
+ // Only the comment content is returned; comment markers (e.g. //) are
+ // stripped out. For block comments, leading whitespace and an asterisk will
+ // be stripped from the beginning of each line other than the first. Newlines
+ // are included in the output.
+ //
+ // Examples:
+ //
+ // optional int32 foo = 1; // Comment attached to foo.
+ // // Comment attached to bar.
+ // optional int32 bar = 2;
+ //
+ // optional string baz = 3;
+ // // Comment attached to baz.
+ // // Another line attached to baz.
+ //
+ // // Comment attached to qux.
+ // //
+ // // Another line attached to qux.
+ // optional double qux = 4;
+ //
+ // // Detached comment. This is not attached to qux or corge
+ // // because there are blank lines separating it from both.
+ //
+ // optional string corge = 5;
+ // /* Block comment attached
+ // * to corge. Leading asterisks
+ // * will be removed. */
+ // /* Block comment attached to
+ // * grault. */
+ // optional int32 grault = 6;
+ bool NextWithComments(string* prev_trailing_comments,
+ vector<string>* detached_comments,
+ string* next_leading_comments);
+
// Parse helpers ---------------------------------------------------
// Parses a TYPE_FLOAT token. This never fails, so long as the text actually
@@ -180,6 +229,21 @@ class LIBPROTOBUF_EXPORT Tokenizer {
// Sets the comment style.
void set_comment_style(CommentStyle style) { comment_style_ = style; }
+ // Whether to require whitespace between a number and a field name.
+ // Default is true. Do not use this; for Google-internal cleanup only.
+ void set_require_space_after_number(bool require) {
+ require_space_after_number_ = require;
+ }
+
+ // Whether to allow string literals to span multiple lines. Default is false.
+ // Do not use this; for Google-internal cleanup only.
+ void set_allow_multiline_strings(bool allow) {
+ allow_multiline_strings_ = allow;
+ }
+
+ // External helper: validate an identifier.
+ static bool IsIdentifier(const string& text);
+
// -----------------------------------------------------------------
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer);
@@ -200,15 +264,18 @@ class LIBPROTOBUF_EXPORT Tokenizer {
int line_;
int column_;
- // Position in buffer_ where StartToken() was called. If the token
- // started in the previous buffer, this is zero, and current_.text already
- // contains the part of the token from the previous buffer. If not
- // currently parsing a token, this is -1.
- int token_start_;
+ // String to which text should be appended as we advance through it.
+ // Call RecordTo(&str) to start recording and StopRecording() to stop.
+ // E.g. StartToken() calls RecordTo(&current_.text). record_start_ is the
+ // position within the current buffer where recording started.
+ string* record_target_;
+ int record_start_;
// Options.
bool allow_f_after_float_;
CommentStyle comment_style_;
+ bool require_space_after_number_;
+ bool allow_multiline_strings_;
// Since we count columns we need to interpret tabs somehow. We'll take
// the standard 8-character definition for lack of any way to do better.
@@ -223,6 +290,9 @@ class LIBPROTOBUF_EXPORT Tokenizer {
// Read a new buffer from the input.
void Refresh();
+ inline void RecordTo(string* target);
+ inline void StopRecording();
+
// Called when the current character is the first character of a new
// token (not including whitespace or comments).
inline void StartToken();
@@ -255,13 +325,32 @@ class LIBPROTOBUF_EXPORT Tokenizer {
TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
// Consume the rest of a line.
- void ConsumeLineComment();
+ void ConsumeLineComment(string* content);
// Consume until "*/".
- void ConsumeBlockComment();
+ void ConsumeBlockComment(string* content);
+
+ enum NextCommentStatus {
+ // Started a line comment.
+ LINE_COMMENT,
+
+ // Started a block comment.
+ BLOCK_COMMENT,
+
+ // Consumed a slash, then realized it wasn't a comment. current_ has
+ // been filled in with a slash token. The caller should return it.
+ SLASH_NOT_COMMENT,
+
+ // We do not appear to be starting a comment here.
+ NO_COMMENT
+ };
+
+ // If we're at the start of a new comment, consume it and return what kind
+ // of comment it is.
+ NextCommentStatus TryConsumeCommentStart();
// -----------------------------------------------------------------
// These helper methods make the parsing code more readable. The
- // "character classes" refered to are defined at the top of the .cc file.
+ // "character classes" referred to are defined at the top of the .cc file.
// Basically it is a C++ class with one method:
// static bool InClass(char c);
// The method returns true if c is a member of this "class", like "Letter"
diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc
index 106d080f..de096fb9 100644
--- a/src/google/protobuf/io/tokenizer_unittest.cc
+++ b/src/google/protobuf/io/tokenizer_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,9 +32,10 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
-#include <vector>
-#include <math.h>
#include <limits.h>
+#include <math.h>
+
+#include <vector>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -410,12 +411,6 @@ MultiTokenCase kMultiTokenCases[] = {
{ Tokenizer::TYPE_END , "" , 1, 3, 3 },
}},
- // Bytes with the high-order bit set should not be seen as control characters.
- { "\300", {
- { Tokenizer::TYPE_SYMBOL, "\300", 0, 0, 1 },
- { Tokenizer::TYPE_END , "" , 0, 1, 1 },
- }},
-
// Test all whitespace chars
{ "foo\n\t\r\v\fbar", {
{ Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0, 3 },
@@ -514,6 +509,217 @@ TEST_1D(TokenizerTest, ShCommentStyle, kBlockSizes) {
// -------------------------------------------------------------------
+// In each case, the input is expected to have two tokens named "prev" and
+// "next" with comments in between.
+struct DocCommentCase {
+ string input;
+
+ const char* prev_trailing_comments;
+ const char* detached_comments[10];
+ const char* next_leading_comments;
+};
+
+inline ostream& operator<<(ostream& out,
+ const DocCommentCase& test_case) {
+ return out << CEscape(test_case.input);
+}
+
+DocCommentCase kDocCommentCases[] = {
+ {
+ "prev next",
+
+ "",
+ {},
+ ""
+ },
+
+ {
+ "prev /* ignored */ next",
+
+ "",
+ {},
+ ""
+ },
+
+ {
+ "prev // trailing comment\n"
+ "next",
+
+ " trailing comment\n",
+ {},
+ ""
+ },
+
+ {
+ "prev\n"
+ "// leading comment\n"
+ "// line 2\n"
+ "next",
+
+ "",
+ {},
+ " leading comment\n"
+ " line 2\n"
+ },
+
+ {
+ "prev\n"
+ "// trailing comment\n"
+ "// line 2\n"
+ "\n"
+ "next",
+
+ " trailing comment\n"
+ " line 2\n",
+ {},
+ ""
+ },
+
+ {
+ "prev // trailing comment\n"
+ "// leading comment\n"
+ "// line 2\n"
+ "next",
+
+ " trailing comment\n",
+ {},
+ " leading comment\n"
+ " line 2\n"
+ },
+
+ {
+ "prev /* trailing block comment */\n"
+ "/* leading block comment\n"
+ " * line 2\n"
+ " * line 3 */"
+ "next",
+
+ " trailing block comment ",
+ {},
+ " leading block comment\n"
+ " line 2\n"
+ " line 3 "
+ },
+
+ {
+ "prev\n"
+ "/* trailing block comment\n"
+ " * line 2\n"
+ " * line 3\n"
+ " */\n"
+ "/* leading block comment\n"
+ " * line 2\n"
+ " * line 3 */"
+ "next",
+
+ " trailing block comment\n"
+ " line 2\n"
+ " line 3\n",
+ {},
+ " leading block comment\n"
+ " line 2\n"
+ " line 3 "
+ },
+
+ {
+ "prev\n"
+ "// trailing comment\n"
+ "\n"
+ "// detached comment\n"
+ "// line 2\n"
+ "\n"
+ "// second detached comment\n"
+ "/* third detached comment\n"
+ " * line 2 */\n"
+ "// leading comment\n"
+ "next",
+
+ " trailing comment\n",
+ {
+ " detached comment\n"
+ " line 2\n",
+ " second detached comment\n",
+ " third detached comment\n"
+ " line 2 "
+ },
+ " leading comment\n"
+ },
+
+ {
+ "prev /**/\n"
+ "\n"
+ "// detached comment\n"
+ "\n"
+ "// leading comment\n"
+ "next",
+
+ "",
+ {
+ " detached comment\n"
+ },
+ " leading comment\n"
+ },
+
+ {
+ "prev /**/\n"
+ "// leading comment\n"
+ "next",
+
+ "",
+ {},
+ " leading comment\n"
+ },
+ };
+
+TEST_2D(TokenizerTest, DocComments, kDocCommentCases, kBlockSizes) {
+ // Set up the tokenizer.
+ TestInputStream input(kDocCommentCases_case.input.data(),
+ kDocCommentCases_case.input.size(),
+ kBlockSizes_case);
+ TestErrorCollector error_collector;
+ Tokenizer tokenizer(&input, &error_collector);
+
+ // Set up a second tokenizer where we'll pass all NULLs to NextWithComments().
+ TestInputStream input2(kDocCommentCases_case.input.data(),
+ kDocCommentCases_case.input.size(),
+ kBlockSizes_case);
+ Tokenizer tokenizer2(&input2, &error_collector);
+
+ tokenizer.Next();
+ tokenizer2.Next();
+
+ EXPECT_EQ("prev", tokenizer.current().text);
+ EXPECT_EQ("prev", tokenizer2.current().text);
+
+ string prev_trailing_comments;
+ vector<string> detached_comments;
+ string next_leading_comments;
+ tokenizer.NextWithComments(&prev_trailing_comments, &detached_comments,
+ &next_leading_comments);
+ tokenizer2.NextWithComments(NULL, NULL, NULL);
+ EXPECT_EQ("next", tokenizer.current().text);
+ EXPECT_EQ("next", tokenizer2.current().text);
+
+ EXPECT_EQ(kDocCommentCases_case.prev_trailing_comments,
+ prev_trailing_comments);
+
+ for (int i = 0; i < detached_comments.size(); i++) {
+ ASSERT_LT(i, GOOGLE_ARRAYSIZE(kDocCommentCases));
+ ASSERT_TRUE(kDocCommentCases_case.detached_comments[i] != NULL);
+ EXPECT_EQ(kDocCommentCases_case.detached_comments[i],
+ detached_comments[i]);
+ }
+
+ // Verify that we matched all the detached comments.
+ EXPECT_EQ(NULL,
+ kDocCommentCases_case.detached_comments[detached_comments.size()]);
+
+ EXPECT_EQ(kDocCommentCases_case.next_leading_comments,
+ next_leading_comments);
+}
+
+// -------------------------------------------------------------------
+
// Test parse helpers. It's not really worth setting up a full data-driven
// test here.
TEST_F(TokenizerTest, ParseInteger) {
@@ -529,7 +735,7 @@ TEST_F(TokenizerTest, ParseInteger) {
EXPECT_EQ(0, ParseInteger("0x"));
uint64 i;
-#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
+#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet
// Test invalid integers that will never be tokenized as integers.
EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("zxy", kuint64max, &i),
"passed text that could not have been tokenized as an integer");
@@ -541,7 +747,7 @@ TEST_F(TokenizerTest, ParseInteger) {
"passed text that could not have been tokenized as an integer");
EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("-1", kuint64max, &i),
"passed text that could not have been tokenized as an integer");
-#endif // GTEST_HAS_DEATH_TEST
+#endif // PROTOBUF_HAS_DEATH_TEST
// Test overflows.
EXPECT_TRUE (Tokenizer::ParseInteger("0", 0, &i));
@@ -584,7 +790,7 @@ TEST_F(TokenizerTest, ParseFloat) {
EXPECT_EQ( 0.0, Tokenizer::ParseFloat("1e-9999999999999999999999999999"));
EXPECT_EQ(HUGE_VAL, Tokenizer::ParseFloat("1e+9999999999999999999999999999"));
-#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
+#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet
// Test invalid integers that will never be tokenized as integers.
EXPECT_DEBUG_DEATH(Tokenizer::ParseFloat("zxy"),
"passed text that could not have been tokenized as a float");
@@ -592,7 +798,7 @@ TEST_F(TokenizerTest, ParseFloat) {
"passed text that could not have been tokenized as a float");
EXPECT_DEBUG_DEATH(Tokenizer::ParseFloat("-1.0"),
"passed text that could not have been tokenized as a float");
-#endif // GTEST_HAS_DEATH_TEST
+#endif // PROTOBUF_HAS_DEATH_TEST
}
TEST_F(TokenizerTest, ParseString) {
@@ -614,11 +820,27 @@ TEST_F(TokenizerTest, ParseString) {
Tokenizer::ParseString("'\\", &output);
EXPECT_EQ("\\", output);
+ // Experiment with Unicode escapes. Here are one-, two- and three-byte Unicode
+ // characters.
+ Tokenizer::ParseString("'\\u0024\\u00a2\\u20ac\\U00024b62XX'", &output);
+ EXPECT_EQ("$¢€𤭢XX", output);
+ // Same thing encoded using UTF16.
+ Tokenizer::ParseString("'\\u0024\\u00a2\\u20ac\\ud852\\udf62XX'", &output);
+ EXPECT_EQ("$¢€𤭢XX", output);
+ // Here's some broken UTF16; there's a head surrogate with no tail surrogate.
+ // We just output this as if it were UTF8; it's not a defined code point, but
+ // it has a defined encoding.
+ Tokenizer::ParseString("'\\ud852XX'", &output);
+ EXPECT_EQ("\xed\xa1\x92XX", output);
+ // Malformed escape: Demons may fly out of the nose.
+ Tokenizer::ParseString("\\u0", &output);
+ EXPECT_EQ("u0", output);
+
// Test invalid strings that will never be tokenized as strings.
-#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
+#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet
EXPECT_DEBUG_DEATH(Tokenizer::ParseString("", &output),
"passed text that could not have been tokenized as a string");
-#endif // GTEST_HAS_DEATH_TEST
+#endif // PROTOBUF_HAS_DEATH_TEST
}
TEST_F(TokenizerTest, ParseStringAppend) {
@@ -655,9 +877,15 @@ ErrorCase kErrorCases[] = {
{ "'\\x' foo", true,
"0:3: Expected hex digits for escape sequence.\n" },
{ "'foo", false,
- "0:4: String literals cannot cross line boundaries.\n" },
+ "0:4: Unexpected end of string.\n" },
{ "'bar\nfoo", true,
"0:4: String literals cannot cross line boundaries.\n" },
+ { "'\\u01' foo", true,
+ "0:5: Expected four hex digits for \\u escape sequence.\n" },
+ { "'\\u01' foo", true,
+ "0:5: Expected four hex digits for \\u escape sequence.\n" },
+ { "'\\uXYZ' foo", true,
+ "0:3: Expected four hex digits for \\u escape sequence.\n" },
// Integer errors.
{ "123foo", true,
@@ -717,6 +945,10 @@ ErrorCase kErrorCases[] = {
"0:0: Invalid control characters encountered in text.\n" },
{ string("\0\0foo", 5), true,
"0:0: Invalid control characters encountered in text.\n" },
+
+ // Check error from high order bits set
+ { "\300foo", true,
+ "0:0: Interpreting non ascii codepoint 192.\n" },
};
TEST_2D(TokenizerTest, Errors, kErrorCases, kBlockSizes) {
@@ -734,7 +966,7 @@ TEST_2D(TokenizerTest, Errors, kErrorCases, kBlockSizes) {
}
// Check that the errors match what was expected.
- EXPECT_EQ(error_collector.text_, kErrorCases_case.errors);
+ EXPECT_EQ(kErrorCases_case.errors, error_collector.text_);
// If the error was recoverable, make sure we saw "foo" after it.
if (kErrorCases_case.recoverable) {
@@ -760,6 +992,7 @@ TEST_1D(TokenizerTest, BackUpOnDestruction, kBlockSizes) {
EXPECT_EQ(strlen("foo"), input.ByteCount());
}
+
} // namespace
} // namespace io
} // namespace protobuf
diff --git a/src/google/protobuf/io/zero_copy_stream.cc b/src/google/protobuf/io/zero_copy_stream.cc
index dad6ff14..f77c768f 100644
--- a/src/google/protobuf/io/zero_copy_stream.cc
+++ b/src/google/protobuf/io/zero_copy_stream.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,6 +34,7 @@
#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
@@ -43,6 +44,14 @@ ZeroCopyInputStream::~ZeroCopyInputStream() {}
ZeroCopyOutputStream::~ZeroCopyOutputStream() {}
+bool ZeroCopyOutputStream::WriteAliasedRaw(const void* /* data */,
+ int /* size */) {
+ GOOGLE_LOG(FATAL) << "This ZeroCopyOutputStream doesn't support aliasing. "
+ "Reaching here usually means a ZeroCopyOutputStream "
+ "implementation bug.";
+ return false;
+}
+
} // namespace io
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/io/zero_copy_stream.h b/src/google/protobuf/io/zero_copy_stream.h
index db5326f7..52650fc6 100644
--- a/src/google/protobuf/io/zero_copy_stream.h
+++ b/src/google/protobuf/io/zero_copy_stream.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -226,6 +226,16 @@ class LIBPROTOBUF_EXPORT ZeroCopyOutputStream {
// Returns the total number of bytes written since this object was created.
virtual int64 ByteCount() const = 0;
+ // Write a given chunk of data to the output. Some output streams may
+ // implement this in a way that avoids copying. Check AllowsAliasing() before
+ // calling WriteAliasedRaw(). It will GOOGLE_CHECK fail if WriteAliasedRaw() is
+ // called on a stream that does not allow aliasing.
+ //
+ // NOTE: It is caller's responsibility to ensure that the chunk of memory
+ // remains live until all of the data has been consumed from the stream.
+ virtual bool WriteAliasedRaw(const void* data, int size);
+ virtual bool AllowsAliasing() const { return false; }
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyOutputStream);
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc
index 1384c746..f7901b27 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,7 +46,8 @@
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
+
namespace google {
namespace protobuf {
@@ -412,7 +413,9 @@ int64 ConcatenatingInputStream::ByteCount() const {
LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
int64 limit)
- : input_(input), limit_(limit) {}
+ : input_(input), limit_(limit) {
+ prior_bytes_read_ = input_->ByteCount();
+}
LimitingInputStream::~LimitingInputStream() {
// If we overshot the limit, back up.
@@ -456,9 +459,9 @@ bool LimitingInputStream::Skip(int count) {
int64 LimitingInputStream::ByteCount() const {
if (limit_ < 0) {
- return input_->ByteCount() + limit_;
+ return input_->ByteCount() + limit_ - prior_bytes_read_;
} else {
- return input_->ByteCount();
+ return input_->ByteCount() - prior_bytes_read_;
}
}
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.h b/src/google/protobuf/io/zero_copy_stream_impl.h
index 9fedb005..0746fa6a 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -344,6 +344,7 @@ class LIBPROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
private:
ZeroCopyInputStream* input_;
int64 limit_; // Decreases as we go, becomes negative if we overshoot.
+ int64 prior_bytes_read_; // Bytes read on underlying stream at construction
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
};
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 e8012510..97b73b88 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,9 +32,14 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
-#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+#include <algorithm>
+#include <limits>
+
+#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -159,15 +164,23 @@ bool StringOutputStream::Next(void** data, int* size) {
// without a memory allocation this way.
STLStringResizeUninitialized(target_, target_->capacity());
} else {
- // Size has reached capacity, so double the size. Also make sure
- // that the new size is at least kMinimumSize.
+ // Size has reached capacity, try to double the size.
+ if (old_size > std::numeric_limits<int>::max() / 2) {
+ // Can not double the size otherwise it is going to cause integer
+ // overflow in the expression below: old_size * 2 ";
+ GOOGLE_LOG(ERROR) << "Cannot allocate buffer larger than kint32max for "
+ << "StringOutputStream.";
+ return false;
+ }
+ // Double the size, also make sure that the new size is at least
+ // kMinimumSize.
STLStringResizeUninitialized(
target_,
max(old_size * 2,
kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
}
- *data = string_as_array(target_) + old_size;
+ *data = mutable_string_data(target_) + old_size;
*size = target_->size() - old_size;
return true;
}
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 153f543e..4360b18f 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -48,6 +48,7 @@
#include <iosfwd>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
@@ -126,8 +127,10 @@ class LIBPROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream {
class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
public:
// Create a StringOutputStream which appends bytes to the given string.
- // The string remains property of the caller, but it MUST NOT be accessed
- // in any way until the stream is destroyed.
+ // The string remains property of the caller, but it is mutated in arbitrary
+ // ways and MUST NOT be accessed in any way until you're done with the
+ // stream. Either be sure there's no further usage, or (safest) destroy the
+ // stream before using the contents.
//
// Hint: If you call target->reserve(n) before creating the stream,
// the first call to Next() will return at least n bytes of buffer
@@ -333,6 +336,44 @@ 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().
+inline char* mutable_string_data(string* s) {
+#ifdef LANG_CXX11
+ // This should be simpler & faster than string_as_array() because the latter
+ // is guaranteed to return NULL when *s is empty, so it has to check for that.
+ return &(*s)[0];
+#else
+ return string_as_array(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<char*, bool> as_string_data(string* s) {
+ char *p = mutable_string_data(s);
+#ifdef LANG_CXX11
+ return std::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 5196d905..dd3d1285 100644
--- a/src/google/protobuf/io/zero_copy_stream_unittest.cc
+++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -370,6 +370,100 @@ TEST_F(IoTest, GzipIo) {
delete [] buffer;
}
+TEST_F(IoTest, GzipIoWithFlush) {
+ const int kBufferSize = 2*1024;
+ uint8* buffer = new uint8[kBufferSize];
+ // We start with i = 4 as we want a block size > 6. With block size <= 6
+ // Flush() fills up the entire 2K buffer with flush markers and the test
+ // fails. See documentation for Flush() for more detail.
+ for (int i = 4; i < kBlockSizeCount; i++) {
+ for (int j = 0; j < kBlockSizeCount; j++) {
+ for (int z = 0; z < kBlockSizeCount; z++) {
+ int gzip_buffer_size = kBlockSizes[z];
+ int size;
+ {
+ ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
+ GzipOutputStream::Options options;
+ options.format = GzipOutputStream::GZIP;
+ if (gzip_buffer_size != -1) {
+ options.buffer_size = gzip_buffer_size;
+ }
+ GzipOutputStream gzout(&output, options);
+ WriteStuff(&gzout);
+ EXPECT_TRUE(gzout.Flush());
+ gzout.Close();
+ size = output.ByteCount();
+ }
+ {
+ ArrayInputStream input(buffer, size, kBlockSizes[j]);
+ GzipInputStream gzin(
+ &input, GzipInputStream::GZIP, gzip_buffer_size);
+ ReadStuff(&gzin);
+ }
+ }
+ }
+ }
+ delete [] buffer;
+}
+
+TEST_F(IoTest, GzipIoContiguousFlushes) {
+ const int kBufferSize = 2*1024;
+ uint8* buffer = new uint8[kBufferSize];
+
+ int block_size = kBlockSizes[4];
+ int gzip_buffer_size = block_size;
+ int size;
+
+ ArrayOutputStream output(buffer, kBufferSize, block_size);
+ GzipOutputStream::Options options;
+ options.format = GzipOutputStream::GZIP;
+ if (gzip_buffer_size != -1) {
+ options.buffer_size = gzip_buffer_size;
+ }
+ GzipOutputStream gzout(&output, options);
+ WriteStuff(&gzout);
+ EXPECT_TRUE(gzout.Flush());
+ EXPECT_TRUE(gzout.Flush());
+ gzout.Close();
+ size = output.ByteCount();
+
+ ArrayInputStream input(buffer, size, block_size);
+ GzipInputStream gzin(
+ &input, GzipInputStream::GZIP, gzip_buffer_size);
+ ReadStuff(&gzin);
+
+ delete [] buffer;
+}
+
+TEST_F(IoTest, GzipIoReadAfterFlush) {
+ const int kBufferSize = 2*1024;
+ uint8* buffer = new uint8[kBufferSize];
+
+ int block_size = kBlockSizes[4];
+ int gzip_buffer_size = block_size;
+ int size;
+ ArrayOutputStream output(buffer, kBufferSize, block_size);
+ GzipOutputStream::Options options;
+ options.format = GzipOutputStream::GZIP;
+ if (gzip_buffer_size != -1) {
+ options.buffer_size = gzip_buffer_size;
+ }
+
+ GzipOutputStream gzout(&output, options);
+ WriteStuff(&gzout);
+ EXPECT_TRUE(gzout.Flush());
+ size = output.ByteCount();
+
+ ArrayInputStream input(buffer, size, block_size);
+ GzipInputStream gzin(
+ &input, GzipInputStream::GZIP, gzip_buffer_size);
+ ReadStuff(&gzin);
+
+ gzout.Close();
+
+ delete [] buffer;
+}
+
TEST_F(IoTest, ZlibIo) {
const int kBufferSize = 2*1024;
uint8* buffer = new uint8[kBufferSize];
@@ -466,9 +560,10 @@ TEST_F(IoTest, CompressionOptions) {
// Some ad-hoc testing of compression options.
string golden;
- File::ReadFileToStringOrDie(
- TestSourceDir() + "/google/protobuf/testdata/golden_message",
- &golden);
+ GOOGLE_CHECK_OK(File::GetContents(
+ TestSourceDir() +
+ "/google/protobuf/testdata/golden_message",
+ &golden, true));
GzipOutputStream::Options options;
string gzip_compressed = Compress(golden, options);
@@ -561,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
@@ -829,6 +961,26 @@ TEST_F(IoTest, LimitingInputStream) {
ReadStuff(&input);
}
+// Checks that ByteCount works correctly for LimitingInputStreams where the
+// underlying stream has already been read.
+TEST_F(IoTest, LimitingInputStreamByteCount) {
+ const int kHalfBufferSize = 128;
+ const int kBufferSize = kHalfBufferSize * 2;
+ uint8 buffer[kBufferSize];
+
+ // Set up input. Only allow half to be read at once.
+ ArrayInputStream array_input(buffer, kBufferSize, kHalfBufferSize);
+ const void* data;
+ int size;
+ EXPECT_TRUE(array_input.Next(&data, &size));
+ EXPECT_EQ(kHalfBufferSize, array_input.ByteCount());
+ // kHalfBufferSize - 1 to test limiting logic as well.
+ LimitingInputStream input(&array_input, kHalfBufferSize - 1);
+ EXPECT_EQ(0, input.ByteCount());
+ EXPECT_TRUE(input.Next(&data, &size));
+ EXPECT_EQ(kHalfBufferSize - 1 , input.ByteCount());
+}
+
// Check that a zero-size array doesn't confuse the code.
TEST(ZeroSizeArray, Input) {
ArrayInputStream input(NULL, 0);
diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc
index ffeec3c4..4ea21007 100644
--- a/src/google/protobuf/lite_unittest.cc
+++ b/src/google/protobuf/lite_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -33,13 +33,59 @@
#include <string>
#include <iostream>
-#include <google/protobuf/test_util_lite.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/test_util_lite.h>
+#include <google/protobuf/unittest_lite.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/wire_format_lite_inl.h>
using namespace std;
+namespace {
+// Helper methods to test parsing merge behavior.
+void ExpectMessageMerged(const google::protobuf::unittest::TestAllTypesLite& message) {
+ GOOGLE_CHECK(message.optional_int32() == 3);
+ GOOGLE_CHECK(message.optional_int64() == 2);
+ GOOGLE_CHECK(message.optional_string() == "hello");
+}
+
+void AssignParsingMergeMessages(
+ google::protobuf::unittest::TestAllTypesLite* msg1,
+ google::protobuf::unittest::TestAllTypesLite* msg2,
+ google::protobuf::unittest::TestAllTypesLite* msg3) {
+ msg1->set_optional_int32(1);
+ msg2->set_optional_int64(2);
+ msg3->set_optional_int32(3);
+ msg3->set_optional_string("hello");
+}
+
+void SetAllTypesInEmptyMessageUnknownFields(
+ google::protobuf::unittest::TestEmptyMessageLite* empty_message) {
+ protobuf_unittest::TestAllTypesLite message;
+ google::protobuf::TestUtilLite::ExpectClear(message);
+ google::protobuf::TestUtilLite::SetAllFields(&message);
+ string data = message.SerializeAsString();
+ empty_message->ParseFromString(data);
+}
+
+void SetSomeTypesInEmptyMessageUnknownFields(
+ google::protobuf::unittest::TestEmptyMessageLite* empty_message) {
+ protobuf_unittest::TestAllTypesLite message;
+ google::protobuf::TestUtilLite::ExpectClear(message);
+ message.set_optional_int32(101);
+ message.set_optional_int64(102);
+ message.set_optional_uint32(103);
+ message.set_optional_uint64(104);
+ string data = message.SerializeAsString();
+ empty_message->ParseFromString(data);
+}
+
+} // namespace
+
int main(int argc, char* argv[]) {
- string data, packed_data;
+ string data, data2, packed_data;
{
protobuf_unittest::TestAllTypesLite message, message2, message3;
@@ -63,7 +109,6 @@ int main(int argc, char* argv[]) {
google::protobuf::TestUtilLite::SetAllExtensions(&message);
message2.CopyFrom(message);
string extensions_data = message.SerializeAsString();
- GOOGLE_CHECK(extensions_data == data);
message3.ParseFromString(extensions_data);
google::protobuf::TestUtilLite::ExpectAllExtensionsSet(message);
google::protobuf::TestUtilLite::ExpectAllExtensionsSet(message2);
@@ -107,6 +152,199 @@ int main(int argc, char* argv[]) {
google::protobuf::TestUtilLite::ExpectPackedExtensionsClear(message);
}
- cout << "PASS" << endl;
+ {
+ // Test that if an optional or required message/group field appears multiple
+ // times in the input, they need to be merged.
+ google::protobuf::unittest::TestParsingMergeLite::RepeatedFieldsGenerator generator;
+ google::protobuf::unittest::TestAllTypesLite* msg1;
+ google::protobuf::unittest::TestAllTypesLite* msg2;
+ google::protobuf::unittest::TestAllTypesLite* msg3;
+
+#define ASSIGN_REPEATED_FIELD(FIELD) \
+ msg1 = generator.add_##FIELD(); \
+ msg2 = generator.add_##FIELD(); \
+ msg3 = generator.add_##FIELD(); \
+ AssignParsingMergeMessages(msg1, msg2, msg3)
+
+ ASSIGN_REPEATED_FIELD(field1);
+ ASSIGN_REPEATED_FIELD(field2);
+ ASSIGN_REPEATED_FIELD(field3);
+ ASSIGN_REPEATED_FIELD(ext1);
+ ASSIGN_REPEATED_FIELD(ext2);
+
+#undef ASSIGN_REPEATED_FIELD
+#define ASSIGN_REPEATED_GROUP(FIELD) \
+ msg1 = generator.add_##FIELD()->mutable_field1(); \
+ msg2 = generator.add_##FIELD()->mutable_field1(); \
+ msg3 = generator.add_##FIELD()->mutable_field1(); \
+ AssignParsingMergeMessages(msg1, msg2, msg3)
+
+ ASSIGN_REPEATED_GROUP(group1);
+ ASSIGN_REPEATED_GROUP(group2);
+
+#undef ASSIGN_REPEATED_GROUP
+
+ string buffer;
+ generator.SerializeToString(&buffer);
+ google::protobuf::unittest::TestParsingMergeLite parsing_merge;
+ parsing_merge.ParseFromString(buffer);
+
+ // Required and optional fields should be merged.
+ ExpectMessageMerged(parsing_merge.required_all_types());
+ ExpectMessageMerged(parsing_merge.optional_all_types());
+ ExpectMessageMerged(
+ parsing_merge.optionalgroup().optional_group_all_types());
+ ExpectMessageMerged(parsing_merge.GetExtension(
+ google::protobuf::unittest::TestParsingMergeLite::optional_ext));
+
+ // Repeated fields should not be merged.
+ GOOGLE_CHECK(parsing_merge.repeated_all_types_size() == 3);
+ GOOGLE_CHECK(parsing_merge.repeatedgroup_size() == 3);
+ GOOGLE_CHECK(parsing_merge.ExtensionSize(
+ google::protobuf::unittest::TestParsingMergeLite::repeated_ext) == 3);
+ }
+
+ // Test unknown fields support for lite messages.
+ {
+ protobuf_unittest::TestAllTypesLite message, message2;
+ protobuf_unittest::TestEmptyMessageLite empty_message;
+ google::protobuf::TestUtilLite::ExpectClear(message);
+ google::protobuf::TestUtilLite::SetAllFields(&message);
+ data = message.SerializeAsString();
+ empty_message.ParseFromString(data);
+ data.clear();
+ data = empty_message.SerializeAsString();
+ message2.ParseFromString(data);
+ data = message2.SerializeAsString();
+ google::protobuf::TestUtilLite::ExpectAllFieldsSet(message2);
+ message.Clear();
+ google::protobuf::TestUtilLite::ExpectClear(message);
+ }
+
+ {
+ protobuf_unittest::TestAllExtensionsLite message, message2;
+ protobuf_unittest::TestEmptyMessageLite empty_message;
+ google::protobuf::TestUtilLite::ExpectExtensionsClear(message);
+ google::protobuf::TestUtilLite::SetAllExtensions(&message);
+ data = message.SerializeAsString();
+ empty_message.ParseFromString(data);
+ data.clear();
+ data = empty_message.SerializeAsString();
+ message2.ParseFromString(data);
+ data = message2.SerializeAsString();
+ google::protobuf::TestUtilLite::ExpectAllExtensionsSet(message2);
+ message.Clear();
+ google::protobuf::TestUtilLite::ExpectExtensionsClear(message);
+ }
+
+ {
+ protobuf_unittest::TestPackedTypesLite message, message2;
+ protobuf_unittest::TestEmptyMessageLite empty_message;
+ google::protobuf::TestUtilLite::ExpectPackedClear(message);
+ google::protobuf::TestUtilLite::SetPackedFields(&message);
+ data = message.SerializeAsString();
+ empty_message.ParseFromString(data);
+ data.clear();
+ data = empty_message.SerializeAsString();
+ message2.ParseFromString(data);
+ data = message2.SerializeAsString();
+ google::protobuf::TestUtilLite::ExpectPackedFieldsSet(message2);
+ message.Clear();
+ google::protobuf::TestUtilLite::ExpectPackedClear(message);
+ }
+
+ {
+ protobuf_unittest::TestPackedExtensionsLite message, message2;
+ protobuf_unittest::TestEmptyMessageLite empty_message;
+ google::protobuf::TestUtilLite::ExpectPackedExtensionsClear(message);
+ google::protobuf::TestUtilLite::SetPackedExtensions(&message);
+ data = message.SerializeAsString();
+ empty_message.ParseFromString(data);
+ data.clear();
+ data = empty_message.SerializeAsString();
+ message2.ParseFromString(data);
+ data = message2.SerializeAsString();
+ google::protobuf::TestUtilLite::ExpectPackedExtensionsSet(message2);
+ message.Clear();
+ google::protobuf::TestUtilLite::ExpectPackedExtensionsClear(message);
+ }
+
+ {
+ // Test Unknown fields swap
+ protobuf_unittest::TestEmptyMessageLite empty_message, empty_message2;
+ SetAllTypesInEmptyMessageUnknownFields(&empty_message);
+ SetSomeTypesInEmptyMessageUnknownFields(&empty_message2);
+ data = empty_message.SerializeAsString();
+ data2 = empty_message2.SerializeAsString();
+ empty_message.Swap(&empty_message2);
+ GOOGLE_CHECK_EQ(data, empty_message2.SerializeAsString());
+ GOOGLE_CHECK_EQ(data2, empty_message.SerializeAsString());
+ }
+
+ {
+ // Test unknown fields swap with self
+ protobuf_unittest::TestEmptyMessageLite empty_message;
+ SetAllTypesInEmptyMessageUnknownFields(&empty_message);
+ data = empty_message.SerializeAsString();
+ empty_message.Swap(&empty_message);
+ GOOGLE_CHECK_EQ(data, empty_message.SerializeAsString());
+ }
+
+ {
+ // Test MergeFrom with unknown fields
+ protobuf_unittest::TestAllTypesLite message, message2;
+ protobuf_unittest::TestEmptyMessageLite empty_message, empty_message2;
+ message.set_optional_int32(101);
+ message.add_repeated_int32(201);
+ message.set_optional_nested_enum(google::protobuf::unittest::TestAllTypesLite::BAZ);
+ message2.set_optional_int64(102);
+ message2.add_repeated_int64(202);
+ message2.set_optional_foreign_enum(google::protobuf::unittest::FOREIGN_LITE_BAZ);
+
+ data = message.SerializeAsString();
+ empty_message.ParseFromString(data);
+ data = message2.SerializeAsString();
+ empty_message2.ParseFromString(data);
+ message.MergeFrom(message2);
+ empty_message.MergeFrom(empty_message2);
+
+ data = empty_message.SerializeAsString();
+ message2.ParseFromString(data);
+ // We do not compare the serialized output of a normal message and a lite
+ // message because the order of fields do not match. We convert lite message
+ // back into normal message, then compare.
+ GOOGLE_CHECK_EQ(message.SerializeAsString(), message2.SerializeAsString());
+ }
+
+ {
+ // Test unknown enum value
+ protobuf_unittest::TestAllTypesLite message;
+ string buffer;
+ {
+ google::protobuf::io::StringOutputStream output_stream(&buffer);
+ google::protobuf::io::CodedOutputStream coded_output(&output_stream);
+ google::protobuf::internal::WireFormatLite::WriteTag(
+ protobuf_unittest::TestAllTypesLite::kOptionalNestedEnumFieldNumber,
+ google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT, &coded_output);
+ coded_output.WriteVarint32(10);
+ google::protobuf::internal::WireFormatLite::WriteTag(
+ protobuf_unittest::TestAllTypesLite::kRepeatedNestedEnumFieldNumber,
+ google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT, &coded_output);
+ coded_output.WriteVarint32(20);
+ }
+ message.ParseFromString(buffer);
+ data = message.SerializeAsString();
+ GOOGLE_CHECK_EQ(data, buffer);
+ }
+
+ {
+ // Test Clear with unknown fields
+ protobuf_unittest::TestEmptyMessageLite empty_message;
+ SetAllTypesInEmptyMessageUnknownFields(&empty_message);
+ empty_message.Clear();
+ GOOGLE_CHECK_EQ(0, empty_message.unknown_fields().size());
+ }
+
+ std::cout << "PASS" << std::endl;
return 0;
}
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
new file mode 100644
index 00000000..e56af3fc
--- /dev/null
+++ b/src/google/protobuf/map.h
@@ -0,0 +1,436 @@
+// 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_MAP_H__
+#define GOOGLE_PROTOBUF_MAP_H__
+
+#include <iterator>
+#include <google/protobuf/stubs/hash.h>
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_enum_util.h>
+#include <google/protobuf/map_type_handler.h>
+
+namespace google {
+namespace protobuf {
+
+template <typename Key, typename T>
+class Map;
+
+template <typename Enum> struct is_proto_enum;
+
+namespace internal {
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+class MapFieldLite;
+}
+
+// This is the class for google::protobuf::Map's internal value_type. Instead of using
+// std::pair as value_type, we use this class which provides us more control of
+// its process of construction and destruction.
+template <typename Key, typename T>
+class MapPair {
+ public:
+ typedef const Key first_type;
+ typedef T second_type;
+
+ MapPair(const Key& other_first, const T& other_second)
+ : first(other_first), second(other_second) {}
+ explicit MapPair(const Key& other_first) : first(other_first), second() {}
+ MapPair(const MapPair& other)
+ : first(other.first), second(other.second) {}
+
+ ~MapPair() {}
+
+ // Implicitly convertible to std::pair of compatible types.
+ template <typename T1, typename T2>
+ operator std::pair<T1, T2>() const {
+ return std::pair<T1, T2>(first, second);
+ }
+
+ const Key first;
+ T second;
+
+ private:
+ typedef void DestructorSkippable_;
+ friend class ::google::protobuf::Arena;
+ friend class Map<Key, T>;
+};
+
+// google::protobuf::Map is an associative container type used to store protobuf map
+// fields. Its interface is similar to std::unordered_map. Users should use this
+// interface directly to visit or change map fields.
+template <typename Key, typename T>
+class Map {
+ typedef internal::MapCppTypeHandler<Key> KeyTypeHandler;
+ typedef internal::MapCppTypeHandler<T> ValueTypeHandler;
+
+ public:
+ typedef Key key_type;
+ typedef T mapped_type;
+ typedef MapPair<Key, T> value_type;
+
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+
+ typedef size_t size_type;
+ typedef hash<Key> hasher;
+ typedef equal_to<Key> key_equal;
+
+ Map()
+ : arena_(NULL),
+ allocator_(arena_),
+ elements_(0, hasher(), key_equal(), allocator_),
+ default_enum_value_(0) {}
+ explicit Map(Arena* arena)
+ : arena_(arena),
+ allocator_(arena_),
+ elements_(0, hasher(), key_equal(), allocator_),
+ default_enum_value_(0) {}
+
+ Map(const Map& other)
+ : arena_(NULL),
+ allocator_(arena_),
+ elements_(0, hasher(), key_equal(), allocator_),
+ default_enum_value_(other.default_enum_value_) {
+ insert(other.begin(), other.end());
+ }
+
+ ~Map() { clear(); }
+
+ private:
+ // re-implement std::allocator to use arena allocator for memory allocation.
+ // Used for google::protobuf::Map implementation. Users should not use this class
+ // directly.
+ template <typename U>
+ class MapAllocator {
+ public:
+ typedef U value_type;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+ MapAllocator() : arena_(NULL) {}
+ explicit MapAllocator(Arena* arena) : arena_(arena) {}
+ template <typename X>
+ MapAllocator(const MapAllocator<X>& allocator)
+ : arena_(allocator.arena_) {}
+
+ pointer allocate(size_type n, const_pointer hint = 0) {
+ // If arena is not given, malloc needs to be called which doesn't
+ // construct element object.
+ if (arena_ == NULL) {
+ return reinterpret_cast<pointer>(malloc(n * sizeof(value_type)));
+ } else {
+ return reinterpret_cast<pointer>(
+ Arena::CreateArray<uint8>(arena_, n * sizeof(value_type)));
+ }
+ }
+
+ void deallocate(pointer p, size_type n) {
+ if (arena_ == NULL) {
+ free(p);
+ }
+ }
+
+ void construct(pointer p, const_reference t) { new (p) value_type(t); }
+
+ void destroy(pointer p) {
+ if (arena_ == NULL) p->~value_type();
+ }
+
+ template <typename X>
+ struct rebind {
+ typedef MapAllocator<X> other;
+ };
+
+ template <typename X>
+ bool operator==(const MapAllocator<X>& other) const {
+ return arena_ == other.arena_;
+ }
+
+ template <typename X>
+ bool operator!=(const MapAllocator<X>& other) const {
+ return arena_ != other.arena_;
+ }
+
+ private:
+ Arena* arena_;
+
+ template <typename X>
+ friend class MapAllocator;
+ };
+
+ public:
+ typedef MapAllocator<std::pair<const Key, MapPair<Key, T>*> > Allocator;
+
+ // Iterators
+ class LIBPROTOBUF_EXPORT const_iterator
+ : public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t,
+ const value_type*, const value_type&> {
+ typedef typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
+ Allocator>::const_iterator InnerIt;
+
+ public:
+ const_iterator() {}
+ explicit const_iterator(const InnerIt& it) : it_(it) {}
+
+ const_reference operator*() const { return *it_->second; }
+ const_pointer operator->() const { return it_->second; }
+
+ const_iterator& operator++() {
+ ++it_;
+ return *this;
+ }
+ const_iterator operator++(int) { return const_iterator(it_++); }
+
+ friend bool operator==(const const_iterator& a, const const_iterator& b) {
+ return a.it_ == b.it_;
+ }
+ friend bool operator!=(const const_iterator& a, const const_iterator& b) {
+ return a.it_ != b.it_;
+ }
+
+ private:
+ InnerIt it_;
+ };
+
+ class LIBPROTOBUF_EXPORT iterator : public std::iterator<std::forward_iterator_tag, value_type> {
+ typedef typename hash_map<Key, value_type*, hasher, equal_to<Key>,
+ Allocator>::iterator InnerIt;
+
+ public:
+ iterator() {}
+ explicit iterator(const InnerIt& it) : it_(it) {}
+
+ reference operator*() const { return *it_->second; }
+ pointer operator->() const { return it_->second; }
+
+ iterator& operator++() {
+ ++it_;
+ return *this;
+ }
+ iterator operator++(int) { return iterator(it_++); }
+
+ // Implicitly convertible to const_iterator.
+ operator const_iterator() const { return const_iterator(it_); }
+
+ friend bool operator==(const iterator& a, const iterator& b) {
+ return a.it_ == b.it_;
+ }
+ friend bool operator!=(const iterator& a, const iterator& b) {
+ return a.it_ != b.it_;
+ }
+
+ private:
+ friend class Map;
+ InnerIt it_;
+ };
+
+ iterator begin() { return iterator(elements_.begin()); }
+ iterator end() { return iterator(elements_.end()); }
+ const_iterator begin() const { return const_iterator(elements_.begin()); }
+ const_iterator end() const { return const_iterator(elements_.end()); }
+ const_iterator cbegin() const { return begin(); }
+ const_iterator cend() const { return end(); }
+
+ // Capacity
+ size_type size() const { return elements_.size(); }
+ bool empty() const { return elements_.empty(); }
+
+ // Element access
+ T& operator[](const key_type& key) {
+ value_type** value = &elements_[key];
+ if (*value == NULL) {
+ *value = CreateValueTypeInternal(key);
+ internal::MapValueInitializer<google::protobuf::is_proto_enum<T>::value,
+ T>::Initialize((*value)->second,
+ default_enum_value_);
+ }
+ return (*value)->second;
+ }
+ const T& at(const key_type& key) const {
+ const_iterator it = find(key);
+ GOOGLE_CHECK(it != end());
+ return it->second;
+ }
+ T& at(const key_type& key) {
+ iterator it = find(key);
+ GOOGLE_CHECK(it != end());
+ return it->second;
+ }
+
+ // Lookup
+ size_type count(const key_type& key) const {
+ return elements_.count(key);
+ }
+ const_iterator find(const key_type& key) const {
+ return const_iterator(elements_.find(key));
+ }
+ iterator find(const key_type& key) {
+ return iterator(elements_.find(key));
+ }
+ std::pair<const_iterator, const_iterator> equal_range(
+ const key_type& key) const {
+ const_iterator it = find(key);
+ if (it == end()) {
+ return std::pair<const_iterator, const_iterator>(it, it);
+ } else {
+ const_iterator begin = it++;
+ return std::pair<const_iterator, const_iterator>(begin, it);
+ }
+ }
+ std::pair<iterator, iterator> equal_range(const key_type& key) {
+ iterator it = find(key);
+ if (it == end()) {
+ return std::pair<iterator, iterator>(it, it);
+ } else {
+ iterator begin = it++;
+ return std::pair<iterator, iterator>(begin, it);
+ }
+ }
+
+ // insert
+ std::pair<iterator, bool> insert(const value_type& value) {
+ iterator it = find(value.first);
+ if (it != end()) {
+ return std::pair<iterator, bool>(it, false);
+ } else {
+ return std::pair<iterator, bool>(
+ iterator(elements_.insert(std::pair<Key, value_type*>(
+ value.first, CreateValueTypeInternal(value))).first), true);
+ }
+ }
+ template <class InputIt>
+ void insert(InputIt first, InputIt last) {
+ for (InputIt it = first; it != last; ++it) {
+ iterator exist_it = find(it->first);
+ if (exist_it == end()) {
+ operator[](it->first) = it->second;
+ }
+ }
+ }
+
+ // Erase
+ size_type erase(const key_type& key) {
+ typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
+ Allocator>::iterator it = elements_.find(key);
+ if (it == elements_.end()) {
+ return 0;
+ } else {
+ if (arena_ == NULL) delete it->second;
+ elements_.erase(it);
+ return 1;
+ }
+ }
+ void erase(iterator pos) {
+ if (arena_ == NULL) delete pos.it_->second;
+ elements_.erase(pos.it_);
+ }
+ void erase(iterator first, iterator last) {
+ for (iterator it = first; it != last;) {
+ if (arena_ == NULL) delete it.it_->second;
+ elements_.erase((it++).it_);
+ }
+ }
+ void clear() {
+ for (iterator it = begin(); it != end(); ++it) {
+ if (arena_ == NULL) delete it.it_->second;
+ }
+ elements_.clear();
+ }
+
+ // Assign
+ Map& operator=(const Map& other) {
+ if (this != &other) {
+ clear();
+ insert(other.begin(), other.end());
+ }
+ return *this;
+ }
+
+ private:
+ // Set default enum value only for proto2 map field whose value is enum type.
+ void SetDefaultEnumValue(int default_enum_value) {
+ default_enum_value_ = default_enum_value;
+ }
+
+ value_type* CreateValueTypeInternal(const Key& key) {
+ if (arena_ == NULL) {
+ return new value_type(key);
+ } else {
+ value_type* value = reinterpret_cast<value_type*>(
+ Arena::CreateArray<uint8>(arena_, sizeof(value_type)));
+ Arena::CreateInArenaStorage(const_cast<Key*>(&value->first), arena_);
+ Arena::CreateInArenaStorage(&value->second, arena_);
+ const_cast<Key&>(value->first) = key;
+ return value;
+ }
+ }
+
+ value_type* CreateValueTypeInternal(const value_type& value) {
+ if (arena_ == NULL) {
+ return new value_type(value);
+ } else {
+ value_type* p = reinterpret_cast<value_type*>(
+ Arena::CreateArray<uint8>(arena_, sizeof(value_type)));
+ Arena::CreateInArenaStorage(const_cast<Key*>(&p->first), arena_);
+ Arena::CreateInArenaStorage(&p->second, arena_);
+ const_cast<Key&>(p->first) = value.first;
+ p->second = value.second;
+ return p;
+ }
+ }
+
+ Arena* arena_;
+ Allocator allocator_;
+ hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator> elements_;
+ int default_enum_value_;
+
+ friend class ::google::protobuf::Arena;
+ typedef void DestructorSkippable_;
+ template <typename K, typename V,
+ internal::WireFormatLite::FieldType key_wire_type,
+ internal::WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+ friend class LIBPROTOBUF_EXPORT internal::MapFieldLite;
+};
+
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MAP_H__
diff --git a/src/google/protobuf/map_entry.h b/src/google/protobuf/map_entry.h
new file mode 100644
index 00000000..f78a4f40
--- /dev/null
+++ b/src/google/protobuf/map_entry.h
@@ -0,0 +1,295 @@
+// 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_MAP_ENTRY_H__
+#define GOOGLE_PROTOBUF_MAP_ENTRY_H__
+
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/map_entry_lite.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+
+namespace google {
+namespace protobuf {
+class Arena;
+namespace internal {
+template <typename Key, typename Value,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+class MapField;
+}
+}
+
+namespace protobuf {
+namespace internal {
+
+// Register all MapEntry default instances so we can delete them in
+// ShutdownProtobufLibrary().
+void LIBPROTOBUF_EXPORT RegisterMapEntryDefaultInstance(
+ MessageLite* default_instance);
+
+// This is the common base class for MapEntry. It is used by MapFieldBase in
+// reflection api, in which the static type of key and value is unknown.
+class LIBPROTOBUF_EXPORT MapEntryBase : public Message {
+ public:
+ ::google::protobuf::Metadata GetMetadata() const {
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = descriptor_;
+ metadata.reflection = reflection_;
+ return metadata;
+ }
+
+ protected:
+ MapEntryBase() : descriptor_(NULL), reflection_(NULL) { }
+ virtual ~MapEntryBase() {}
+
+ const Descriptor* descriptor_;
+ const Reflection* reflection_;
+};
+
+// MapEntry is the returned google::protobuf::Message when calling AddMessage of
+// google::protobuf::Reflection. In order to let it work with generated message
+// reflection, its internal layout is the same as generated message with the
+// same fields. However, in order to decide the internal layout of key/value, we
+// need to know both their cpp type in generated api and proto type.
+//
+// cpp type | proto type | internal layout
+// int32 TYPE_INT32 int32
+// int32 TYPE_FIXED32 int32
+// FooEnum TYPE_ENUM int
+// FooMessage TYPE_MESSAGE FooMessage*
+//
+// The internal layouts of primitive types can be inferred from its proto type,
+// while we need to explicitly tell cpp type if proto type is TYPE_MESSAGE to
+// get internal layout.
+// Moreover, default_enum_value is used to initialize enum field in proto2.
+template <typename Key, typename Value,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+class LIBPROTOBUF_EXPORT MapEntry : public MapEntryBase {
+ // Handlers for key/value wire type. Provide utilities to parse/serialize
+ // key/value.
+ typedef MapWireFieldTypeHandler<kKeyFieldType> KeyWireHandler;
+ typedef MapWireFieldTypeHandler<kValueFieldType> ValueWireHandler;
+
+ // Define key/value's internal stored type. Message is the only one whose
+ // internal stored type cannot be inferred from its proto type.
+ static const bool kIsKeyMessage = KeyWireHandler::kIsMessage;
+ static const bool kIsValueMessage = ValueWireHandler::kIsMessage;
+ typedef typename KeyWireHandler::CppType KeyInternalType;
+ typedef typename ValueWireHandler::CppType ValueInternalType;
+ typedef typename MapIf<kIsKeyMessage, Key, KeyInternalType>::type
+ KeyCppType;
+ typedef typename MapIf<kIsValueMessage, Value, ValueInternalType>::type
+ ValCppType;
+
+ // Abbreviation for MapEntry
+ typedef typename google::protobuf::internal::MapEntry<
+ Key, Value, kKeyFieldType, kValueFieldType, default_enum_value> EntryType;
+
+ // Abbreviation for MapEntryLite
+ typedef typename google::protobuf::internal::MapEntryLite<
+ Key, Value, kKeyFieldType, kValueFieldType, default_enum_value>
+ EntryLiteType;
+
+ public:
+ ~MapEntry() {
+ if (this == default_instance_) {
+ delete reflection_;
+ }
+ }
+
+ // accessors ======================================================
+
+ virtual inline const KeyCppType& key() const {
+ return entry_lite_.key();
+ }
+ inline KeyCppType* mutable_key() {
+ return entry_lite_.mutable_key();
+ }
+ virtual inline const ValCppType& value() const {
+ return entry_lite_.value();
+ }
+ inline ValCppType* mutable_value() {
+ return entry_lite_.mutable_value();
+ }
+
+ // implements Message =============================================
+
+ bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
+ return entry_lite_.MergePartialFromCodedStream(input);
+ }
+
+ int ByteSize() const {
+ return entry_lite_.ByteSize();
+ }
+
+ void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const {
+ entry_lite_.SerializeWithCachedSizes(output);
+ }
+
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return entry_lite_.SerializeWithCachedSizesToArray(output);
+ }
+
+ int GetCachedSize() const {
+ return entry_lite_.GetCachedSize();
+ }
+
+ bool IsInitialized() const {
+ return entry_lite_.IsInitialized();
+ }
+
+ Message* New() const {
+ MapEntry* entry = new MapEntry;
+ entry->descriptor_ = descriptor_;
+ entry->reflection_ = reflection_;
+ entry->set_default_instance(default_instance_);
+ return entry;
+ }
+
+ Message* New(Arena* arena) const {
+ MapEntry* entry = Arena::CreateMessage<MapEntry>(arena);
+ entry->descriptor_ = descriptor_;
+ entry->reflection_ = reflection_;
+ entry->set_default_instance(default_instance_);
+ return entry;
+ }
+
+ int SpaceUsed() const {
+ int size = sizeof(MapEntry);
+ size += entry_lite_.SpaceUsed();
+ return size;
+ }
+
+ void CopyFrom(const ::google::protobuf::Message& from) {
+ Clear();
+ MergeFrom(from);
+ }
+
+ void MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const MapEntry* source = dynamic_cast_if_available<const MapEntry*>(&from);
+ if (source == NULL) {
+ ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+ }
+
+ void CopyFrom(const MapEntry& from) {
+ Clear();
+ MergeFrom(from);
+ }
+
+ void MergeFrom(const MapEntry& from) {
+ entry_lite_.MergeFrom(from.entry_lite_);
+ }
+
+ void Clear() {
+ entry_lite_.Clear();
+ }
+
+ void InitAsDefaultInstance() {
+ entry_lite_.InitAsDefaultInstance();
+ }
+
+ Arena* GetArena() const {
+ return entry_lite_.GetArena();
+ }
+
+ // Create default MapEntry instance for given descriptor. Descriptor has to be
+ // given when creating default MapEntry instance because different map field
+ // may have the same type and MapEntry class. The given descriptor is needed
+ // to distinguish instances of the same MapEntry class.
+ static MapEntry* CreateDefaultInstance(const Descriptor* descriptor) {
+ MapEntry* entry = new MapEntry;
+ const Reflection* reflection = new GeneratedMessageReflection(
+ descriptor, entry, offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, entry_lite_._has_bits_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, _unknown_fields_), -1,
+ DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(), sizeof(MapEntry), -1);
+ entry->descriptor_ = descriptor;
+ entry->reflection_ = reflection;
+ entry->set_default_instance(entry);
+ entry->InitAsDefaultInstance();
+ RegisterMapEntryDefaultInstance(entry);
+ return entry;
+ }
+
+ private:
+ MapEntry() : default_instance_(NULL), entry_lite_() {}
+
+ explicit MapEntry(Arena* arena)
+ : default_instance_(NULL), entry_lite_(arena) {}
+
+ inline Arena* GetArenaNoVirtual() const {
+ return entry_lite_.GetArenaNoVirtual();
+ }
+
+ void set_default_instance(MapEntry* default_instance) {
+ default_instance_ = default_instance;
+ entry_lite_.set_default_instance(&default_instance->entry_lite_);
+ }
+
+ static int offsets_[2];
+ UnknownFieldSet _unknown_fields_;
+ MapEntry* default_instance_;
+ EntryLiteType entry_lite_;
+
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
+ template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
+ WireFormatLite::FieldType, int default_enum>
+ friend class LIBPROTOBUF_EXPORT internal::MapField;
+ friend class LIBPROTOBUF_EXPORT internal::GeneratedMessageReflection;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntry);
+};
+
+template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType, int default_enum_value>
+int MapEntry<Key, Value, kKeyFieldType, kValueFieldType,
+ default_enum_value>::offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, entry_lite_.key_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, entry_lite_.value_),
+};
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MAP_ENTRY_H__
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
new file mode 100644
index 00000000..304fba88
--- /dev/null
+++ b/src/google/protobuf/map_entry_lite.h
@@ -0,0 +1,409 @@
+// 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_MAP_ENTRY_LITE_H__
+#define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
+
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+
+namespace google {
+namespace protobuf {
+class Arena;
+namespace internal {
+template <typename Key, typename Value,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+class MapEntry;
+template <typename Key, typename Value,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+class MapFieldLite;
+} // namespace internal
+} // namespace protobuf
+
+namespace protobuf {
+namespace internal {
+
+// MapEntryLite is used to implement parsing and serialization of map for lite
+// runtime.
+template <typename Key, typename Value,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+class LIBPROTOBUF_EXPORT MapEntryLite : public MessageLite {
+ // Handlers for key/value wire type. Provide utilities to parse/serialize
+ // key/value.
+ typedef MapWireFieldTypeHandler<kKeyFieldType> KeyWireHandler;
+ typedef MapWireFieldTypeHandler<kValueFieldType> ValueWireHandler;
+
+ // Define key/value's internal stored type. Message is the only one whose
+ // internal stored type cannot be inferred from its proto type
+ static const bool kIsKeyMessage = KeyWireHandler::kIsMessage;
+ static const bool kIsValueMessage = ValueWireHandler::kIsMessage;
+ typedef typename KeyWireHandler::CppType KeyInternalType;
+ typedef typename ValueWireHandler::CppType ValueInternalType;
+ typedef typename MapIf<kIsKeyMessage, Key, KeyInternalType>::type
+ KeyCppType;
+ typedef typename MapIf<kIsValueMessage, Value, ValueInternalType>::type
+ ValCppType;
+
+ // Handlers for key/value's internal stored type. Provide utilities to
+ // manipulate internal stored type. We need it because some types are stored
+ // as values and others are stored as pointers (Message and string), but we
+ // need to keep the code in MapEntry unified instead of providing different
+ // codes for each type.
+ typedef MapCppTypeHandler<KeyCppType> KeyCppHandler;
+ typedef MapCppTypeHandler<ValCppType> ValueCppHandler;
+
+ // Define internal memory layout. Strings and messages are stored as
+ // pointers, while other types are stored as values.
+ static const bool kKeyIsStringOrMessage = KeyCppHandler::kIsStringOrMessage;
+ static const bool kValIsStringOrMessage = ValueCppHandler::kIsStringOrMessage;
+ typedef typename MapIf<kKeyIsStringOrMessage, KeyCppType*, KeyCppType>::type
+ KeyBase;
+ typedef typename MapIf<kValIsStringOrMessage, ValCppType*, ValCppType>::type
+ ValueBase;
+
+ // Constants for field number.
+ static const int kKeyFieldNumber = 1;
+ static const int kValueFieldNumber = 2;
+
+ // Constants for field tag.
+ static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+ kKeyFieldNumber, KeyWireHandler::kWireType);
+ static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+ kValueFieldNumber, ValueWireHandler::kWireType);
+ static const int kTagSize = 1;
+
+ public:
+ ~MapEntryLite() {
+ if (this != default_instance_) {
+ KeyCppHandler::Delete(key_);
+ ValueCppHandler::Delete(value_);
+ }
+ }
+
+ // accessors ======================================================
+
+ virtual inline const KeyCppType& key() const {
+ return KeyCppHandler::Reference(key_);
+ }
+ inline KeyCppType* mutable_key() {
+ set_has_key();
+ KeyCppHandler::EnsureMutable(&key_, GetArenaNoVirtual());
+ return KeyCppHandler::Pointer(key_);
+ }
+ virtual inline const ValCppType& value() const {
+ GOOGLE_CHECK(default_instance_ != NULL);
+ return ValueCppHandler::DefaultIfNotInitialized(value_,
+ default_instance_->value_);
+ }
+ inline ValCppType* mutable_value() {
+ set_has_value();
+ ValueCppHandler::EnsureMutable(&value_, GetArenaNoVirtual());
+ return ValueCppHandler::Pointer(value_);
+ }
+
+ // implements MessageLite =========================================
+
+ // MapEntryLite is for implementation only and this function isn't called
+ // anywhere. Just provide a fake implementation here for MessageLite.
+ string GetTypeName() const { return ""; }
+
+ void CheckTypeAndMergeFrom(const MessageLite& other) {
+ MergeFrom(*::google::protobuf::down_cast<const MapEntryLite*>(&other));
+ }
+
+ bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
+ uint32 tag;
+
+ for (;;) {
+ // 1) corrupted data: return false;
+ // 2) unknown field: skip without putting into unknown field set;
+ // 3) unknown enum value: keep it in parsing. In proto2, caller should
+ // check the value and put this entry into containing message's unknown
+ // field set if the value is an unknown enum. In proto3, caller doesn't
+ // need to care whether the value is unknown enum;
+ // 4) missing key/value: missed key/value will have default value. caller
+ // should take this entry as if key/value is set to default value.
+ tag = input->ReadTag();
+ switch (tag) {
+ case kKeyTag:
+ if (!KeyWireHandler::Read(input, mutable_key())) return false;
+ set_has_key();
+ if (!input->ExpectTag(kValueTag)) break;
+ GOOGLE_FALLTHROUGH_INTENDED;
+
+ case kValueTag:
+ if (!ValueWireHandler::Read(input, mutable_value())) return false;
+ set_has_value();
+ if (input->ExpectAtEnd()) return true;
+ break;
+
+ default:
+ if (tag == 0 ||
+ WireFormatLite::GetTagWireType(tag) ==
+ WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ if (!WireFormatLite::SkipField(input, tag)) return false;
+ break;
+ }
+ }
+ }
+
+ int ByteSize() const {
+ int size = 0;
+ size += has_key() ? kTagSize + KeyWireHandler::ByteSize(key()) : 0;
+ size += has_value() ? kTagSize + ValueWireHandler::ByteSize(value()) : 0;
+ return size;
+ }
+
+ void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const {
+ KeyWireHandler::Write(kKeyFieldNumber, key(), output);
+ ValueWireHandler::Write(kValueFieldNumber, value(), output);
+ }
+
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ output = KeyWireHandler::WriteToArray(kKeyFieldNumber, key(), output);
+ output =
+ ValueWireHandler::WriteToArray(kValueFieldNumber, value(), output);
+ return output;
+ }
+
+ int GetCachedSize() const {
+ int size = 0;
+ size += has_key() ? kTagSize + KeyWireHandler::GetCachedSize(key()) : 0;
+ size +=
+ has_value() ? kTagSize + ValueWireHandler::GetCachedSize(value()) : 0;
+ return size;
+ }
+
+ bool IsInitialized() const { return ValueCppHandler::IsInitialized(value_); }
+
+ MessageLite* New() const {
+ MapEntryLite* entry = new MapEntryLite;
+ entry->default_instance_ = default_instance_;
+ return entry;
+ }
+
+ MessageLite* New(Arena* arena) const {
+ MapEntryLite* entry = Arena::CreateMessage<MapEntryLite>(arena);
+ entry->default_instance_ = default_instance_;
+ return entry;
+ }
+
+ int SpaceUsed() const {
+ int size = sizeof(MapEntryLite);
+ size += KeyCppHandler::SpaceUsedInMapEntry(key_);
+ size += ValueCppHandler::SpaceUsedInMapEntry(value_);
+ return size;
+ }
+
+ void MergeFrom(const MapEntryLite& from) {
+ if (from._has_bits_[0]) {
+ if (from.has_key()) {
+ KeyCppHandler::EnsureMutable(&key_, GetArenaNoVirtual());
+ KeyCppHandler::Merge(from.key(), &key_);
+ set_has_key();
+ }
+ if (from.has_value()) {
+ ValueCppHandler::EnsureMutable(&value_, GetArenaNoVirtual());
+ ValueCppHandler::Merge(from.value(), &value_);
+ set_has_value();
+ }
+ }
+ }
+
+ void Clear() {
+ KeyCppHandler::Clear(&key_);
+ ValueCppHandler::ClearMaybeByDefaultEnum(&value_, default_enum_value);
+ clear_has_key();
+ clear_has_value();
+ }
+
+ void InitAsDefaultInstance() {
+ KeyCppHandler::AssignDefaultValue(&key_);
+ ValueCppHandler::AssignDefaultValue(&value_);
+ }
+
+ Arena* GetArena() const {
+ return GetArenaNoVirtual();
+ }
+
+ // Create a MapEntryLite for given key and value from google::protobuf::Map in
+ // serialization. This function is only called when value is enum. Enum is
+ // treated differently because its type in MapEntry is int and its type in
+ // google::protobuf::Map is enum. We cannot create a reference to int from an enum.
+ static MapEntryLite* EnumWrap(const Key& key, const Value value,
+ Arena* arena) {
+ return Arena::Create<MapEnumEntryWrapper<
+ Key, Value, kKeyFieldType, kValueFieldType, default_enum_value> >(
+ arena, key, value, arena);
+ }
+
+ // Like above, but for all the other types. This avoids value copy to create
+ // MapEntryLite from google::protobuf::Map in serialization.
+ static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) {
+ return Arena::Create<MapEntryWrapper<Key, Value, kKeyFieldType,
+ kValueFieldType, default_enum_value> >(
+ arena, key, value, arena);
+ }
+
+ protected:
+ void set_has_key() { _has_bits_[0] |= 0x00000001u; }
+ bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
+ void clear_has_key() { _has_bits_[0] &= ~0x00000001u; }
+ void set_has_value() { _has_bits_[0] |= 0x00000002u; }
+ bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
+ void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
+
+ private:
+ // Serializing a generated message containing map field involves serializing
+ // key-value pairs from google::protobuf::Map. The wire format of each key-value pair
+ // after serialization should be the same as that of a MapEntry message
+ // containing the same key and value inside it. However, google::protobuf::Map doesn't
+ // store key and value as MapEntry message, which disables us to use existing
+ // code to serialize message. In order to use existing code to serialize
+ // message, we need to construct a MapEntry from key-value pair. But it
+ // involves copy of key and value to construct a MapEntry. In order to avoid
+ // this copy in constructing a MapEntry, we need the following class which
+ // only takes references of given key and value.
+ template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
+ WireFormatLite::FieldType v_wire_type, int default_enum>
+ class LIBPROTOBUF_EXPORT MapEntryWrapper
+ : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> {
+ typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base;
+ typedef typename Base::KeyCppType KeyCppType;
+ typedef typename Base::ValCppType ValCppType;
+
+ public:
+ MapEntryWrapper(const K& key, const V& value, Arena* arena)
+ : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena),
+ key_(key),
+ value_(value) {
+ Base::set_has_key();
+ Base::set_has_value();
+ }
+ inline const KeyCppType& key() const { return key_; }
+ inline const ValCppType& value() const { return value_; }
+
+ private:
+ const Key& key_;
+ const Value& value_;
+
+ friend class ::google::protobuf::Arena;
+ typedef void DestructorSkippable_;
+ };
+
+ // Like above, but for enum value only, which stores value instead of
+ // reference of value field inside. This is needed because the type of value
+ // field in constructor is an enum, while we need to store it as an int. If we
+ // initialize a reference to int with a reference to enum, compiler will
+ // generate a temporary int from enum and initialize the reference to int with
+ // the temporary.
+ template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
+ WireFormatLite::FieldType v_wire_type, int default_enum>
+ class LIBPROTOBUF_EXPORT MapEnumEntryWrapper
+ : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> {
+ typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base;
+ typedef typename Base::KeyCppType KeyCppType;
+ typedef typename Base::ValCppType ValCppType;
+
+ public:
+ MapEnumEntryWrapper(const K& key, const V& value, Arena* arena)
+ : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena),
+ key_(key),
+ value_(value) {
+ Base::set_has_key();
+ Base::set_has_value();
+ }
+ inline const KeyCppType& key() const { return key_; }
+ inline const ValCppType& value() const { return value_; }
+
+ private:
+ const KeyCppType& key_;
+ const ValCppType value_;
+
+ friend class ::google::protobuf::Arena;
+ typedef void DestructorSkippable_;
+ };
+
+ MapEntryLite() : default_instance_(NULL), arena_(NULL) {
+ KeyCppHandler::Initialize(&key_, NULL);
+ ValueCppHandler::InitializeMaybeByDefaultEnum(
+ &value_, default_enum_value, NULL);
+ _has_bits_[0] = 0;
+ }
+
+ explicit MapEntryLite(Arena* arena)
+ : default_instance_(NULL), arena_(arena) {
+ KeyCppHandler::Initialize(&key_, arena);
+ ValueCppHandler::InitializeMaybeByDefaultEnum(
+ &value_, default_enum_value, arena);
+ _has_bits_[0] = 0;
+ }
+
+ inline Arena* GetArenaNoVirtual() const {
+ return arena_;
+ }
+
+ void set_default_instance(MapEntryLite* default_instance) {
+ default_instance_ = default_instance;
+ }
+
+ MapEntryLite* default_instance_;
+
+ KeyBase key_;
+ ValueBase value_;
+ Arena* arena_;
+ uint32 _has_bits_[1];
+
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
+ template <typename K, typename V, WireFormatLite::FieldType,
+ WireFormatLite::FieldType, int>
+ friend class LIBPROTOBUF_EXPORT internal::MapEntry;
+ template <typename K, typename V, WireFormatLite::FieldType,
+ WireFormatLite::FieldType, int>
+ friend class LIBPROTOBUF_EXPORT internal::MapFieldLite;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
+};
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
new file mode 100644
index 00000000..fd40c0d8
--- /dev/null
+++ b/src/google/protobuf/map_field.cc
@@ -0,0 +1,142 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/map_field.h>
+
+#include <vector>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+ProtobufOnceType map_entry_default_instances_once_;
+Mutex* map_entry_default_instances_mutex_;
+vector<MessageLite*>* map_entry_default_instances_;
+
+void DeleteMapEntryDefaultInstances() {
+ for (int i = 0; i < map_entry_default_instances_->size(); ++i) {
+ delete map_entry_default_instances_->at(i);
+ }
+ delete map_entry_default_instances_mutex_;
+ delete map_entry_default_instances_;
+}
+
+void InitMapEntryDefaultInstances() {
+ map_entry_default_instances_mutex_ = new Mutex();
+ map_entry_default_instances_ = new vector<MessageLite*>();
+ OnShutdown(&DeleteMapEntryDefaultInstances);
+}
+
+void RegisterMapEntryDefaultInstance(MessageLite* default_instance) {
+ ::google::protobuf::GoogleOnceInit(&map_entry_default_instances_once_,
+ &InitMapEntryDefaultInstances);
+ MutexLock lock(map_entry_default_instances_mutex_);
+ map_entry_default_instances_->push_back(default_instance);
+}
+
+MapFieldBase::~MapFieldBase() {
+ if (repeated_field_ != NULL && arena_ == NULL) delete repeated_field_;
+}
+
+const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const {
+ SyncRepeatedFieldWithMap();
+ return *repeated_field_;
+}
+
+RepeatedPtrFieldBase* MapFieldBase::MutableRepeatedField() {
+ SyncRepeatedFieldWithMap();
+ SetRepeatedDirty();
+ return repeated_field_;
+}
+
+int MapFieldBase::SpaceUsedExcludingSelf() const {
+ mutex_.Lock();
+ int size = SpaceUsedExcludingSelfNoLock();
+ mutex_.Unlock();
+ return size;
+}
+
+int MapFieldBase::SpaceUsedExcludingSelfNoLock() const {
+ if (repeated_field_ != NULL) {
+ return repeated_field_->SpaceUsedExcludingSelf();
+ } else {
+ return 0;
+ }
+}
+
+void MapFieldBase::InitMetadataOnce() const {
+ GOOGLE_CHECK(entry_descriptor_ != NULL);
+ GOOGLE_CHECK(assign_descriptor_callback_ != NULL);
+ (*assign_descriptor_callback_)();
+}
+
+void MapFieldBase::SetMapDirty() { state_ = STATE_MODIFIED_MAP; }
+
+void MapFieldBase::SetRepeatedDirty() { state_ = STATE_MODIFIED_REPEATED; }
+
+void* MapFieldBase::MutableRepeatedPtrField() const { return repeated_field_; }
+
+void MapFieldBase::SyncRepeatedFieldWithMap() const {
+ Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_);
+ if (state == STATE_MODIFIED_MAP) {
+ mutex_.Lock();
+ // Double check state, because another thread may have seen the same state
+ // and done the synchronization before the current thread.
+ if (state_ == STATE_MODIFIED_MAP) {
+ SyncRepeatedFieldWithMapNoLock();
+ google::protobuf::internal::NoBarrier_Store(&state_, CLEAN);
+ }
+ mutex_.Unlock();
+ }
+}
+
+void MapFieldBase::SyncRepeatedFieldWithMapNoLock() const {
+ if (repeated_field_ == NULL) {
+ repeated_field_ = Arena::Create<RepeatedPtrField<Message> >(arena_, arena_);
+ }
+}
+
+void MapFieldBase::SyncMapWithRepeatedField() const {
+ Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_);
+ if (state == STATE_MODIFIED_REPEATED) {
+ mutex_.Lock();
+ // Double check state, because another thread may have seen the same state
+ // and done the synchronization before the current thread.
+ if (state_ == STATE_MODIFIED_REPEATED) {
+ SyncMapWithRepeatedFieldNoLock();
+ google::protobuf::internal::NoBarrier_Store(&state_, CLEAN);
+ }
+ mutex_.Unlock();
+ }
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
new file mode 100644
index 00000000..6d8b6ec8
--- /dev/null
+++ b/src/google/protobuf/map_field.h
@@ -0,0 +1,237 @@
+// 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_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_H__
+
+#include <google/protobuf/stubs/atomicops.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/map_entry.h>
+#include <google/protobuf/map_field_lite.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+class ContendedMapCleanTest;
+class GeneratedMessageReflection;
+class MapFieldAccessor;
+
+// This class provides accesss to map field using reflection, which is the same
+// as those provided for RepeatedPtrField<Message>. It is used for internal
+// reflection implentation only. Users should never use this directly.
+class LIBPROTOBUF_EXPORT MapFieldBase {
+ public:
+ MapFieldBase()
+ : arena_(NULL),
+ repeated_field_(NULL),
+ entry_descriptor_(NULL),
+ assign_descriptor_callback_(NULL),
+ state_(STATE_MODIFIED_MAP) {}
+ explicit MapFieldBase(Arena* arena)
+ : arena_(arena),
+ repeated_field_(NULL),
+ entry_descriptor_(NULL),
+ assign_descriptor_callback_(NULL),
+ state_(STATE_MODIFIED_MAP) {}
+ virtual ~MapFieldBase();
+
+ // Returns reference to internal repeated field. Data written using
+ // google::protobuf::Map's api prior to calling this function is guarantted to be
+ // included in repeated field.
+ const RepeatedPtrFieldBase& GetRepeatedField() const;
+
+ // Like above. Returns mutable pointer to the internal repeated field.
+ RepeatedPtrFieldBase* MutableRepeatedField();
+
+ // Returns the number of bytes used by the repeated field, excluding
+ // sizeof(*this)
+ int SpaceUsedExcludingSelf() const;
+
+ protected:
+ // Gets the size of space used by map field.
+ virtual int SpaceUsedExcludingSelfNoLock() const;
+
+ // Synchronizes the content in Map to RepeatedPtrField if there is any change
+ // to Map after last synchronization.
+ void SyncRepeatedFieldWithMap() const;
+ virtual void SyncRepeatedFieldWithMapNoLock() const;
+
+ // Synchronizes the content in RepeatedPtrField to Map if there is any change
+ // to RepeatedPtrField after last synchronization.
+ void SyncMapWithRepeatedField() const;
+ virtual void SyncMapWithRepeatedFieldNoLock() const {}
+
+ // Tells MapFieldBase that there is new change to Map.
+ void SetMapDirty();
+
+ // Tells MapFieldBase that there is new change to RepeatedPTrField.
+ void SetRepeatedDirty();
+
+ // Provides derived class the access to repeated field.
+ void* MutableRepeatedPtrField() const;
+
+ // Creates descriptor for only one time.
+ void InitMetadataOnce() const;
+
+ enum State {
+ STATE_MODIFIED_MAP = 0, // map has newly added data that has not been
+ // synchronized to repeated field
+ STATE_MODIFIED_REPEATED = 1, // repeated field has newly added data that
+ // has not been synchronized to map
+ CLEAN = 2, // data in map and repeated field are same
+ };
+
+ Arena* arena_;
+ mutable RepeatedPtrField<Message>* repeated_field_;
+ // MapEntry can only be created from MapField. To create MapEntry, MapField
+ // needs to know its descriptor, because MapEntry is not generated class which
+ // cannot initialize its own descriptor by calling generated
+ // descriptor-assign-function. Thus, we need to register a callback to
+ // initialize MapEntry's descriptor.
+ const Descriptor** entry_descriptor_;
+ void (*assign_descriptor_callback_)();
+
+ mutable Mutex mutex_; // The thread to synchronize map and repeated field
+ // needs to get lock first;
+ mutable volatile Atomic32 state_; // 0: STATE_MODIFIED_MAP
+ // 1: STATE_MODIFIED_REPEATED
+ // 2: CLEAN
+
+ private:
+ friend class ContendedMapCleanTest;
+ friend class GeneratedMessageReflection;
+ friend class MapFieldAccessor;
+};
+
+// This class provides accesss to map field using generated api. It is used for
+// internal generated message implentation only. Users should never use this
+// directly.
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value = 0>
+class LIBPROTOBUF_EXPORT MapField : public MapFieldBase,
+ public MapFieldLite<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value> {
+ // Handlers for key/value wire type. Provide utilities to parse/serialize
+ // key/value.
+ typedef MapWireFieldTypeHandler<kKeyFieldType> KeyWireHandler;
+ typedef MapWireFieldTypeHandler<kValueFieldType> ValueWireHandler;
+
+ // Define key/value's internal stored type.
+ static const bool kIsKeyMessage = KeyWireHandler::kIsMessage;
+ static const bool kIsValMessage = ValueWireHandler::kIsMessage;
+ typedef typename KeyWireHandler::CppType KeyInternalType;
+ typedef typename ValueWireHandler::CppType ValueInternalType;
+ typedef typename MapIf<kIsKeyMessage, Key, KeyInternalType>::type KeyCpp;
+ typedef typename MapIf<kIsValMessage, T , ValueInternalType>::type ValCpp;
+
+ // Handlers for key/value's internal stored type.
+ typedef MapCppTypeHandler<KeyCpp> KeyHandler;
+ typedef MapCppTypeHandler<ValCpp> ValHandler;
+
+ // Define message type for internal repeated field.
+ typedef MapEntry<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>
+ EntryType;
+ typedef MapEntryLite<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value> EntryLiteType;
+
+ // Define abbreviation for parent MapFieldLite
+ typedef MapFieldLite<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value> MapFieldLiteType;
+
+ // Enum needs to be handled differently from other types because it has
+ // different exposed type in google::protobuf::Map's api and repeated field's api. For
+ // details see the comment in the implementation of
+ // SyncMapWithRepeatedFieldNoLocki.
+ static const bool kIsValueEnum = ValueWireHandler::kIsEnum;
+ typedef typename MapIf<kIsValueEnum, T, const T&>::type CastValueType;
+
+ public:
+ MapField();
+ explicit MapField(Arena* arena);
+ // MapField doesn't own the default_entry, which means default_entry must
+ // outlive the lifetime of MapField.
+ MapField(const Message* default_entry);
+ // For tests only.
+ MapField(Arena* arena, const Message* default_entry);
+ ~MapField();
+
+ // Accessors
+ const Map<Key, T>& GetMap() const;
+ Map<Key, T>* MutableMap();
+
+ // Convenient methods for generated message implementation.
+ int size() const;
+ void Clear();
+ void MergeFrom(const MapFieldLiteType& other);
+ void Swap(MapFieldLiteType* other);
+
+ // Allocates metadata only if this MapField is part of a generated message.
+ void SetEntryDescriptor(const Descriptor** descriptor);
+ void SetAssignDescriptorCallback(void (*callback)());
+
+ private:
+ typedef void DestructorSkippable_;
+
+ // MapField needs MapEntry's default instance to create new MapEntry.
+ void InitDefaultEntryOnce() const;
+
+ // Manually set default entry instance. For test only.
+ void SetDefaultEntryOnce(const EntryType* default_entry) const;
+
+ // Convenient methods to get internal google::protobuf::Map
+ const Map<Key, T>& GetInternalMap() const;
+ Map<Key, T>* MutableInternalMap();
+
+ // Implements MapFieldBase
+ void SyncRepeatedFieldWithMapNoLock() const;
+ void SyncMapWithRepeatedFieldNoLock() const;
+ int SpaceUsedExcludingSelfNoLock() const;
+
+ mutable const EntryType* default_entry_;
+
+ friend class ::google::protobuf::Arena;
+};
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MAP_FIELD_H__
diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h
new file mode 100644
index 00000000..ae63c721
--- /dev/null
+++ b/src/google/protobuf/map_field_inl.h
@@ -0,0 +1,302 @@
+// 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_MAP_FIELD_INL_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_type_handler.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField()
+ : default_entry_(NULL) {}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField(
+ Arena* arena)
+ : MapFieldBase(arena),
+ MapFieldLite<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>(
+ arena),
+ default_entry_(NULL) {}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField(
+ const Message* default_entry)
+ : default_entry_(down_cast<const EntryType*>(default_entry)) {}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField(
+ Arena* arena, const Message* default_entry)
+ : MapFieldBase(arena),
+ MapFieldLite<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>(
+ arena),
+ default_entry_(down_cast<const EntryType*>(default_entry)) {}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::~MapField() {}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+int
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::size() const {
+ SyncMapWithRepeatedField();
+ return MapFieldLiteType::GetInternalMap().size();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::Clear() {
+ SyncMapWithRepeatedField();
+ MapFieldLiteType::MutableInternalMap()->clear();
+ SetMapDirty();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+const Map<Key, T>&
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::GetMap() const {
+ SyncMapWithRepeatedField();
+ return MapFieldLiteType::GetInternalMap();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+Map<Key, T>*
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::MutableMap() {
+ SyncMapWithRepeatedField();
+ Map<Key, T>* result = MapFieldLiteType::MutableInternalMap();
+ SetMapDirty();
+ return result;
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::MergeFrom(
+ const MapFieldLiteType& other) {
+ const MapField& down_other = down_cast<const MapField&>(other);
+ SyncMapWithRepeatedField();
+ down_other.SyncMapWithRepeatedField();
+ MapFieldLiteType::MergeFrom(other);
+ SetMapDirty();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::Swap(
+ MapFieldLiteType* other) {
+ MapField* down_other = down_cast<MapField*>(other);
+ std::swap(repeated_field_, down_other->repeated_field_);
+ MapFieldLiteType::Swap(other);
+ std::swap(state_, down_other->state_);
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::SetEntryDescriptor(
+ const Descriptor** descriptor) {
+ entry_descriptor_ = descriptor;
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::SetAssignDescriptorCallback(void (*callback)()) {
+ assign_descriptor_callback_ = callback;
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+const Map<Key, T>&
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::GetInternalMap() const {
+ return MapFieldLiteType::GetInternalMap();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+Map<Key, T>*
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::MutableInternalMap() {
+ return MapFieldLiteType::MutableInternalMap();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::SyncRepeatedFieldWithMapNoLock() const {
+ if (repeated_field_ == NULL) {
+ if (arena_ == NULL) {
+ repeated_field_ = new RepeatedPtrField<Message>();
+ } else {
+ repeated_field_ =
+ Arena::Create<RepeatedPtrField<Message> >(arena_, arena_);
+ }
+ }
+ const Map<Key, T>& map = GetInternalMap();
+ RepeatedPtrField<EntryType>* repeated_field =
+ reinterpret_cast<RepeatedPtrField<EntryType>*>(repeated_field_);
+
+ repeated_field->Clear();
+
+ for (typename Map<Key, T>::const_iterator it = map.begin();
+ it != map.end(); ++it) {
+ InitDefaultEntryOnce();
+ GOOGLE_CHECK(default_entry_ != NULL);
+ EntryType* new_entry = down_cast<EntryType*>(default_entry_->New(arena_));
+ repeated_field->AddAllocated(new_entry);
+ (*new_entry->mutable_key()) = it->first;
+ (*new_entry->mutable_value()) = it->second;
+ }
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::SyncMapWithRepeatedFieldNoLock() const {
+ Map<Key, T>* map = const_cast<MapField*>(this)->MutableInternalMap();
+ RepeatedPtrField<EntryType>* repeated_field =
+ reinterpret_cast<RepeatedPtrField<EntryType>*>(repeated_field_);
+ map->clear();
+ for (typename RepeatedPtrField<EntryType>::iterator it =
+ repeated_field->begin(); it != repeated_field->end(); ++it) {
+ // Cast is needed because Map's api and internal storage is different when
+ // value is enum. For enum, we cannot cast an int to enum. Thus, we have to
+ // copy value. For other types, they have same exposed api type and internal
+ // stored type. We should not introduce value copy for them. We achieve this
+ // by casting to value for enum while casting to reference for other types.
+ (*map)[it->key()] = static_cast<CastValueType>(it->value());
+ }
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+int
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::SpaceUsedExcludingSelfNoLock() const {
+ int size = 0;
+ if (repeated_field_ != NULL) {
+ size += repeated_field_->SpaceUsedExcludingSelf();
+ }
+ Map<Key, T>* map = const_cast<MapField*>(this)->MutableInternalMap();
+ size += sizeof(*map);
+ for (typename Map<Key, T>::iterator it = map->begin();
+ it != map->end(); ++it) {
+ size += KeyHandler::SpaceUsedInMap(it->first);
+ size += ValHandler::SpaceUsedInMap(it->second);
+ }
+ return size;
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType kKeyFieldType,
+ WireFormatLite::FieldType kValueFieldType,
+ int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+ default_enum_value>::InitDefaultEntryOnce()
+ const {
+ if (default_entry_ == NULL) {
+ InitMetadataOnce();
+ GOOGLE_CHECK(*entry_descriptor_ != NULL);
+ default_entry_ = down_cast<const EntryType*>(
+ MessageFactory::generated_factory()->GetPrototype(*entry_descriptor_));
+ }
+}
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
new file mode 100644
index 00000000..549ecc08
--- /dev/null
+++ b/src/google/protobuf/map_field_lite.h
@@ -0,0 +1,278 @@
+// 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_MAP_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
+
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_entry_lite.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This class provides accesss to map field using generated api. It is used for
+// internal generated message implentation only. Users should never use this
+// directly.
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value = 0>
+class LIBPROTOBUF_EXPORT MapFieldLite {
+ // Define message type for internal repeated field.
+ typedef MapEntryLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value> EntryType;
+
+ public:
+ MapFieldLite();
+ explicit MapFieldLite(Arena* arena);
+ virtual ~MapFieldLite();
+
+ // Accessors
+ virtual const Map<Key, T>& GetMap() const;
+ virtual Map<Key, T>* MutableMap();
+
+ // Convenient methods for generated message implementation.
+ virtual int size() const;
+ virtual void Clear();
+ virtual void MergeFrom(const MapFieldLite& other);
+ virtual void Swap(MapFieldLite* other);
+
+ // Set default enum value only for proto2 map field whose value is enum type.
+ void SetDefaultEnumValue();
+
+ // Used in the implementation of parsing. Caller should take the ownership.
+ EntryType* NewEntry() const;
+ // Used in the implementation of serializing enum value type. Caller should
+ // take the ownership.
+ EntryType* NewEnumEntryWrapper(const Key& key, const T t) const;
+ // Used in the implementation of serializing other value types. Caller should
+ // take the ownership.
+ EntryType* NewEntryWrapper(const Key& key, const T& t) const;
+
+ protected:
+ // Convenient methods to get internal google::protobuf::Map
+ virtual const Map<Key, T>& GetInternalMap() const;
+ virtual Map<Key, T>* MutableInternalMap();
+
+ private:
+ typedef void DestructorSkippable_;
+
+ Arena* arena_;
+ Map<Key, T>* map_;
+
+ friend class ::google::protobuf::Arena;
+};
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::MapFieldLite()
+ : arena_(NULL) {
+ map_ = new Map<Key, T>;
+ SetDefaultEnumValue();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::MapFieldLite(Arena* arena)
+ : arena_(arena) {
+ map_ = Arena::Create<Map<Key, T> >(arena, arena);
+ SetDefaultEnumValue();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::~MapFieldLite() {
+ delete map_;
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+const Map<Key, T>&
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::GetMap() const {
+ return *map_;
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+Map<Key, T>*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::MutableMap() {
+ return map_;
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+int
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::size() const {
+ return map_->size();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+void
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::Clear() {
+ map_->clear();
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+void
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::MergeFrom(
+ const MapFieldLite& other) {
+ for (typename Map<Key, T>::const_iterator it = other.map_->begin();
+ it != other.map_->end(); ++it) {
+ (*map_)[it->first] = it->second;
+ }
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+void
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::Swap(
+ MapFieldLite* other) {
+ std::swap(map_, other->map_);
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+void
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::SetDefaultEnumValue() {
+ MutableInternalMap()->SetDefaultEnumValue(default_enum_value);
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+const Map<Key, T>&
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::GetInternalMap() const {
+ return *map_;
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+Map<Key, T>*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::MutableInternalMap() {
+ return map_;
+}
+
+#define EntryType \
+ MapEntryLite<Key, T, key_wire_type, value_wire_type, default_enum_value>
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+EntryType*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::NewEntry() const {
+ if (arena_ == NULL) {
+ return new EntryType();
+ } else {
+ return Arena::CreateMessage<EntryType>(arena_);
+ }
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+EntryType*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::NewEnumEntryWrapper(const Key& key,
+ const T t) const {
+ return EntryType::EnumWrap(key, t, arena_);
+}
+
+template <typename Key, typename T,
+ WireFormatLite::FieldType key_wire_type,
+ WireFormatLite::FieldType value_wire_type,
+ int default_enum_value>
+EntryType*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+ default_enum_value>::NewEntryWrapper(const Key& key,
+ const T& t) const {
+ return EntryType::Wrap(key, t, arena_);
+}
+
+#undef EntryType
+
+// True if IsInitialized() is true for value field in all elements of t. T is
+// expected to be message. It's useful to have this helper here to keep the
+// protobuf compiler from ever having to emit loops in IsInitialized() methods.
+// We want the C++ compiler to inline this or not as it sees fit.
+template <typename Key, typename T>
+bool AllAreInitialized(const Map<Key, T>& t) {
+ for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end();
+ ++it) {
+ if (!it->second.IsInitialized()) return false;
+ }
+ return true;
+}
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
new file mode 100644
index 00000000..61344cbb
--- /dev/null
+++ b/src/google/protobuf/map_field_test.cc
@@ -0,0 +1,466 @@
+// 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 <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/map_test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+using unittest::TestAllTypes;
+
+class MapFieldBaseStub : public MapFieldBase {
+ public:
+ typedef void DestructorSkippable_;
+ MapFieldBaseStub() {}
+ explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {}
+ void SyncRepeatedFieldWithMap() const {
+ MapFieldBase::SyncRepeatedFieldWithMap();
+ }
+ void SyncMapWithRepeatedField() const {
+ MapFieldBase::SyncMapWithRepeatedField();
+ }
+ // Get underlined repeated field without synchronizing map.
+ RepeatedPtrField<Message>* InternalRepeatedField() {
+ return repeated_field_;
+ }
+ bool IsMapClean() { return state_ != 0; }
+ bool IsRepeatedClean() { return state_ != 1; }
+ void SetMapDirty() { state_ = 0; }
+ void SetRepeatedDirty() { state_ = 1; }
+};
+
+class MapFieldBasePrimitiveTest : public ::testing::Test {
+ protected:
+ typedef MapField<int32, int32, WireFormatLite::TYPE_INT32,
+ WireFormatLite::TYPE_INT32, false> MapFieldType;
+
+ MapFieldBasePrimitiveTest() {
+ // Get descriptors
+ map_descriptor_ = unittest::TestMap::descriptor()
+ ->FindFieldByName("map_int32_int32")
+ ->message_type();
+ key_descriptor_ = map_descriptor_->FindFieldByName("key");
+ value_descriptor_ = map_descriptor_->FindFieldByName("value");
+
+ // Build map field
+ default_entry_ =
+ MessageFactory::generated_factory()->GetPrototype(map_descriptor_);
+ map_field_.reset(new MapFieldType(default_entry_));
+ map_field_base_ = map_field_.get();
+ map_ = map_field_->MutableMap();
+ initial_value_map_[0] = 100;
+ initial_value_map_[1] = 101;
+ map_->insert(initial_value_map_.begin(), initial_value_map_.end());
+ EXPECT_EQ(2, map_->size());
+ }
+
+ google::protobuf::scoped_ptr<MapFieldType> map_field_;
+ MapFieldBase* map_field_base_;
+ Map<int32, int32>* map_;
+ const Descriptor* map_descriptor_;
+ const FieldDescriptor* key_descriptor_;
+ const FieldDescriptor* value_descriptor_;
+ const Message* default_entry_;
+ std::map<int32, int32> initial_value_map_; // copy of initial values inserted
+};
+
+TEST_F(MapFieldBasePrimitiveTest, SpaceUsedExcludingSelf) {
+ EXPECT_LT(0, map_field_base_->SpaceUsedExcludingSelf());
+}
+
+TEST_F(MapFieldBasePrimitiveTest, GetRepeatedField) {
+ const RepeatedPtrField<Message>& repeated =
+ reinterpret_cast<const RepeatedPtrField<Message>&>(
+ map_field_base_->GetRepeatedField());
+ EXPECT_EQ(2, repeated.size());
+ for (int i = 0; i < repeated.size(); i++) {
+ const Message& message = repeated.Get(i);
+ int key = message.GetReflection()->GetInt32(message, key_descriptor_);
+ int value = message.GetReflection()->GetInt32(message, value_descriptor_);
+ EXPECT_EQ(value, initial_value_map_[key]);
+ }
+}
+
+TEST_F(MapFieldBasePrimitiveTest, MutableRepeatedField) {
+ RepeatedPtrField<Message>* repeated =
+ reinterpret_cast<RepeatedPtrField<Message>*>(
+ map_field_base_->MutableRepeatedField());
+ EXPECT_EQ(2, repeated->size());
+ for (int i = 0; i < repeated->size(); i++) {
+ const Message& message = repeated->Get(i);
+ int key = message.GetReflection()->GetInt32(message, key_descriptor_);
+ int value = message.GetReflection()->GetInt32(message, value_descriptor_);
+ EXPECT_EQ(value, initial_value_map_[key]);
+ }
+}
+
+TEST_F(MapFieldBasePrimitiveTest, Arena) {
+ // Allocate a large initial block to avoid mallocs during hooked test.
+ std::vector<char> arena_block(128 * 1024);
+ ArenaOptions options;
+ options.initial_block = arena_block.data();
+ options.initial_block_size = arena_block.size();
+ Arena arena(options);
+
+ {
+ NoHeapChecker no_heap;
+
+ MapFieldType* map_field =
+ Arena::Create<MapFieldType>(&arena, &arena, default_entry_);
+
+ // Set content in map
+ (*map_field->MutableMap())[100] = 101;
+
+ // Trigger conversion to repeated field.
+ map_field->GetRepeatedField();
+ }
+
+ {
+ NoHeapChecker no_heap;
+
+ MapFieldBaseStub* map_field =
+ Arena::Create<MapFieldBaseStub>(&arena, &arena);
+
+ // Trigger conversion to repeated field.
+ EXPECT_TRUE(map_field->MutableRepeatedField() != NULL);
+ }
+}
+
+namespace {
+enum State { CLEAN, MAP_DIRTY, REPEATED_DIRTY };
+} // anonymous namespace
+
+class MapFieldStateTest
+ : public testing::TestWithParam<State> {
+ public:
+ protected:
+ typedef MapField<int32, int32, WireFormatLite::TYPE_INT32,
+ WireFormatLite::TYPE_INT32, false> MapFieldType;
+ typedef MapFieldLite<int32, int32, WireFormatLite::TYPE_INT32,
+ WireFormatLite::TYPE_INT32, false> MapFieldLiteType;
+ MapFieldStateTest() : state_(GetParam()) {
+ // Build map field
+ const Descriptor* map_descriptor =
+ unittest::TestMap::descriptor()
+ ->FindFieldByName("map_int32_int32")
+ ->message_type();
+ default_entry_ =
+ MessageFactory::generated_factory()->GetPrototype(map_descriptor);
+ map_field_.reset(new MapFieldType(default_entry_));
+ map_field_base_ = map_field_.get();
+
+ Expect(map_field_.get(), MAP_DIRTY, 0, 0, true);
+ switch (state_) {
+ case CLEAN:
+ AddOneStillClean(map_field_.get());
+ break;
+ case MAP_DIRTY:
+ MakeMapDirty(map_field_.get());
+ break;
+ case REPEATED_DIRTY:
+ MakeRepeatedDirty(map_field_.get());
+ break;
+ default:
+ break;
+ }
+ }
+
+ void AddOneStillClean(MapFieldType* map_field) {
+ MapFieldBase* map_field_base = map_field;
+ Map<int32, int32>* map = map_field->MutableMap();
+ (*map)[0] = 0;
+ map_field_base->GetRepeatedField();
+ Expect(map_field, CLEAN, 1, 1, false);
+ }
+
+ void MakeMapDirty(MapFieldType* map_field) {
+ Map<int32, int32>* map = map_field->MutableMap();
+ (*map)[0] = 0;
+ Expect(map_field, MAP_DIRTY, 1, 0, true);
+ }
+
+ void MakeRepeatedDirty(MapFieldType* map_field) {
+ MakeMapDirty(map_field);
+ MapFieldBase* map_field_base = map_field;
+ map_field_base->MutableRepeatedField();
+ Map<int32, int32>* map = implicit_cast<MapFieldLiteType*>(map_field)
+ ->MapFieldLiteType::MutableMap();
+ map->clear();
+
+ Expect(map_field, REPEATED_DIRTY, 0, 1, false);
+ }
+
+ void Expect(MapFieldType* map_field, State state, int map_size,
+ int repeated_size, bool is_repeated_null) {
+ MapFieldBase* map_field_base = map_field;
+ MapFieldBaseStub* stub =
+ reinterpret_cast<MapFieldBaseStub*>(map_field_base);
+
+ Map<int32, int32>* map = implicit_cast<MapFieldLiteType*>(map_field)
+ ->MapFieldLiteType::MutableMap();
+ RepeatedPtrField<Message>* repeated_field = stub->InternalRepeatedField();
+
+ switch (state) {
+ case MAP_DIRTY:
+ EXPECT_FALSE(stub->IsMapClean());
+ EXPECT_TRUE(stub->IsRepeatedClean());
+ break;
+ case REPEATED_DIRTY:
+ EXPECT_TRUE(stub->IsMapClean());
+ EXPECT_FALSE(stub->IsRepeatedClean());
+ break;
+ case CLEAN:
+ EXPECT_TRUE(stub->IsMapClean());
+ EXPECT_TRUE(stub->IsRepeatedClean());
+ break;
+ default:
+ FAIL();
+ }
+
+ EXPECT_EQ(map_size, map->size());
+ if (is_repeated_null) {
+ EXPECT_TRUE(repeated_field == NULL);
+ } else {
+ EXPECT_EQ(repeated_size, repeated_field->size());
+ }
+ }
+
+ google::protobuf::scoped_ptr<MapFieldType> map_field_;
+ MapFieldBase* map_field_base_;
+ State state_;
+ const Message* default_entry_;
+};
+
+INSTANTIATE_TEST_CASE_P(MapFieldStateTestInstance, MapFieldStateTest,
+ ::testing::Values(CLEAN, MAP_DIRTY, REPEATED_DIRTY));
+
+TEST_P(MapFieldStateTest, GetMap) {
+ map_field_->GetMap();
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), CLEAN, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+}
+
+TEST_P(MapFieldStateTest, MutableMap) {
+ map_field_->MutableMap();
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+}
+
+TEST_P(MapFieldStateTest, MergeFromClean) {
+ MapFieldType other(default_entry_);
+ AddOneStillClean(&other);
+
+ map_field_->MergeFrom(other);
+
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+
+ Expect(&other, CLEAN, 1, 1, false);
+}
+
+TEST_P(MapFieldStateTest, MergeFromMapDirty) {
+ MapFieldType other(default_entry_);
+ MakeMapDirty(&other);
+
+ map_field_->MergeFrom(other);
+
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+
+ Expect(&other, MAP_DIRTY, 1, 0, true);
+}
+
+TEST_P(MapFieldStateTest, MergeFromRepeatedDirty) {
+ MapFieldType other(default_entry_);
+ MakeRepeatedDirty(&other);
+
+ map_field_->MergeFrom(other);
+
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+
+ Expect(&other, CLEAN, 1, 1, false);
+}
+
+TEST_P(MapFieldStateTest, SwapClean) {
+ MapFieldType other(default_entry_);
+ AddOneStillClean(&other);
+
+ map_field_->Swap(&other);
+
+ Expect(map_field_.get(), CLEAN, 1, 1, false);
+
+ switch (state_) {
+ case CLEAN:
+ Expect(&other, CLEAN, 1, 1, false);
+ break;
+ case MAP_DIRTY:
+ Expect(&other, MAP_DIRTY, 1, 0, true);
+ break;
+ case REPEATED_DIRTY:
+ Expect(&other, REPEATED_DIRTY, 0, 1, false);
+ break;
+ default:
+ break;
+ }
+}
+
+TEST_P(MapFieldStateTest, SwapMapDirty) {
+ MapFieldType other(default_entry_);
+ MakeMapDirty(&other);
+
+ map_field_->Swap(&other);
+
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+
+ switch (state_) {
+ case CLEAN:
+ Expect(&other, CLEAN, 1, 1, false);
+ break;
+ case MAP_DIRTY:
+ Expect(&other, MAP_DIRTY, 1, 0, true);
+ break;
+ case REPEATED_DIRTY:
+ Expect(&other, REPEATED_DIRTY, 0, 1, false);
+ break;
+ default:
+ break;
+ }
+}
+
+TEST_P(MapFieldStateTest, SwapRepeatedDirty) {
+ MapFieldType other(default_entry_);
+ MakeRepeatedDirty(&other);
+
+ map_field_->Swap(&other);
+
+ Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+
+ switch (state_) {
+ case CLEAN:
+ Expect(&other, CLEAN, 1, 1, false);
+ break;
+ case MAP_DIRTY:
+ Expect(&other, MAP_DIRTY, 1, 0, true);
+ break;
+ case REPEATED_DIRTY:
+ Expect(&other, REPEATED_DIRTY, 0, 1, false);
+ break;
+ default:
+ break;
+ }
+}
+
+TEST_P(MapFieldStateTest, Clear) {
+ map_field_->Clear();
+
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), MAP_DIRTY, 0, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 0, 0, true);
+ }
+}
+
+TEST_P(MapFieldStateTest, SpaceUsedExcludingSelf) {
+ map_field_base_->SpaceUsedExcludingSelf();
+
+ switch (state_) {
+ case CLEAN:
+ Expect(map_field_.get(), CLEAN, 1, 1, false);
+ break;
+ case MAP_DIRTY:
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ break;
+ case REPEATED_DIRTY:
+ Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+ break;
+ default:
+ break;
+ }
+}
+
+TEST_P(MapFieldStateTest, GetMapField) {
+ map_field_base_->GetRepeatedField();
+
+ if (state_ != REPEATED_DIRTY) {
+ Expect(map_field_.get(), CLEAN, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+ }
+}
+
+TEST_P(MapFieldStateTest, MutableMapField) {
+ map_field_base_->MutableRepeatedField();
+
+ if (state_ != REPEATED_DIRTY) {
+ Expect(map_field_.get(), REPEATED_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+ }
+}
+
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/map_lite_test_util.cc b/src/google/protobuf/map_lite_test_util.cc
new file mode 100644
index 00000000..b65b4d63
--- /dev/null
+++ b/src/google/protobuf/map_lite_test_util.cc
@@ -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.
+
+#include <google/protobuf/map_lite_test_util.h>
+#include <google/protobuf/map_lite_unittest.pb.h>
+#include <google/protobuf/map_test_util_impl.h>
+
+namespace google {
+namespace protobuf {
+
+void MapLiteTestUtil::SetMapFields(unittest::TestMapLite* message) {
+ MapTestUtilImpl::SetMapFields<unittest::MapEnumLite,
+ unittest::MAP_ENUM_BAR_LITE,
+ unittest::MAP_ENUM_BAZ_LITE>(message);
+}
+
+void MapLiteTestUtil::SetArenaMapFields(unittest::TestArenaMapLite* message) {
+ MapTestUtilImpl::SetArenaMapFields<unittest::MapEnumLite,
+ unittest::MAP_ENUM_BAR_LITE,
+ unittest::MAP_ENUM_BAZ_LITE>(message);
+}
+
+void MapLiteTestUtil::SetMapFieldsInitialized(unittest::TestMapLite* message) {
+ MapTestUtilImpl::SetMapFieldsInitialized(message);
+}
+
+void MapLiteTestUtil::ModifyMapFields(unittest::TestMapLite* message) {
+ MapTestUtilImpl::ModifyMapFields<unittest::MapEnumLite,
+ unittest::MAP_ENUM_FOO_LITE>(message);
+}
+
+void MapLiteTestUtil::ExpectClear(const unittest::TestMapLite& message) {
+ MapTestUtilImpl::ExpectClear(message);
+}
+
+void MapLiteTestUtil::ExpectMapFieldsSet(const unittest::TestMapLite& message) {
+ MapTestUtilImpl::ExpectMapFieldsSet<unittest::MapEnumLite,
+ unittest::MAP_ENUM_BAR_LITE,
+ unittest::MAP_ENUM_BAZ_LITE>(message);
+}
+
+void MapLiteTestUtil::ExpectArenaMapFieldsSet(
+ const unittest::TestArenaMapLite& message) {
+ MapTestUtilImpl::ExpectArenaMapFieldsSet<unittest::MapEnumLite,
+ unittest::MAP_ENUM_BAR_LITE,
+ unittest::MAP_ENUM_BAZ_LITE>(
+ message);
+}
+
+void MapLiteTestUtil::ExpectMapFieldsSetInitialized(
+ const unittest::TestMapLite& message) {
+ MapTestUtilImpl::ExpectMapFieldsSetInitialized<unittest::MapEnumLite,
+ unittest::MAP_ENUM_FOO_LITE>(
+ message);
+}
+
+void MapLiteTestUtil::ExpectMapFieldsModified(
+ const unittest::TestMapLite& message) {
+ MapTestUtilImpl::ExpectMapFieldsModified<unittest::MapEnumLite,
+ unittest::MAP_ENUM_BAR_LITE,
+ unittest::MAP_ENUM_FOO_LITE>(
+ message);
+}
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/map_lite_test_util.h b/src/google/protobuf/map_lite_test_util.h
new file mode 100644
index 00000000..77b5336f
--- /dev/null
+++ b/src/google/protobuf/map_lite_test_util.h
@@ -0,0 +1,80 @@
+// 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_MAP_LITE_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_MAP_LITE_TEST_UTIL_H__
+
+#include <google/protobuf/map_lite_unittest.pb.h>
+
+namespace google {
+namespace protobuf {
+
+class MapLiteTestUtil {
+ public:
+ // Set every field in the TestMapLite message to a unique value.
+ static void SetMapFields(protobuf_unittest::TestMapLite* message);
+
+ // Set every field in the TestArenaMapLite message to a unique value.
+ static void SetArenaMapFields(protobuf_unittest::TestArenaMapLite* message);
+
+ // Set every field in the message to a default value.
+ static void SetMapFieldsInitialized(protobuf_unittest::TestMapLite* message);
+
+ // Modify all the map fields of the messsage (which should already have been
+ // initialized with SetMapFields()).
+ static void ModifyMapFields(protobuf_unittest::TestMapLite* message);
+
+ // Check that all fields have the values that they should have after
+ // SetMapFields() is called.
+ static void ExpectMapFieldsSet(const protobuf_unittest::TestMapLite& message);
+
+ // Check that all fields have the values that they should have after
+ // SetMapFields() is called for TestArenaMapLite.
+ static void ExpectArenaMapFieldsSet(
+ const protobuf_unittest::TestArenaMapLite& message);
+
+ // Check that all fields have the values that they should have after
+ // SetMapFieldsInitialized() is called.
+ static void ExpectMapFieldsSetInitialized(
+ const protobuf_unittest::TestMapLite& message);
+
+ // Expect that the message is modified as would be expected from
+ // ModifyMapFields().
+ static void ExpectMapFieldsModified(
+ const protobuf_unittest::TestMapLite& message);
+
+ // Check that all fields are empty.
+ static void ExpectClear(const protobuf_unittest::TestMapLite& message);
+};
+
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MAP_LITE_TEST_UTIL_H__
diff --git a/src/google/protobuf/map_lite_unittest.proto b/src/google/protobuf/map_lite_unittest.proto
new file mode 100644
index 00000000..c69e8d94
--- /dev/null
+++ b/src/google/protobuf/map_lite_unittest.proto
@@ -0,0 +1,133 @@
+// 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 cc_enable_arenas = true;
+option optimize_for = LITE_RUNTIME;
+
+import "google/protobuf/unittest_lite.proto";
+
+package protobuf_unittest;
+
+message TestMapLite {
+ map<int32 , int32 > map_int32_int32 = 1;
+ map<int64 , int64 > map_int64_int64 = 2;
+ map<uint32 , uint32 > map_uint32_uint32 = 3;
+ map<uint64 , uint64 > map_uint64_uint64 = 4;
+ map<sint32 , sint32 > map_sint32_sint32 = 5;
+ map<sint64 , sint64 > map_sint64_sint64 = 6;
+ map<fixed32 , fixed32 > map_fixed32_fixed32 = 7;
+ map<fixed64 , fixed64 > map_fixed64_fixed64 = 8;
+ map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+ map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+ map<int32 , float > map_int32_float = 11;
+ map<int32 , double > map_int32_double = 12;
+ map<bool , bool > map_bool_bool = 13;
+ map<string , string > map_string_string = 14;
+ map<int32 , bytes > map_int32_bytes = 15;
+ map<int32 , MapEnumLite> map_int32_enum = 16;
+ map<int32 , ForeignMessageLite> map_int32_foreign_message = 17;
+ map<int32, int32> teboring = 18;
+}
+
+message TestArenaMapLite {
+ map<int32 , int32 > map_int32_int32 = 1;
+ map<int64 , int64 > map_int64_int64 = 2;
+ map<uint32 , uint32 > map_uint32_uint32 = 3;
+ map<uint64 , uint64 > map_uint64_uint64 = 4;
+ map<sint32 , sint32 > map_sint32_sint32 = 5;
+ map<sint64 , sint64 > map_sint64_sint64 = 6;
+ map<fixed32 , fixed32 > map_fixed32_fixed32 = 7;
+ map<fixed64 , fixed64 > map_fixed64_fixed64 = 8;
+ map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+ map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+ map<int32 , float > map_int32_float = 11;
+ map<int32 , double > map_int32_double = 12;
+ map<bool , bool > map_bool_bool = 13;
+ map<int32 , MapEnumLite> map_int32_enum = 14;
+ map<int32 , ForeignMessageArenaLite> map_int32_foreign_message = 15;
+}
+
+// Test embeded message with required fields
+message TestRequiredMessageMapLite {
+ map<int32, TestRequiredLite> map_field = 1;
+}
+
+message TestEnumStartWithNonZeroMapLite {
+ map<int32, Proto2MapEnumStartWithNonZeroLite> map_field = 101;
+}
+
+message TestEnumMapLite {
+ map<int32, Proto2MapEnumLite> known_map_field = 101;
+ map<int32, Proto2MapEnumLite> unknown_map_field = 102;
+}
+
+message TestEnumMapPlusExtraLite {
+ map<int32, Proto2MapEnumPlusExtraLite> known_map_field = 101;
+ map<int32, Proto2MapEnumPlusExtraLite> unknown_map_field = 102;
+}
+
+message TestMessageMapLite {
+ map<int32, TestAllTypesLite> map_int32_message = 1;
+}
+
+enum Proto2MapEnumLite {
+ PROTO2_MAP_ENUM_FOO_LITE = 0;
+ PROTO2_MAP_ENUM_BAR_LITE = 1;
+ PROTO2_MAP_ENUM_BAZ_LITE = 2;
+}
+
+enum Proto2MapEnumPlusExtraLite {
+ E_PROTO2_MAP_ENUM_FOO_LITE = 0;
+ E_PROTO2_MAP_ENUM_BAR_LITE = 1;
+ E_PROTO2_MAP_ENUM_BAZ_LITE = 2;
+ E_PROTO2_MAP_ENUM_EXTRA_LITE = 3;
+}
+
+enum Proto2MapEnumStartWithNonZeroLite {
+ PROTO2_NON_ZERO_MAP_ENUM_FOO_LITE = 1;
+}
+
+enum MapEnumLite {
+ MAP_ENUM_FOO_LITE = 0;
+ MAP_ENUM_BAR_LITE = 1;
+ MAP_ENUM_BAZ_LITE = 2;
+}
+
+message TestRequiredLite {
+ required int32 a = 1;
+ required int32 b = 2;
+ required int32 c = 3;
+}
+
+message ForeignMessageArenaLite {
+ optional int32 c = 1;
+}
diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto
new file mode 100644
index 00000000..3d4af28e
--- /dev/null
+++ b/src/google/protobuf/map_proto2_unittest.proto
@@ -0,0 +1,68 @@
+// 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";
+
+
+// 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 map_test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+enum Proto2MapEnum {
+ PROTO2_MAP_ENUM_FOO = 0;
+ PROTO2_MAP_ENUM_BAR = 1;
+ PROTO2_MAP_ENUM_BAZ = 2;
+}
+
+enum Proto2MapEnumPlusExtra {
+ E_PROTO2_MAP_ENUM_FOO = 0;
+ E_PROTO2_MAP_ENUM_BAR = 1;
+ E_PROTO2_MAP_ENUM_BAZ = 2;
+ E_PROTO2_MAP_ENUM_EXTRA = 3;
+}
+
+enum Proto2MapEnumStartWithNonZero {
+ PROTO2_NON_ZERO_MAP_ENUM_FOO = 1;
+}
+
+message TestEnumMap {
+ map<int32, Proto2MapEnum> known_map_field = 101;
+ map<int32, Proto2MapEnum> unknown_map_field = 102;
+}
+
+message TestEnumMapPlusExtra {
+ map<int32, Proto2MapEnumPlusExtra> known_map_field = 101;
+ map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102;
+}
+
+message TestEnumStartWithNonZeroMap {
+ map<int32, Proto2MapEnumStartWithNonZero> map_field = 101;
+}
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
new file mode 100644
index 00000000..88cba1f2
--- /dev/null
+++ b/src/google/protobuf/map_test.cc
@@ -0,0 +1,2310 @@
+// 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 <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <sstream>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/map_proto2_unittest.pb.h>
+#include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/map_test_util.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+
+using google::protobuf::unittest::ForeignMessage;
+using google::protobuf::unittest::TestAllTypes;
+using google::protobuf::unittest::TestMap;
+
+namespace protobuf {
+namespace internal {
+
+// Map API Test =====================================================
+
+class MapImplTest : public ::testing::Test {
+ protected:
+ MapImplTest()
+ : map_ptr_(new Map<int32, int32>),
+ map_(*map_ptr_),
+ const_map_(*map_ptr_) {
+ EXPECT_TRUE(map_.empty());
+ EXPECT_EQ(0, map_.size());
+ }
+ ~MapImplTest() {}
+
+ void ExpectSingleElement(int32 key, int32 value) {
+ EXPECT_FALSE(map_.empty());
+ EXPECT_EQ(1, map_.size());
+ ExpectElement(key, value);
+ }
+
+ void ExpectElements(const std::map<int32, int32>& map) {
+ EXPECT_FALSE(map_.empty());
+ EXPECT_EQ(map.size(), map_.size());
+ for (std::map<int32, int32>::const_iterator it = map.begin();
+ it != map.end(); ++it) {
+ ExpectElement(it->first, it->second);
+ }
+ }
+
+ void ExpectElement(int32 key, int32 value) {
+ // Test map size is correct.
+ EXPECT_EQ(value, map_[key]);
+ EXPECT_EQ(1, map_.count(key));
+
+ // Check mutable at and find work correctly.
+ EXPECT_EQ(value, map_.at(key));
+ Map<int32, int32>::iterator it = map_.find(key);
+
+ // interator dereferenceable
+ EXPECT_EQ(key, (*it).first);
+ EXPECT_EQ(value, (*it).second);
+ EXPECT_EQ(key, it->first);
+ EXPECT_EQ(value, it->second);
+
+ // iterator mutable
+ ((*it).second) = value + 1;
+ EXPECT_EQ(value + 1, map_[key]);
+ ((*it).second) = value;
+ EXPECT_EQ(value, map_[key]);
+
+ it->second = value + 1;
+ EXPECT_EQ(value + 1, map_[key]);
+ it->second = value;
+ EXPECT_EQ(value, map_[key]);
+
+ // copy constructor
+ Map<int32, int32>::iterator it_copy = it;
+ EXPECT_EQ(key, it_copy->first);
+ EXPECT_EQ(value, it_copy->second);
+
+ // Immutable API ================================================
+
+ // Check immutable at and find work correctly.
+ EXPECT_EQ(value, const_map_.at(key));
+ Map<int32, int32>::const_iterator const_it = const_map_.find(key);
+
+ // interator dereferenceable
+ EXPECT_EQ(key, (*const_it).first);
+ EXPECT_EQ(value, (*const_it).second);
+ EXPECT_EQ(key, const_it->first);
+ EXPECT_EQ(value, const_it->second);
+
+ // copy constructor
+ Map<int32, int32>::const_iterator const_it_copy = const_it;
+ EXPECT_EQ(key, const_it_copy->first);
+ EXPECT_EQ(value, const_it_copy->second);
+ }
+
+ google::protobuf::scoped_ptr<Map<int32, int32> > map_ptr_;
+ Map<int32, int32>& map_;
+ const Map<int32, int32>& const_map_;
+};
+
+TEST_F(MapImplTest, OperatorBracket) {
+ int32 key = 0;
+ int32 value1 = 100;
+ int32 value2 = 101;
+
+ EXPECT_EQ(0, map_[key]);
+
+ map_[key] = value1;
+ ExpectSingleElement(key, value1);
+
+ map_[key] = value2;
+ ExpectSingleElement(key, value2);
+}
+
+TEST_F(MapImplTest, OperatorBracketNonExist) {
+ int32 key = 0;
+ int32 default_value = 0;
+
+ EXPECT_EQ(default_value, map_[key]);
+ ExpectSingleElement(key, default_value);
+}
+
+TEST_F(MapImplTest, MutableAt) {
+ int32 key = 0;
+ int32 value1 = 100;
+ int32 value2 = 101;
+
+ map_[key] = value1;
+ ExpectSingleElement(key, value1);
+
+ map_.at(key) = value2;
+ ExpectSingleElement(key, value2);
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+TEST_F(MapImplTest, MutableAtNonExistDeathTest) {
+ EXPECT_DEATH(map_.at(0), "");
+}
+
+TEST_F(MapImplTest, ImmutableAtNonExistDeathTest) {
+ EXPECT_DEATH(const_map_.at(0), "");
+}
+
+#endif // PROTOBUF_HAS_DEATH_TEST
+
+TEST_F(MapImplTest, CountNonExist) {
+ EXPECT_EQ(0, map_.count(0));
+}
+
+TEST_F(MapImplTest, MutableFindNonExist) {
+ EXPECT_TRUE(map_.end() == map_.find(0));
+}
+
+TEST_F(MapImplTest, ImmutableFindNonExist) {
+ EXPECT_TRUE(const_map_.end() == const_map_.find(0));
+}
+
+TEST_F(MapImplTest, ConstEnd) {
+ EXPECT_TRUE(const_map_.end() == const_map_.cend());
+}
+
+TEST_F(MapImplTest, GetReferenceFromIterator) {
+ for (int i = 0; i < 10; i++) {
+ map_[i] = i;
+ }
+
+ for (Map<int32, int32>::const_iterator it = map_.cbegin();
+ it != map_.cend();) {
+ Map<int32, int32>::const_reference entry = *it++;
+ EXPECT_EQ(entry.first, entry.second);
+ }
+
+ for (Map<int32, int32>::const_iterator it = const_map_.begin();
+ it != const_map_.end();) {
+ Map<int32, int32>::const_reference entry = *it++;
+ EXPECT_EQ(entry.first, entry.second);
+ }
+
+ for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
+ Map<int32, int32>::reference entry = *it++;
+ EXPECT_EQ(entry.first + 1, ++entry.second);
+ }
+}
+
+TEST_F(MapImplTest, IteratorBasic) {
+ map_[0] = 0;
+
+ // Default constructible (per forward iterator requirements).
+ Map<int, int>::const_iterator cit;
+ Map<int, int>::iterator it;
+
+ it = map_.begin();
+ cit = it; // Converts to const_iterator
+
+ // Can compare between them.
+ EXPECT_TRUE(it == cit);
+ EXPECT_FALSE(cit != it);
+
+ // Pre increment.
+ EXPECT_FALSE(it == ++cit);
+
+ // Post increment.
+ EXPECT_FALSE(it++ == cit);
+ EXPECT_TRUE(it == cit);
+}
+
+template <typename T>
+bool IsConstHelper(T& /*t*/) { // NOLINT. We want to catch non-const refs here.
+ return false;
+}
+template <typename T>
+bool IsConstHelper(const T& /*t*/) {
+ return true;
+}
+
+TEST_F(MapImplTest, IteratorConstness) {
+ map_[0] = 0;
+ EXPECT_TRUE(IsConstHelper(*map_.cbegin()));
+ EXPECT_TRUE(IsConstHelper(*const_map_.begin()));
+ EXPECT_FALSE(IsConstHelper(*map_.begin()));
+}
+
+bool IsForwardIteratorHelper(std::forward_iterator_tag /*tag*/) { return true; }
+template <typename T>
+bool IsForwardIteratorHelper(T /*t*/) {
+ return false;
+}
+
+TEST_F(MapImplTest, IteratorCategory) {
+ EXPECT_TRUE(IsForwardIteratorHelper(
+ std::iterator_traits<Map<int, int>::iterator>::iterator_category()));
+ EXPECT_TRUE(IsForwardIteratorHelper(std::iterator_traits<
+ Map<int, int>::const_iterator>::iterator_category()));
+}
+
+TEST_F(MapImplTest, InsertSingle) {
+ int32 key = 0;
+ int32 value1 = 100;
+ int32 value2 = 101;
+
+ // Insert a non-existed key.
+ std::pair<Map<int32, int32>::iterator, bool> result1 =
+ map_.insert(Map<int32, int32>::value_type(key, value1));
+ ExpectSingleElement(key, value1);
+
+ Map<int32, int32>::iterator it1 = result1.first;
+ EXPECT_EQ(key, it1->first);
+ EXPECT_EQ(value1, it1->second);
+ EXPECT_TRUE(result1.second);
+
+ // Insert an existed key.
+ std::pair<Map<int32, int32>::iterator, bool> result2 =
+ map_.insert(Map<int32, int32>::value_type(key, value2));
+ ExpectSingleElement(key, value1);
+
+ Map<int32, int32>::iterator it2 = result2.first;
+ EXPECT_TRUE(it1 == it2);
+ EXPECT_FALSE(result2.second);
+}
+
+TEST_F(MapImplTest, InsertByIterator) {
+ int32 key1 = 0;
+ int32 key2 = 1;
+ int32 value1a = 100;
+ int32 value1b = 101;
+ int32 value2a = 200;
+ int32 value2b = 201;
+
+ std::map<int32, int32> map1;
+ map1[key1] = value1a;
+ map1[key2] = value2a;
+
+ map_.insert(map1.begin(), map1.end());
+ ExpectElements(map1);
+
+ std::map<int32, int32> map2;
+ map2[key1] = value1b;
+ map2[key2] = value2b;
+
+ map_.insert(map2.begin(), map2.end());
+ ExpectElements(map1);
+}
+
+TEST_F(MapImplTest, EraseSingleByKey) {
+ int32 key = 0;
+ int32 value = 100;
+
+ map_[key] = value;
+ ExpectSingleElement(key, value);
+
+ // Erase an existing key.
+ EXPECT_EQ(1, map_.erase(key));
+ EXPECT_TRUE(map_.empty());
+ EXPECT_EQ(0, map_.size());
+ EXPECT_TRUE(map_.end() == map_.find(key));
+ EXPECT_TRUE(map_.begin() == map_.end());
+
+ // Erase a non-existing key.
+ EXPECT_EQ(0, map_.erase(key));
+}
+
+TEST_F(MapImplTest, EraseMutipleByKey) {
+ // erase in one specific order to trigger corner cases
+ for (int i = 0; i < 5; i++) {
+ map_[i] = i;
+ }
+
+ map_.erase(0);
+ EXPECT_EQ(4, map_.size());
+ EXPECT_TRUE(map_.end() == map_.find(0));
+
+ map_.erase(1);
+ EXPECT_EQ(3, map_.size());
+ EXPECT_TRUE(map_.end() == map_.find(1));
+
+ map_.erase(3);
+ EXPECT_EQ(2, map_.size());
+ EXPECT_TRUE(map_.end() == map_.find(3));
+
+ map_.erase(4);
+ EXPECT_EQ(1, map_.size());
+ EXPECT_TRUE(map_.end() == map_.find(4));
+
+ map_.erase(2);
+ EXPECT_EQ(0, map_.size());
+ EXPECT_TRUE(map_.end() == map_.find(2));
+}
+
+TEST_F(MapImplTest, EraseSingleByIterator) {
+ int32 key = 0;
+ int32 value = 100;
+
+ map_[key] = value;
+ ExpectSingleElement(key, value);
+
+ Map<int32, int32>::iterator it = map_.find(key);
+ map_.erase(it);
+ EXPECT_TRUE(map_.empty());
+ EXPECT_EQ(0, map_.size());
+ EXPECT_TRUE(map_.end() == map_.find(key));
+ EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+TEST_F(MapImplTest, ValidIteratorAfterErase) {
+ for (int i = 0; i < 10; i++) {
+ map_[i] = i;
+ }
+
+ int count = 0;
+
+ for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
+ count++;
+ if (it->first % 2 == 1) {
+ map_.erase(it++);
+ } else {
+ ++it;
+ }
+ }
+
+ EXPECT_EQ(10, count);
+ EXPECT_EQ(5, map_.size());
+}
+
+TEST_F(MapImplTest, EraseByIterator) {
+ int32 key1 = 0;
+ int32 key2 = 1;
+ int32 value1 = 100;
+ int32 value2 = 101;
+
+ std::map<int32, int32> map;
+ map[key1] = value1;
+ map[key2] = value2;
+
+ map_.insert(map.begin(), map.end());
+ ExpectElements(map);
+
+ map_.erase(map_.begin(), map_.end());
+ EXPECT_TRUE(map_.empty());
+ EXPECT_EQ(0, map_.size());
+ EXPECT_TRUE(map_.end() == map_.find(key1));
+ EXPECT_TRUE(map_.end() == map_.find(key2));
+ EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+TEST_F(MapImplTest, Clear) {
+ int32 key = 0;
+ int32 value = 100;
+
+ map_[key] = value;
+ ExpectSingleElement(key, value);
+
+ map_.clear();
+
+ EXPECT_TRUE(map_.empty());
+ EXPECT_EQ(0, map_.size());
+ EXPECT_TRUE(map_.end() == map_.find(key));
+ EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+TEST_F(MapImplTest, CopyConstructor) {
+ int32 key1 = 0;
+ int32 key2 = 1;
+ int32 value1 = 100;
+ int32 value2 = 101;
+
+ std::map<int32, int32> map;
+ map[key1] = value1;
+ map[key2] = value2;
+
+ map_.insert(map.begin(), map.end());
+
+ Map<int32, int32> other(map_);
+
+ EXPECT_EQ(2, other.size());
+ EXPECT_EQ(value1, other.at(key1));
+ EXPECT_EQ(value2, other.at(key2));
+}
+
+TEST_F(MapImplTest, Assigner) {
+ int32 key1 = 0;
+ int32 key2 = 1;
+ int32 value1 = 100;
+ int32 value2 = 101;
+
+ std::map<int32, int32> map;
+ map[key1] = value1;
+ map[key2] = value2;
+
+ map_.insert(map.begin(), map.end());
+
+ Map<int32, int32> other;
+ int32 key_other = 123;
+ int32 value_other = 321;
+ other[key_other] = value_other;
+ EXPECT_EQ(1, other.size());
+
+ other = map_;
+
+ EXPECT_EQ(2, other.size());
+ EXPECT_EQ(value1, other.at(key1));
+ EXPECT_EQ(value2, other.at(key2));
+ EXPECT_TRUE(other.find(key_other) == other.end());
+
+ // Self assign
+ other = other;
+ EXPECT_EQ(2, other.size());
+ EXPECT_EQ(value1, other.at(key1));
+ EXPECT_EQ(value2, other.at(key2));
+}
+
+TEST_F(MapImplTest, Rehash) {
+ const int test_size = 50;
+ std::map<int32, int32> reference_map;
+ for (int i = 0; i < test_size; i++) {
+ reference_map[i] = i;
+ }
+ for (int i = 0; i < test_size; i++) {
+ map_[i] = reference_map[i];
+ EXPECT_EQ(reference_map[i], map_[i]);
+ }
+ for (int i = 0; i < test_size; i++) {
+ map_.erase(i);
+ EXPECT_TRUE(map_.end() == map_.find(i));
+ }
+ EXPECT_TRUE(map_.empty());
+}
+
+TEST_F(MapImplTest, EqualRange) {
+ int key = 100, key_missing = 101;
+ map_[key] = 100;
+
+ std::pair<google::protobuf::Map<int32, int32>::iterator,
+ google::protobuf::Map<int32, int32>::iterator> range = map_.equal_range(key);
+ EXPECT_TRUE(map_.find(key) == range.first);
+ EXPECT_TRUE(++map_.find(key) == range.second);
+
+ range = map_.equal_range(key_missing);
+ EXPECT_TRUE(map_.end() == range.first);
+ EXPECT_TRUE(map_.end() == range.second);
+
+ std::pair<google::protobuf::Map<int32, int32>::const_iterator,
+ google::protobuf::Map<int32, int32>::const_iterator> const_range =
+ const_map_.equal_range(key);
+ EXPECT_TRUE(const_map_.find(key) == const_range.first);
+ EXPECT_TRUE(++const_map_.find(key) == const_range.second);
+
+ const_range = const_map_.equal_range(key_missing);
+ EXPECT_TRUE(const_map_.end() == const_range.first);
+ EXPECT_TRUE(const_map_.end() == const_range.second);
+}
+
+TEST_F(MapImplTest, ConvertToStdMap) {
+ map_[100] = 101;
+ std::map<int32, int32> std_map(map_.begin(), map_.end());
+ EXPECT_EQ(1, std_map.size());
+ EXPECT_EQ(101, std_map[100]);
+}
+
+TEST_F(MapImplTest, ConvertToStdVectorOfPairs) {
+ map_[100] = 101;
+ std::vector<std::pair<int32, int32> > std_vec(map_.begin(), map_.end());
+ EXPECT_EQ(1, std_vec.size());
+ EXPECT_EQ(100, std_vec[0].first);
+ EXPECT_EQ(101, std_vec[0].second);
+}
+
+// Map Field Reflection Test ========================================
+
+static int Func(int i, int j) {
+ return i * j;
+}
+
+static string StrFunc(int i, int j) {
+ string str;
+ SStringPrintf(&str, "%d", Func(i, j));
+ return str;
+}
+
+static int Int(const string& value) {
+ int result = 0;
+ std::istringstream(value) >> result;
+ return result;
+}
+
+class MapFieldReflectionTest : public testing::Test {
+ protected:
+ typedef FieldDescriptor FD;
+};
+
+TEST_F(MapFieldReflectionTest, RegularFields) {
+ TestMap message;
+ const Reflection* refl = message.GetReflection();
+ const Descriptor* desc = message.GetDescriptor();
+
+ Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
+ Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
+ Map<string, string>* map_string_string = message.mutable_map_string_string();
+ Map<int32, ForeignMessage>* map_int32_foreign_message =
+ message.mutable_map_int32_foreign_message();
+
+ for (int i = 0; i < 10; ++i) {
+ (*map_int32_int32)[i] = Func(i, 1);
+ (*map_int32_double)[i] = Func(i, 2);
+ (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
+ (*map_int32_foreign_message)[i].set_c(Func(i, 6));
+ }
+
+ // Get FieldDescriptors for all the fields of interest.
+ const FieldDescriptor* fd_map_int32_int32 =
+ desc->FindFieldByName("map_int32_int32");
+ const FieldDescriptor* fd_map_int32_double =
+ desc->FindFieldByName("map_int32_double");
+ const FieldDescriptor* fd_map_string_string =
+ desc->FindFieldByName("map_string_string");
+ const FieldDescriptor* fd_map_int32_foreign_message =
+ desc->FindFieldByName("map_int32_foreign_message");
+
+ const FieldDescriptor* fd_map_int32_in32_key =
+ fd_map_int32_int32->message_type()->FindFieldByName("key");
+ const FieldDescriptor* fd_map_int32_in32_value =
+ fd_map_int32_int32->message_type()->FindFieldByName("value");
+ const FieldDescriptor* fd_map_int32_double_key =
+ fd_map_int32_double->message_type()->FindFieldByName("key");
+ const FieldDescriptor* fd_map_int32_double_value =
+ fd_map_int32_double->message_type()->FindFieldByName("value");
+ const FieldDescriptor* fd_map_string_string_key =
+ fd_map_string_string->message_type()->FindFieldByName("key");
+ const FieldDescriptor* fd_map_string_string_value =
+ fd_map_string_string->message_type()->FindFieldByName("value");
+ const FieldDescriptor* fd_map_int32_foreign_message_key =
+ fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
+ const FieldDescriptor* fd_map_int32_foreign_message_value =
+ fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
+
+ // Get RepeatedPtrField objects for all fields of interest.
+ const RepeatedPtrField<Message>& mf_int32_int32 =
+ refl->GetRepeatedPtrField<Message>(message, fd_map_int32_int32);
+ const RepeatedPtrField<Message>& mf_int32_double =
+ refl->GetRepeatedPtrField<Message>(message, fd_map_int32_double);
+ const RepeatedPtrField<Message>& mf_string_string =
+ refl->GetRepeatedPtrField<Message>(message, fd_map_string_string);
+ const RepeatedPtrField<Message>&
+ mf_int32_foreign_message =
+ refl->GetRepeatedPtrField<Message>(
+ message, fd_map_int32_foreign_message);
+
+ // Get mutable RepeatedPtrField objects for all fields of interest.
+ RepeatedPtrField<Message>* mmf_int32_int32 =
+ refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_int32);
+ RepeatedPtrField<Message>* mmf_int32_double =
+ refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_double);
+ RepeatedPtrField<Message>* mmf_string_string =
+ refl->MutableRepeatedPtrField<Message>(&message, fd_map_string_string);
+ RepeatedPtrField<Message>* mmf_int32_foreign_message =
+ refl->MutableRepeatedPtrField<Message>(
+ &message, fd_map_int32_foreign_message);
+
+ // Make sure we can do gets through the RepeatedPtrField objects.
+ for (int i = 0; i < 10; ++i) {
+ {
+ // Check gets through const objects.
+ const Message& message_int32_int32 = mf_int32_int32.Get(i);
+ int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+ message_int32_int32, fd_map_int32_in32_key);
+ int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+ message_int32_int32, fd_map_int32_in32_value);
+ EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+ const Message& message_int32_double = mf_int32_double.Get(i);
+ int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+ message_int32_double, fd_map_int32_double_key);
+ double value_int32_double =
+ message_int32_double.GetReflection()->GetDouble(
+ message_int32_double, fd_map_int32_double_value);
+ EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+ const Message& message_string_string = mf_string_string.Get(i);
+ string key_string_string =
+ message_string_string.GetReflection()->GetString(
+ message_string_string, fd_map_string_string_key);
+ string value_string_string =
+ message_string_string.GetReflection()->GetString(
+ message_string_string, fd_map_string_string_value);
+ EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+ const Message& message_int32_message = mf_int32_foreign_message.Get(i);
+ int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+ message_int32_message, fd_map_int32_foreign_message_key);
+ const ForeignMessage& value_int32_message =
+ down_cast<const ForeignMessage&>(
+ message_int32_message.GetReflection()
+ ->GetMessage(message_int32_message,
+ fd_map_int32_foreign_message_value));
+ EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+ }
+
+ {
+ // Check gets through mutable objects.
+ const Message& message_int32_int32 = mmf_int32_int32->Get(i);
+ int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+ message_int32_int32, fd_map_int32_in32_key);
+ int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+ message_int32_int32, fd_map_int32_in32_value);
+ EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+ const Message& message_int32_double = mmf_int32_double->Get(i);
+ int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+ message_int32_double, fd_map_int32_double_key);
+ double value_int32_double =
+ message_int32_double.GetReflection()->GetDouble(
+ message_int32_double, fd_map_int32_double_value);
+ EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+ const Message& message_string_string = mmf_string_string->Get(i);
+ string key_string_string =
+ message_string_string.GetReflection()->GetString(
+ message_string_string, fd_map_string_string_key);
+ string value_string_string =
+ message_string_string.GetReflection()->GetString(
+ message_string_string, fd_map_string_string_value);
+ EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+ const Message& message_int32_message = mmf_int32_foreign_message->Get(i);
+ int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+ message_int32_message, fd_map_int32_foreign_message_key);
+ const ForeignMessage& value_int32_message =
+ down_cast<const ForeignMessage&>(
+ message_int32_message.GetReflection()
+ ->GetMessage(message_int32_message,
+ fd_map_int32_foreign_message_value));
+ EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+ }
+ }
+
+ // Do sets through the RepeatedPtrField objects.
+ for (int i = 0; i < 10; i++) {
+ {
+ Message* message_int32_int32 = mmf_int32_int32->Mutable(i);
+ int32 key_int32_int32 = message_int32_int32->GetReflection()->GetInt32(
+ *message_int32_int32, fd_map_int32_in32_key);
+ message_int32_int32->GetReflection()->SetInt32(message_int32_int32,
+ fd_map_int32_in32_value,
+ Func(key_int32_int32, -1));
+
+ Message* message_int32_double = mmf_int32_double->Mutable(i);
+ int32 key_int32_double = message_int32_double->GetReflection()->GetInt32(
+ *message_int32_double, fd_map_int32_double_key);
+ message_int32_double->GetReflection()->SetDouble(
+ message_int32_double, fd_map_int32_double_value,
+ Func(key_int32_double, -2));
+
+ Message* message_string_string = mmf_string_string->Mutable(i);
+ string key_string_string =
+ message_string_string->GetReflection()->GetString(
+ *message_string_string, fd_map_string_string_key);
+ message_string_string->GetReflection()->SetString(
+ message_string_string, fd_map_string_string_value,
+ StrFunc(Int(key_string_string), -5));
+
+ Message* message_int32_message = mmf_int32_foreign_message->Mutable(i);
+ int32 key_int32_message =
+ message_int32_message->GetReflection()->GetInt32(
+ *message_int32_message, fd_map_int32_foreign_message_key);
+ ForeignMessage* value_int32_message = down_cast<ForeignMessage*>(
+ message_int32_message->GetReflection()
+ ->MutableMessage(message_int32_message,
+ fd_map_int32_foreign_message_value));
+ value_int32_message->set_c(Func(key_int32_message, -6));
+ }
+ }
+
+ // Check gets through mutable objects.
+ for (int i = 0; i < 10; i++) {
+ EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
+ EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
+ EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
+ EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
+ }
+}
+
+TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) {
+ TestMap message;
+ const Reflection* refl = message.GetReflection();
+ const Descriptor* desc = message.GetDescriptor();
+
+ Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
+ Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
+ Map<string, string>* map_string_string = message.mutable_map_string_string();
+ Map<int32, ForeignMessage>* map_int32_foreign_message =
+ message.mutable_map_int32_foreign_message();
+
+ for (int i = 0; i < 10; ++i) {
+ (*map_int32_int32)[i] = Func(i, 1);
+ (*map_int32_double)[i] = Func(i, 2);
+ (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
+ (*map_int32_foreign_message)[i].set_c(Func(i, 6));
+ }
+
+ // Get FieldDescriptors for all the fields of interest.
+ const FieldDescriptor* fd_map_int32_int32 =
+ desc->FindFieldByName("map_int32_int32");
+ const FieldDescriptor* fd_map_int32_double =
+ desc->FindFieldByName("map_int32_double");
+ const FieldDescriptor* fd_map_string_string =
+ desc->FindFieldByName("map_string_string");
+ const FieldDescriptor* fd_map_int32_foreign_message =
+ desc->FindFieldByName("map_int32_foreign_message");
+
+ const FieldDescriptor* fd_map_int32_in32_key =
+ fd_map_int32_int32->message_type()->FindFieldByName("key");
+ const FieldDescriptor* fd_map_int32_in32_value =
+ fd_map_int32_int32->message_type()->FindFieldByName("value");
+ const FieldDescriptor* fd_map_int32_double_key =
+ fd_map_int32_double->message_type()->FindFieldByName("key");
+ const FieldDescriptor* fd_map_int32_double_value =
+ fd_map_int32_double->message_type()->FindFieldByName("value");
+ const FieldDescriptor* fd_map_string_string_key =
+ fd_map_string_string->message_type()->FindFieldByName("key");
+ const FieldDescriptor* fd_map_string_string_value =
+ fd_map_string_string->message_type()->FindFieldByName("value");
+ const FieldDescriptor* fd_map_int32_foreign_message_key =
+ fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
+ const FieldDescriptor* fd_map_int32_foreign_message_value =
+ fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
+
+ // Get RepeatedFieldRef objects for all fields of interest.
+ const RepeatedFieldRef<Message> mf_int32_int32 =
+ refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_int32);
+ const RepeatedFieldRef<Message> mf_int32_double =
+ refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_double);
+ const RepeatedFieldRef<Message> mf_string_string =
+ refl->GetRepeatedFieldRef<Message>(message, fd_map_string_string);
+ const RepeatedFieldRef<Message> mf_int32_foreign_message =
+ refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_foreign_message);
+
+ // Get mutable RepeatedFieldRef objects for all fields of interest.
+ const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
+ refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_int32);
+ const MutableRepeatedFieldRef<Message> mmf_int32_double =
+ refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_double);
+ const MutableRepeatedFieldRef<Message> mmf_string_string =
+ refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_string_string);
+ const MutableRepeatedFieldRef<Message>
+ mmf_int32_foreign_message =
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &message, fd_map_int32_foreign_message);
+
+ // Get entry default instances
+ google::protobuf::scoped_ptr<Message> entry_int32_int32(
+ MessageFactory::generated_factory()
+ ->GetPrototype(fd_map_int32_int32->message_type())
+ ->New());
+ google::protobuf::scoped_ptr<Message> entry_int32_double(
+ MessageFactory::generated_factory()
+ ->GetPrototype(fd_map_int32_double->message_type())
+ ->New());
+ google::protobuf::scoped_ptr<Message> entry_string_string(
+ MessageFactory::generated_factory()
+ ->GetPrototype(fd_map_string_string->message_type())
+ ->New());
+ google::protobuf::scoped_ptr<Message> entry_int32_foreign_message(
+ MessageFactory::generated_factory()
+ ->GetPrototype(fd_map_int32_foreign_message->message_type())
+ ->New());
+
+ EXPECT_EQ(10, mf_int32_int32.size());
+ EXPECT_EQ(10, mmf_int32_int32.size());
+ EXPECT_EQ(10, mf_int32_double.size());
+ EXPECT_EQ(10, mmf_int32_double.size());
+ EXPECT_EQ(10, mf_string_string.size());
+ EXPECT_EQ(10, mmf_string_string.size());
+ EXPECT_EQ(10, mf_int32_foreign_message.size());
+ EXPECT_EQ(10, mmf_int32_foreign_message.size());
+
+ EXPECT_FALSE(mf_int32_int32.empty());
+ EXPECT_FALSE(mmf_int32_int32.empty());
+ EXPECT_FALSE(mf_int32_double.empty());
+ EXPECT_FALSE(mmf_int32_double.empty());
+ EXPECT_FALSE(mf_string_string.empty());
+ EXPECT_FALSE(mmf_string_string.empty());
+ EXPECT_FALSE(mf_int32_foreign_message.empty());
+ EXPECT_FALSE(mmf_int32_foreign_message.empty());
+
+ // Make sure we can do gets through the RepeatedFieldRef objects.
+ for (int i = 0; i < 10; ++i) {
+ {
+ // Check gets through const objects.
+ const Message& message_int32_int32 =
+ mf_int32_int32.Get(i, entry_int32_int32.get());
+ int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+ message_int32_int32, fd_map_int32_in32_key);
+ int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+ message_int32_int32, fd_map_int32_in32_value);
+ EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+ const Message& message_int32_double =
+ mf_int32_double.Get(i, entry_int32_double.get());
+ int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+ message_int32_double, fd_map_int32_double_key);
+ double value_int32_double =
+ message_int32_double.GetReflection()->GetDouble(
+ message_int32_double, fd_map_int32_double_value);
+ EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+ const Message& message_string_string =
+ mf_string_string.Get(i, entry_string_string.get());
+ string key_string_string =
+ message_string_string.GetReflection()->GetString(
+ message_string_string, fd_map_string_string_key);
+ string value_string_string =
+ message_string_string.GetReflection()->GetString(
+ message_string_string, fd_map_string_string_value);
+ EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+ const Message& message_int32_message =
+ mf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
+ int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+ message_int32_message, fd_map_int32_foreign_message_key);
+ const ForeignMessage& value_int32_message =
+ down_cast<const ForeignMessage&>(
+ message_int32_message.GetReflection()
+ ->GetMessage(message_int32_message,
+ fd_map_int32_foreign_message_value));
+ EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+ }
+
+ {
+ // Check gets through mutable objects.
+ const Message& message_int32_int32 =
+ mmf_int32_int32.Get(i, entry_int32_int32.get());
+ int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+ message_int32_int32, fd_map_int32_in32_key);
+ int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+ message_int32_int32, fd_map_int32_in32_value);
+ EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+ const Message& message_int32_double =
+ mmf_int32_double.Get(i, entry_int32_double.get());
+ int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+ message_int32_double, fd_map_int32_double_key);
+ double value_int32_double =
+ message_int32_double.GetReflection()->GetDouble(
+ message_int32_double, fd_map_int32_double_value);
+ EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+ const Message& message_string_string =
+ mmf_string_string.Get(i, entry_string_string.get());
+ string key_string_string =
+ message_string_string.GetReflection()->GetString(
+ message_string_string, fd_map_string_string_key);
+ string value_string_string =
+ message_string_string.GetReflection()->GetString(
+ message_string_string, fd_map_string_string_value);
+ EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+ const Message& message_int32_message =
+ mmf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
+ int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+ message_int32_message, fd_map_int32_foreign_message_key);
+ const ForeignMessage& value_int32_message =
+ down_cast<const ForeignMessage&>(
+ message_int32_message.GetReflection()
+ ->GetMessage(message_int32_message,
+ fd_map_int32_foreign_message_value));
+ EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+ }
+ }
+
+ // Make sure we can do sets through the RepeatedFieldRef objects.
+ for (int i = 0; i < 10; i++) {
+ const Message& message_int32_int32 =
+ mmf_int32_int32.Get(i, entry_int32_int32.get());
+ int key = message_int32_int32.GetReflection()->GetInt32(
+ message_int32_int32, fd_map_int32_in32_key);
+
+ entry_int32_int32->GetReflection()->SetInt32(
+ entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
+ key);
+ entry_int32_int32->GetReflection()->SetInt32(
+ entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
+ Func(key, -1));
+ entry_int32_double->GetReflection()->SetInt32(
+ entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
+ key);
+ entry_int32_double->GetReflection()->SetDouble(
+ entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
+ Func(key, -2));
+ entry_string_string->GetReflection()->SetString(
+ entry_string_string.get(),
+ fd_map_string_string->message_type()->field(0), StrFunc(key, 1));
+ entry_string_string->GetReflection()->SetString(
+ entry_string_string.get(),
+ fd_map_string_string->message_type()->field(1), StrFunc(key, -5));
+ entry_int32_foreign_message->GetReflection()->SetInt32(
+ entry_int32_foreign_message.get(),
+ fd_map_int32_foreign_message->message_type()->field(0), key);
+ Message* value_message =
+ entry_int32_foreign_message->GetReflection()->MutableMessage(
+ entry_int32_foreign_message.get(),
+ fd_map_int32_foreign_message->message_type()->field(1));
+ value_message->GetReflection()->SetInt32(
+ value_message, value_message->GetDescriptor()->FindFieldByName("c"),
+ Func(key, -6));
+
+ mmf_int32_int32.Set(i, *entry_int32_int32);
+ mmf_int32_double.Set(i, *entry_int32_double);
+ mmf_string_string.Set(i, *entry_string_string);
+ mmf_int32_foreign_message.Set(i, *entry_int32_foreign_message);
+ }
+
+ for (int i = 0; i < 10; i++) {
+ EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
+ EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
+ EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
+ EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
+ }
+
+ // Test iterators.
+ {
+ int index = 0;
+ hash_map<int32, int32> result;
+ for (RepeatedFieldRef<Message>::iterator it = mf_int32_int32.begin();
+ it != mf_int32_int32.end(); ++it) {
+ const Message& message = *it;
+ int32 key =
+ message.GetReflection()->GetInt32(message, fd_map_int32_in32_key);
+ int32 value =
+ message.GetReflection()->GetInt32(message, fd_map_int32_in32_value);
+ result[key] = value;
+ ++index;
+ }
+ EXPECT_EQ(10, index);
+ for (hash_map<int32, int32>::const_iterator it = result.begin();
+ it != result.end(); ++it) {
+ EXPECT_EQ(message.map_int32_int32().at(it->first), it->second);
+ }
+ }
+
+ {
+ int index = 0;
+ hash_map<int32, double> result;
+ for (RepeatedFieldRef<Message>::iterator it = mf_int32_double.begin();
+ it != mf_int32_double.end(); ++it) {
+ const Message& message = *it;
+ int32 key =
+ message.GetReflection()->GetInt32(message, fd_map_int32_double_key);
+ double value = message.GetReflection()->GetDouble(
+ message, fd_map_int32_double_value);
+ result[key] = value;
+ ++index;
+ }
+ EXPECT_EQ(10, index);
+ for (hash_map<int32, double>::const_iterator it = result.begin();
+ it != result.end(); ++it) {
+ EXPECT_EQ(message.map_int32_double().at(it->first), it->second);
+ }
+ }
+
+ {
+ int index = 0;
+ hash_map<string, string> result;
+ for (RepeatedFieldRef<Message>::iterator it = mf_string_string.begin();
+ it != mf_string_string.end(); ++it) {
+ const Message& message = *it;
+ string key =
+ message.GetReflection()->GetString(message, fd_map_string_string_key);
+ string value = message.GetReflection()->GetString(
+ message, fd_map_string_string_value);
+ result[key] = value;
+ ++index;
+ }
+ EXPECT_EQ(10, index);
+ for (hash_map<string, string>::const_iterator it = result.begin();
+ it != result.end(); ++it) {
+ EXPECT_EQ(message.map_string_string().at(it->first), it->second);
+ }
+ }
+
+ {
+ int index = 0;
+ std::map<int32, ForeignMessage> result;
+ for (RepeatedFieldRef<Message>::iterator it =
+ mf_int32_foreign_message.begin();
+ it != mf_int32_foreign_message.end(); ++it) {
+ const Message& message = *it;
+ int32 key = message.GetReflection()->GetInt32(
+ message, fd_map_int32_foreign_message_key);
+ const ForeignMessage& sub_message = down_cast<const ForeignMessage&>(
+ message.GetReflection()
+ ->GetMessage(message, fd_map_int32_foreign_message_value));
+ result[key].MergeFrom(sub_message);
+ ++index;
+ }
+ EXPECT_EQ(10, index);
+ for (std::map<int32, ForeignMessage>::const_iterator it = result.begin();
+ it != result.end(); ++it) {
+ EXPECT_EQ(message.map_int32_foreign_message().at(it->first).c(),
+ it->second.c());
+ }
+ }
+
+ // Test MutableRepeatedFieldRef::Add()
+ entry_int32_int32->GetReflection()->SetInt32(
+ entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
+ 4321);
+ entry_int32_int32->GetReflection()->SetInt32(
+ entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
+ 1234);
+ mmf_int32_int32.Add(*entry_int32_int32);
+ EXPECT_EQ(1234, message.map_int32_int32().at(4321));
+
+ entry_int32_double->GetReflection()->SetInt32(
+ entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
+ 4321);
+ entry_int32_double->GetReflection()->SetDouble(
+ entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
+ 1234.0);
+ mmf_int32_double.Add(*entry_int32_double);
+ EXPECT_EQ(1234.0, message.map_int32_double().at(4321));
+
+ entry_string_string->GetReflection()->SetString(
+ entry_string_string.get(),
+ fd_map_string_string->message_type()->field(0), "4321");
+ entry_string_string->GetReflection()->SetString(
+ entry_string_string.get(), fd_map_string_string->message_type()->field(1),
+ "1234");
+ mmf_string_string.Add(*entry_string_string);
+ EXPECT_EQ("1234", message.map_string_string().at("4321"));
+
+ entry_int32_foreign_message->GetReflection()->SetInt32(
+ entry_int32_foreign_message.get(),
+ fd_map_int32_foreign_message->message_type()->field(0), 4321);
+ Message* value_message =
+ entry_int32_foreign_message->GetReflection()->MutableMessage(
+ entry_int32_foreign_message.get(),
+ fd_map_int32_foreign_message->message_type()->field(1));
+ ForeignMessage foreign_message;
+ foreign_message.set_c(1234);
+ value_message->CopyFrom(foreign_message);
+
+ mmf_int32_foreign_message.Add(*entry_int32_foreign_message);
+ EXPECT_EQ(1234, message.map_int32_foreign_message().at(4321).c());
+
+ // Test MutableRepeatedFieldRef::RemoveLast()
+ mmf_int32_int32.RemoveLast();
+ mmf_int32_double.RemoveLast();
+ mmf_string_string.RemoveLast();
+ mmf_int32_foreign_message.RemoveLast();
+ EXPECT_EQ(10, message.map_int32_int32().size());
+ EXPECT_EQ(10, message.map_int32_double().size());
+ EXPECT_EQ(10, message.map_string_string().size());
+ EXPECT_EQ(10, message.map_int32_foreign_message().size());
+
+ // Test MutableRepeatedFieldRef::SwapElements()
+ {
+ const Message& message0a = mmf_int32_int32.Get(0, entry_int32_int32.get());
+ int32 int32_value0a =
+ message0a.GetReflection()->GetInt32(message0a, fd_map_int32_in32_value);
+ const Message& message9a = mmf_int32_int32.Get(9, entry_int32_int32.get());
+ int32 int32_value9a =
+ message9a.GetReflection()->GetInt32(message9a, fd_map_int32_in32_value);
+
+ mmf_int32_int32.SwapElements(0, 9);
+
+ const Message& message0b = mmf_int32_int32.Get(0, entry_int32_int32.get());
+ int32 int32_value0b =
+ message0b.GetReflection()->GetInt32(message0b, fd_map_int32_in32_value);
+ const Message& message9b = mmf_int32_int32.Get(9, entry_int32_int32.get());
+ int32 int32_value9b =
+ message9b.GetReflection()->GetInt32(message9b, fd_map_int32_in32_value);
+
+ EXPECT_EQ(int32_value9a, int32_value0b);
+ EXPECT_EQ(int32_value0a, int32_value9b);
+ }
+
+ {
+ const Message& message0a =
+ mmf_int32_double.Get(0, entry_int32_double.get());
+ double double_value0a = message0a.GetReflection()->GetDouble(
+ message0a, fd_map_int32_double_value);
+ const Message& message9a =
+ mmf_int32_double.Get(9, entry_int32_double.get());
+ double double_value9a = message9a.GetReflection()->GetDouble(
+ message9a, fd_map_int32_double_value);
+
+ mmf_int32_double.SwapElements(0, 9);
+
+ const Message& message0b =
+ mmf_int32_double.Get(0, entry_int32_double.get());
+ double double_value0b = message0b.GetReflection()->GetDouble(
+ message0b, fd_map_int32_double_value);
+ const Message& message9b =
+ mmf_int32_double.Get(9, entry_int32_double.get());
+ double double_value9b = message9b.GetReflection()->GetDouble(
+ message9b, fd_map_int32_double_value);
+
+ EXPECT_EQ(double_value9a, double_value0b);
+ EXPECT_EQ(double_value0a, double_value9b);
+ }
+
+ {
+ const Message& message0a =
+ mmf_string_string.Get(0, entry_string_string.get());
+ string string_value0a = message0a.GetReflection()->GetString(
+ message0a, fd_map_string_string_value);
+ const Message& message9a =
+ mmf_string_string.Get(9, entry_string_string.get());
+ string string_value9a = message9a.GetReflection()->GetString(
+ message9a, fd_map_string_string_value);
+
+ mmf_string_string.SwapElements(0, 9);
+
+ const Message& message0b =
+ mmf_string_string.Get(0, entry_string_string.get());
+ string string_value0b = message0b.GetReflection()->GetString(
+ message0b, fd_map_string_string_value);
+ const Message& message9b =
+ mmf_string_string.Get(9, entry_string_string.get());
+ string string_value9b = message9b.GetReflection()->GetString(
+ message9b, fd_map_string_string_value);
+
+ EXPECT_EQ(string_value9a, string_value0b);
+ EXPECT_EQ(string_value0a, string_value9b);
+ }
+
+ {
+ const Message& message0a =
+ mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
+ const ForeignMessage& sub_message0a = down_cast<const ForeignMessage&>(
+ message0a.GetReflection()
+ ->GetMessage(message0a, fd_map_int32_foreign_message_value));
+ int32 int32_value0a = sub_message0a.c();
+ const Message& message9a =
+ mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
+ const ForeignMessage& sub_message9a = down_cast<const ForeignMessage&>(
+ message9a.GetReflection()
+ ->GetMessage(message9a, fd_map_int32_foreign_message_value));
+ int32 int32_value9a = sub_message9a.c();
+
+ mmf_int32_foreign_message.SwapElements(0, 9);
+
+ const Message& message0b =
+ mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
+ const ForeignMessage& sub_message0b = down_cast<const ForeignMessage&>(
+ message0b.GetReflection()
+ ->GetMessage(message0b, fd_map_int32_foreign_message_value));
+ int32 int32_value0b = sub_message0b.c();
+ const Message& message9b =
+ mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
+ const ForeignMessage& sub_message9b = down_cast<const ForeignMessage&>(
+ message9b.GetReflection()
+ ->GetMessage(message9b, fd_map_int32_foreign_message_value));
+ int32 int32_value9b = sub_message9b.c();
+
+ EXPECT_EQ(int32_value9a, int32_value0b);
+ EXPECT_EQ(int32_value0a, int32_value9b);
+ }
+}
+
+TEST_F(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
+ // Set-up message content.
+ TestMap m0, m1, m2;
+ for (int i = 0; i < 10; ++i) {
+ (*m0.mutable_map_int32_int32())[i] = Func(i, 1);
+ (*m0.mutable_map_int32_double())[i] = Func(i, 2);
+ (*m0.mutable_map_string_string())[StrFunc(i, 1)] = StrFunc(i, 5);
+ (*m0.mutable_map_int32_foreign_message())[i].set_c(Func(i, 6));
+ (*m1.mutable_map_int32_int32())[i + 10] = Func(i, 11);
+ (*m1.mutable_map_int32_double())[i + 10] = Func(i, 12);
+ (*m1.mutable_map_string_string())[StrFunc(i + 10, 1)] = StrFunc(i, 15);
+ (*m1.mutable_map_int32_foreign_message())[i + 10].set_c(Func(i, 16));
+ (*m2.mutable_map_int32_int32())[i + 20] = Func(i, 21);
+ (*m2.mutable_map_int32_double())[i + 20] = Func(i, 22);
+ (*m2.mutable_map_string_string())[StrFunc(i + 20, 1)] = StrFunc(i, 25);
+ (*m2.mutable_map_int32_foreign_message())[i + 20].set_c(Func(i, 26));
+ }
+
+ const Reflection* refl = m0.GetReflection();
+ const Descriptor* desc = m0.GetDescriptor();
+
+ // Get FieldDescriptors for all the fields of interest.
+ const FieldDescriptor* fd_map_int32_int32 =
+ desc->FindFieldByName("map_int32_int32");
+ const FieldDescriptor* fd_map_int32_double =
+ desc->FindFieldByName("map_int32_double");
+ const FieldDescriptor* fd_map_string_string =
+ desc->FindFieldByName("map_string_string");
+ const FieldDescriptor* fd_map_int32_foreign_message =
+ desc->FindFieldByName("map_int32_foreign_message");
+
+ // Get MutableRepeatedFieldRef objects for all fields of interest.
+ const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &m0, fd_map_int32_int32);
+ const MutableRepeatedFieldRef<Message> mmf_int32_double =
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &m0, fd_map_int32_double);
+ const MutableRepeatedFieldRef<Message> mmf_string_string =
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &m0, fd_map_string_string);
+ const MutableRepeatedFieldRef<Message>
+ mmf_int32_foreign_message =
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &m0, fd_map_int32_foreign_message);
+
+ // Test MutableRepeatedRef::CopyFrom
+ mmf_int32_int32.CopyFrom(
+ refl->GetRepeatedFieldRef<Message>(
+ m1, fd_map_int32_int32));
+ mmf_int32_double.CopyFrom(
+ refl->GetRepeatedFieldRef<Message>(
+ m1, fd_map_int32_double));
+ mmf_string_string.CopyFrom(
+ refl->GetRepeatedFieldRef<Message>(
+ m1, fd_map_string_string));
+ mmf_int32_foreign_message.CopyFrom(
+ refl->GetRepeatedFieldRef<Message>(
+ m1, fd_map_int32_foreign_message));
+
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(Func(i, 11), m0.map_int32_int32().at(i + 10));
+ EXPECT_EQ(Func(i, 12), m0.map_int32_double().at(i + 10));
+ EXPECT_EQ(StrFunc(i, 15), m0.map_string_string().at(StrFunc(i + 10, 1)));
+ EXPECT_EQ(Func(i, 16), m0.map_int32_foreign_message().at(i + 10).c());
+ }
+
+ // Test MutableRepeatedRef::MergeFrom
+ mmf_int32_int32.MergeFrom(
+ refl->GetRepeatedFieldRef<Message>(
+ m2, fd_map_int32_int32));
+ mmf_int32_double.MergeFrom(
+ refl->GetRepeatedFieldRef<Message>(
+ m2, fd_map_int32_double));
+ mmf_string_string.MergeFrom(
+ refl->GetRepeatedFieldRef<Message>(
+ m2, fd_map_string_string));
+ mmf_int32_foreign_message.MergeFrom(
+ refl->GetRepeatedFieldRef<Message>(
+ m2, fd_map_int32_foreign_message));
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
+ EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
+ EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
+ EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
+ }
+
+ // Test MutableRepeatedRef::Swap
+ // Swap between m0 and m2.
+ mmf_int32_int32.Swap(
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &m2, fd_map_int32_int32));
+ mmf_int32_double.Swap(
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &m2, fd_map_int32_double));
+ mmf_string_string.Swap(
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &m2, fd_map_string_string));
+ mmf_int32_foreign_message.Swap(
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &m2, fd_map_int32_foreign_message));
+ for (int i = 0; i < 10; ++i) {
+ // Check the content of m0.
+ EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
+ EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
+ EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
+ EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
+
+ // Check the content of m2.
+ EXPECT_EQ(Func(i, 11), m2.map_int32_int32().at(i + 10));
+ EXPECT_EQ(Func(i, 12), m2.map_int32_double().at(i + 10));
+ EXPECT_EQ(StrFunc(i, 15), m2.map_string_string().at(StrFunc(i + 10, 1)));
+ EXPECT_EQ(Func(i, 16), m2.map_int32_foreign_message().at(i + 10).c());
+ EXPECT_EQ(Func(i, 21), m2.map_int32_int32().at(i + 20));
+ EXPECT_EQ(Func(i, 22), m2.map_int32_double().at(i + 20));
+ EXPECT_EQ(StrFunc(i, 25), m2.map_string_string().at(StrFunc(i + 20, 1)));
+ EXPECT_EQ(Func(i, 26), m2.map_int32_foreign_message().at(i + 20).c());
+ }
+
+ // TODO(teboring): add test for duplicated key
+}
+
+// Generated Message Test ===========================================
+
+TEST(GeneratedMapFieldTest, Accessors) {
+ unittest::TestMap message;
+
+ MapTestUtil::SetMapFields(&message);
+ MapTestUtil::ExpectMapFieldsSet(message);
+
+ MapTestUtil::ModifyMapFields(&message);
+ MapTestUtil::ExpectMapFieldsModified(message);
+}
+
+TEST(GeneratedMapFieldTest, SetMapFieldsInitialized) {
+ unittest::TestMap message;
+
+ MapTestUtil::SetMapFieldsInitialized(&message);
+ MapTestUtil::ExpectMapFieldsSetInitialized(message);
+}
+
+TEST(GeneratedMapFieldTest, Proto2SetMapFieldsInitialized) {
+ unittest::TestEnumStartWithNonZeroMap message;
+ EXPECT_EQ(unittest::PROTO2_NON_ZERO_MAP_ENUM_FOO,
+ (*message.mutable_map_field())[0]);
+}
+
+TEST(GeneratedMapFieldTest, Clear) {
+ unittest::TestMap message;
+
+ MapTestUtil::SetMapFields(&message);
+ message.Clear();
+ MapTestUtil::ExpectClear(message);
+}
+
+TEST(GeneratedMapFieldTest, ClearMessageMap) {
+ unittest::TestMessageMap message;
+
+ // Creates a TestAllTypes with default value
+ TestUtil::ExpectClear((*message.mutable_map_int32_message())[0]);
+}
+
+TEST(GeneratedMapFieldTest, CopyFrom) {
+ unittest::TestMap message1, message2;
+
+ MapTestUtil::SetMapFields(&message1);
+ message2.CopyFrom(message1);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+
+ // Copying from self should be a no-op.
+ message2.CopyFrom(message2);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyFromMessageMap) {
+ unittest::TestMessageMap message1, message2;
+
+ (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+ (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+ message1.CopyFrom(message2);
+
+ // Checks repeated field is overwritten.
+ EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+ EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+}
+
+TEST(GeneratedMapFieldTest, SwapWithEmpty) {
+ unittest::TestMap message1, message2;
+
+ MapTestUtil::SetMapFields(&message1);
+ MapTestUtil::ExpectMapFieldsSet(message1);
+ MapTestUtil::ExpectClear(message2);
+
+ message1.Swap(&message2);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+ MapTestUtil::ExpectClear(message1);
+}
+
+TEST(GeneratedMapFieldTest, SwapWithSelf) {
+ unittest::TestMap message;
+
+ MapTestUtil::SetMapFields(&message);
+ MapTestUtil::ExpectMapFieldsSet(message);
+
+ message.Swap(&message);
+ MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(GeneratedMapFieldTest, SwapWithOther) {
+ unittest::TestMap message1, message2;
+
+ MapTestUtil::SetMapFields(&message1);
+ MapTestUtil::SetMapFields(&message2);
+ MapTestUtil::ModifyMapFields(&message2);
+
+ message1.Swap(&message2);
+ MapTestUtil::ExpectMapFieldsModified(message1);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyConstructor) {
+ unittest::TestMap message1;
+ MapTestUtil::SetMapFields(&message1);
+
+ unittest::TestMap message2(message1);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyAssignmentOperator) {
+ unittest::TestMap message1;
+ MapTestUtil::SetMapFields(&message1);
+
+ unittest::TestMap message2;
+ message2 = message1;
+ MapTestUtil::ExpectMapFieldsSet(message2);
+
+ // Make sure that self-assignment does something sane.
+ message2.operator=(message2);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \
+ !defined(GOOGLE_PROTOBUF_NO_RTTI)
+TEST(GeneratedMapFieldTest, UpcastCopyFrom) {
+ // Test the CopyFrom method that takes in the generic const Message&
+ // parameter.
+ unittest::TestMap message1, message2;
+
+ MapTestUtil::SetMapFields(&message1);
+
+ const Message* source = implicit_cast<const Message*>(&message1);
+ message2.CopyFrom(*source);
+
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+#endif
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GeneratedMapFieldTest, CopyFromDynamicMessage) {
+ // Test copying from a DynamicMessage, which must fall back to using
+ // reflection.
+ unittest::TestMap message2;
+
+ // Construct a new version of the dynamic message via the factory.
+ DynamicMessageFactory factory;
+ google::protobuf::scoped_ptr<Message> message1;
+ message1.reset(
+ factory.GetPrototype(unittest::TestMap::descriptor())->New());
+
+ MapTestUtil::MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+ reflection_tester.SetMapFieldsViaReflection(message1.get());
+ reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+
+ message2.CopyFrom(*message1);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, DynamicMessageCopyFrom) {
+ // Test copying to a DynamicMessage, which must fall back to using reflection.
+ unittest::TestMap message2;
+ MapTestUtil::SetMapFields(&message2);
+
+ // Construct a new version of the dynamic message via the factory.
+ DynamicMessageFactory factory;
+ google::protobuf::scoped_ptr<Message> message1;
+ message1.reset(
+ factory.GetPrototype(unittest::TestMap::descriptor())->New());
+
+ MapTestUtil::MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+ message1->MergeFrom(message2);
+ reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+}
+
+#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GeneratedMapFieldTest, NonEmptyMergeFrom) {
+ unittest::TestMap message1, message2;
+
+ MapTestUtil::SetMapFields(&message1);
+
+ // This field will test merging into an empty spot.
+ (*message2.mutable_map_int32_int32())[1] = 1;
+ message1.mutable_map_int32_int32()->erase(1);
+
+ // This tests overwriting.
+ (*message2.mutable_map_int32_double())[1] = 1;
+ (*message1.mutable_map_int32_double())[1] = 2;
+
+ message1.MergeFrom(message2);
+ MapTestUtil::ExpectMapFieldsSet(message1);
+}
+
+TEST(GeneratedMapFieldTest, MergeFromMessageMap) {
+ unittest::TestMessageMap message1, message2;
+
+ (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+ (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+ message1.MergeFrom(message2);
+
+ // Checks repeated field is overwritten.
+ EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+ EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+}
+
+// Test the generated SerializeWithCachedSizesToArray()
+TEST(GeneratedMapFieldTest, SerializationToArray) {
+ unittest::TestMap message1, message2;
+ string data;
+ MapTestUtil::SetMapFields(&message1);
+ int size = message1.ByteSize();
+ data.resize(size);
+ uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+ uint8* end = message1.SerializeWithCachedSizesToArray(start);
+ EXPECT_EQ(size, end - start);
+ EXPECT_TRUE(message2.ParseFromString(data));
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+// Test the generated SerializeWithCachedSizes()
+TEST(GeneratedMapFieldTest, SerializationToStream) {
+ unittest::TestMap message1, message2;
+ MapTestUtil::SetMapFields(&message1);
+ int size = message1.ByteSize();
+ string data;
+ data.resize(size);
+ {
+ // Allow the output stream to buffer only one byte at a time.
+ io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+ io::CodedOutputStream output_stream(&array_stream);
+ message1.SerializeWithCachedSizes(&output_stream);
+ EXPECT_FALSE(output_stream.HadError());
+ EXPECT_EQ(size, output_stream.ByteCount());
+ }
+ EXPECT_TRUE(message2.ParseFromString(data));
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+
+TEST(GeneratedMapFieldTest, SameTypeMaps) {
+ const Descriptor* map1 = unittest::TestSameTypeMap::descriptor()
+ ->FindFieldByName("map1")
+ ->message_type();
+ const Descriptor* map2 = unittest::TestSameTypeMap::descriptor()
+ ->FindFieldByName("map2")
+ ->message_type();
+
+ const Message* map1_entry =
+ MessageFactory::generated_factory()->GetPrototype(map1);
+ const Message* map2_entry =
+ MessageFactory::generated_factory()->GetPrototype(map2);
+
+ EXPECT_EQ(map1, map1_entry->GetDescriptor());
+ EXPECT_EQ(map2, map2_entry->GetDescriptor());
+}
+
+TEST(GeneratedMapFieldTest, Proto2UnknownEnum) {
+ unittest::TestEnumMapPlusExtra from;
+ (*from.mutable_known_map_field())[0] = unittest::E_PROTO2_MAP_ENUM_FOO;
+ (*from.mutable_unknown_map_field())[0] = unittest::E_PROTO2_MAP_ENUM_EXTRA;
+ string data;
+ from.SerializeToString(&data);
+
+ unittest::TestEnumMap to;
+ EXPECT_TRUE(to.ParseFromString(data));
+ EXPECT_EQ(0, to.unknown_map_field().size());
+ const UnknownFieldSet& unknown_field_set =
+ to.GetReflection()->GetUnknownFields(to);
+ EXPECT_EQ(1, unknown_field_set.field_count());
+ EXPECT_EQ(1, to.known_map_field().size());
+ EXPECT_EQ(unittest::PROTO2_MAP_ENUM_FOO, to.known_map_field().at(0));
+
+ data.clear();
+ from.Clear();
+ to.SerializeToString(&data);
+ EXPECT_TRUE(from.ParseFromString(data));
+ EXPECT_EQ(0, from.GetReflection()->GetUnknownFields(from).field_count());
+ EXPECT_EQ(1, from.known_map_field().size());
+ EXPECT_EQ(unittest::E_PROTO2_MAP_ENUM_FOO, from.known_map_field().at(0));
+ EXPECT_EQ(1, from.unknown_map_field().size());
+ EXPECT_EQ(unittest::E_PROTO2_MAP_ENUM_EXTRA, from.unknown_map_field().at(0));
+}
+
+TEST(GeneratedMapFieldTest, StandardWireFormat) {
+ unittest::TestMap message;
+ string data = "\x0A\x04\x08\x01\x10\x01";
+
+ EXPECT_TRUE(message.ParseFromString(data));
+ EXPECT_EQ(1, message.map_int32_int32().size());
+ EXPECT_EQ(1, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, UnorderedWireFormat) {
+ unittest::TestMap message;
+
+ // put value before key in wire format
+ string data = "\x0A\x04\x10\x01\x08\x02";
+
+ EXPECT_TRUE(message.ParseFromString(data));
+ EXPECT_EQ(1, message.map_int32_int32().size());
+ EXPECT_EQ(1, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat) {
+ unittest::TestMap message;
+
+ // Two key fields in wire format
+ string data = "\x0A\x06\x08\x01\x08\x02\x10\x01";
+
+ EXPECT_TRUE(message.ParseFromString(data));
+ EXPECT_EQ(1, message.map_int32_int32().size());
+ EXPECT_EQ(1, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) {
+ unittest::TestMap message;
+
+ // Two value fields in wire format
+ string data = "\x0A\x06\x08\x01\x10\x01\x10\x02";
+
+ EXPECT_TRUE(message.ParseFromString(data));
+ EXPECT_EQ(1, message.map_int32_int32().size());
+ EXPECT_EQ(2, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, MissedKeyWireFormat) {
+ unittest::TestMap message;
+
+ // No key field in wire format
+ string data = "\x0A\x02\x10\x01";
+
+ EXPECT_TRUE(message.ParseFromString(data));
+ EXPECT_EQ(1, message.map_int32_int32().size());
+ EXPECT_EQ(1, message.map_int32_int32().at(0));
+}
+
+TEST(GeneratedMapFieldTest, MissedValueWireFormat) {
+ unittest::TestMap message;
+
+ // No value field in wire format
+ string data = "\x0A\x02\x08\x01";
+
+ EXPECT_TRUE(message.ParseFromString(data));
+ EXPECT_EQ(1, message.map_int32_int32().size());
+ EXPECT_EQ(0, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, MissedValueTextFormat) {
+ unittest::TestMap message;
+
+ // No value field in text format
+ string text =
+ "map_int32_foreign_message {\n"
+ " key: 1234567890\n"
+ "}";
+
+ EXPECT_TRUE(google::protobuf::TextFormat::ParseFromString(text, &message));
+ EXPECT_EQ(1, message.map_int32_foreign_message().size());
+ EXPECT_EQ(11, message.ByteSize());
+}
+
+TEST(GeneratedMapFieldTest, UnknownFieldWireFormat) {
+ unittest::TestMap message;
+
+ // Unknown field in wire format
+ string data = "\x0A\x06\x08\x02\x10\x03\x18\x01";
+
+ EXPECT_TRUE(message.ParseFromString(data));
+ EXPECT_EQ(1, message.map_int32_int32().size());
+ EXPECT_EQ(3, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, CorruptedWireFormat) {
+ unittest::TestMap message;
+
+ // corrupted data in wire format
+ string data = "\x0A\x06\x08\x02\x11\x03";
+
+ EXPECT_FALSE(message.ParseFromString(data));
+}
+
+TEST(GeneratedMapFieldTest, IsInitialized) {
+ unittest::TestRequiredMessageMap map_message;
+
+ // Add an uninitialized message.
+ (*map_message.mutable_map_field())[0];
+ EXPECT_FALSE(map_message.IsInitialized());
+
+ // Initialize uninitialized message
+ (*map_message.mutable_map_field())[0].set_a(0);
+ (*map_message.mutable_map_field())[0].set_b(0);
+ (*map_message.mutable_map_field())[0].set_c(0);
+ EXPECT_TRUE(map_message.IsInitialized());
+}
+
+// Generated Message Reflection Test ================================
+
+TEST(GeneratedMapFieldReflectionTest, SpaceUsed) {
+ unittest::TestMap message;
+ MapTestUtil::MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+ reflection_tester.SetMapFieldsViaReflection(&message);
+
+ EXPECT_LT(0, message.GetReflection()->SpaceUsed(message));
+}
+
+TEST(GeneratedMapFieldReflectionTest, Accessors) {
+ // Set every field to a unique value then go back and check all those
+ // values.
+ unittest::TestMap message;
+ MapTestUtil::MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+ reflection_tester.SetMapFieldsViaReflection(&message);
+ MapTestUtil::ExpectMapFieldsSet(message);
+ reflection_tester.ExpectMapFieldsSetViaReflection(message);
+
+ reflection_tester.ModifyMapFieldsViaReflection(&message);
+ MapTestUtil::ExpectMapFieldsModified(message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, Swap) {
+ unittest::TestMap message1;
+ unittest::TestMap message2;
+
+ MapTestUtil::SetMapFields(&message1);
+
+ const Reflection* reflection = message1.GetReflection();
+ reflection->Swap(&message1, &message2);
+
+ MapTestUtil::ExpectClear(message1);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapWithBothSet) {
+ unittest::TestMap message1;
+ unittest::TestMap message2;
+
+ MapTestUtil::SetMapFields(&message1);
+ MapTestUtil::SetMapFields(&message2);
+ MapTestUtil::ModifyMapFields(&message2);
+
+ const Reflection* reflection = message1.GetReflection();
+ reflection->Swap(&message1, &message2);
+
+ MapTestUtil::ExpectMapFieldsModified(message1);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapFields) {
+ unittest::TestMap message1;
+ unittest::TestMap message2;
+
+ MapTestUtil::SetMapFields(&message2);
+
+ vector<const FieldDescriptor*> fields;
+ const Reflection* reflection = message1.GetReflection();
+ reflection->ListFields(message2, &fields);
+ reflection->SwapFields(&message1, &message2, fields);
+
+ MapTestUtil::ExpectMapFieldsSet(message1);
+ MapTestUtil::ExpectClear(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ClearField) {
+ unittest::TestMap message;
+ MapTestUtil::SetMapFields(&message);
+ MapTestUtil::ExpectMapFieldsSet(message);
+
+ MapTestUtil::MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+ reflection_tester.ClearMapFieldsViaReflection(&message);
+ MapTestUtil::ExpectClear(message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, RemoveLast) {
+ unittest::TestMap message;
+ MapTestUtil::MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+
+ MapTestUtil::SetMapFields(&message);
+ MapTestUtil::ExpectMapsSize(message, 2);
+ std::vector<const Message*> expected_entries =
+ MapTestUtil::GetMapEntries(message, 0);
+
+ reflection_tester.RemoveLastMapsViaReflection(&message);
+
+ MapTestUtil::ExpectMapsSize(message, 1);
+ std::vector<const Message*> remained_entries =
+ MapTestUtil::GetMapEntries(message, 0);
+ EXPECT_TRUE(expected_entries == remained_entries);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ReleaseLast) {
+ unittest::TestMap message;
+ const Descriptor* descriptor = message.GetDescriptor();
+ MapTestUtil::MapReflectionTester reflection_tester(descriptor);
+
+ MapTestUtil::SetMapFields(&message);
+
+ MapTestUtil::ExpectMapsSize(message, 2);
+
+ reflection_tester.ReleaseLastMapsViaReflection(&message);
+
+ MapTestUtil::ExpectMapsSize(message, 1);
+
+ // Now test that we actually release the right message.
+ message.Clear();
+ MapTestUtil::SetMapFields(&message);
+
+ MapTestUtil::ExpectMapsSize(message, 2);
+ std::vector<const Message*> expect_last =
+ MapTestUtil::GetMapEntries(message, 1);
+ std::vector<const Message*> release_last =
+ MapTestUtil::GetMapEntriesFromRelease(&message);
+ MapTestUtil::ExpectMapsSize(message, 1);
+ EXPECT_TRUE(expect_last == release_last);
+ for (std::vector<const Message*>::iterator it = release_last.begin();
+ it != release_last.end(); ++it) {
+ delete *it;
+ }
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapElements) {
+ unittest::TestMap message;
+ MapTestUtil::MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+
+ MapTestUtil::SetMapFields(&message);
+
+ // Get pointers of map entries at their original position
+ std::vector<const Message*> entries0 = MapTestUtil::GetMapEntries(message, 0);
+ std::vector<const Message*> entries1 = MapTestUtil::GetMapEntries(message, 1);
+
+ // Swap the first time.
+ reflection_tester.SwapMapsViaReflection(&message);
+
+ // Get pointer of map entry after swap once.
+ std::vector<const Message*> entries0_once =
+ MapTestUtil::GetMapEntries(message, 0);
+ std::vector<const Message*> entries1_once =
+ MapTestUtil::GetMapEntries(message, 1);
+
+ // Test map entries are swapped.
+ MapTestUtil::ExpectMapsSize(message, 2);
+ EXPECT_TRUE(entries0 == entries1_once);
+ EXPECT_TRUE(entries1 == entries0_once);
+
+ // Swap the second time.
+ reflection_tester.SwapMapsViaReflection(&message);
+
+ // Get pointer of map entry after swap once.
+ std::vector<const Message*> entries0_twice =
+ MapTestUtil::GetMapEntries(message, 0);
+ std::vector<const Message*> entries1_twice =
+ MapTestUtil::GetMapEntries(message, 1);
+
+ // Test map entries are swapped back.
+ MapTestUtil::ExpectMapsSize(message, 2);
+ EXPECT_TRUE(entries0 == entries0_twice);
+ EXPECT_TRUE(entries1 == entries1_twice);
+}
+
+TEST(GeneratedMapFieldReflectionTest, MutableUnknownFields) {
+ unittest::TestMap message;
+ MapTestUtil::MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+ reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, EmbedProto2Message) {
+ unittest::TestMessageMap message;
+
+ const FieldDescriptor* map_field =
+ unittest::TestMessageMap::descriptor()->FindFieldByName(
+ "map_int32_message");
+ const FieldDescriptor* value =
+ map_field->message_type()->FindFieldByName("value");
+
+ Message* entry_message =
+ message.GetReflection()->AddMessage(&message, map_field);
+ EXPECT_EQ(
+ &entry_message->GetReflection()->GetMessage(*entry_message, value),
+ reinterpret_cast<const Message*>(&TestAllTypes::default_instance()));
+
+ Message* proto2_message =
+ entry_message->GetReflection()->MutableMessage(entry_message, value);
+ EXPECT_EQ(unittest::TestAllTypes::descriptor(),
+ proto2_message->GetDescriptor());
+ ASSERT_EQ(1, message.map_int32_message().size());
+}
+
+TEST(GeneratedMapFieldReflectionTest, MergeFromClearMapEntry) {
+ unittest::TestMap message;
+ const FieldDescriptor* map_field =
+ unittest::TestMap::descriptor()->FindFieldByName("map_int32_int32");
+ const FieldDescriptor* key =
+ map_field->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value =
+ map_field->message_type()->FindFieldByName("value");
+
+ Message* entry_message1 =
+ message.GetReflection()->AddMessage(&message, map_field);
+ EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
+ EXPECT_FALSE(
+ entry_message1->GetReflection()->HasField(*entry_message1, value));
+
+ Message* entry_message2 =
+ message.GetReflection()->AddMessage(&message, map_field);
+ EXPECT_FALSE(entry_message2->GetReflection()->HasField(*entry_message2, key));
+ EXPECT_FALSE(
+ entry_message2->GetReflection()->HasField(*entry_message2, value));
+
+ entry_message1->MergeFrom(*entry_message2);
+ EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
+ EXPECT_FALSE(
+ entry_message1->GetReflection()->HasField(*entry_message1, value));
+}
+
+TEST(GeneratedMapFieldReflectionTest, MapEntryClear) {
+ unittest::TestMap message;
+ MapTestUtil::MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+ reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, Proto2MapEntryClear) {
+ unittest::TestEnumStartWithNonZeroMap message;
+ const Descriptor* descriptor = message.GetDescriptor();
+ const FieldDescriptor* field_descriptor =
+ descriptor->FindFieldByName("map_field");
+ const FieldDescriptor* value_descriptor =
+ field_descriptor->message_type()->FindFieldByName("value");
+ Message* sub_message =
+ message.GetReflection()->AddMessage(&message, field_descriptor);
+ EXPECT_EQ(1, sub_message->GetReflection()->GetEnumValue(*sub_message,
+ value_descriptor));
+}
+
+// Dynamic Message Test =============================================
+
+class MapFieldInDynamicMessageTest : public testing::Test {
+ protected:
+ const DescriptorPool* pool_;
+ DynamicMessageFactory factory_;
+ const Descriptor* map_descriptor_;
+ const Message* map_prototype_;
+
+ MapFieldInDynamicMessageTest()
+ : pool_(DescriptorPool::generated_pool()), factory_(pool_) {}
+
+ virtual void SetUp() {
+ map_descriptor_ =
+ pool_->FindMessageTypeByName("protobuf_unittest.TestMap");
+ ASSERT_TRUE(map_descriptor_ != NULL);
+ map_prototype_ = factory_.GetPrototype(map_descriptor_);
+ }
+};
+
+TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) {
+ // Check that all fields have independent offsets by setting each
+ // one to a unique value then checking that they all still have those
+ // unique values (i.e. they don't stomp each other).
+ scoped_ptr<Message> message(map_prototype_->New());
+ MapTestUtil::MapReflectionTester reflection_tester(map_descriptor_);
+
+ reflection_tester.SetMapFieldsViaReflection(message.get());
+ reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, Map) {
+ // Check that map fields work properly.
+ scoped_ptr<Message> message(map_prototype_->New());
+
+ // Check set functions.
+ MapTestUtil::MapReflectionTester reflection_tester(map_descriptor_);
+ reflection_tester.SetMapFieldsViaReflection(message.get());
+ reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) {
+ // Test that SpaceUsed() works properly
+
+ // Since we share the implementation with generated messages, we don't need
+ // to test very much here. Just make sure it appears to be working.
+
+ scoped_ptr<Message> message(map_prototype_->New());
+ MapTestUtil::MapReflectionTester reflection_tester(map_descriptor_);
+
+ int initial_space_used = message->SpaceUsed();
+
+ reflection_tester.SetMapFieldsViaReflection(message.get());
+ EXPECT_LT(initial_space_used, message->SpaceUsed());
+}
+
+// ReflectionOps Test ===============================================
+
+TEST(ReflectionOpsForMapFieldTest, MapSanityCheck) {
+ unittest::TestMap message;
+
+ MapTestUtil::SetMapFields(&message);
+ MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MapCopy) {
+ unittest::TestMap message, message2;
+
+ MapTestUtil::SetMapFields(&message);
+
+ ReflectionOps::Copy(message, &message2);
+
+ MapTestUtil::ExpectMapFieldsSet(message2);
+
+ // Copying from self should be a no-op.
+ ReflectionOps::Copy(message2, &message2);
+ MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MergeMap) {
+ // Note: Copy is implemented in terms of Merge() so technically the Copy
+ // test already tested most of this.
+
+ unittest::TestMap message, message2;
+
+ MapTestUtil::SetMapFields(&message);
+
+ ReflectionOps::Merge(message2, &message);
+
+ MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, ClearMap) {
+ unittest::TestMap message;
+
+ MapTestUtil::SetMapFields(&message);
+
+ ReflectionOps::Clear(&message);
+
+ MapTestUtil::ExpectClear(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MapDiscardUnknownFields) {
+ unittest::TestMap message;
+ MapTestUtil::SetMapFields(&message);
+
+ // Set some unknown fields in message.
+ message.GetReflection()->MutableUnknownFields(&message)->
+ AddVarint(123456, 654321);
+
+ // Discard them.
+ ReflectionOps::DiscardUnknownFields(&message);
+ MapTestUtil::ExpectMapFieldsSet(message);
+
+ EXPECT_EQ(0, message.GetReflection()->
+ GetUnknownFields(message).field_count());
+}
+
+// Wire Format Test =================================================
+
+TEST(WireFormatForMapFieldTest, ParseMap) {
+ unittest::TestMap source, dest;
+ string data;
+
+ // Serialize using the generated code.
+ MapTestUtil::SetMapFields(&source);
+ source.SerializeToString(&data);
+
+ // Parse using WireFormat.
+ io::ArrayInputStream raw_input(data.data(), data.size());
+ io::CodedInputStream input(&raw_input);
+ WireFormat::ParseAndMergePartial(&input, &dest);
+
+ // Check.
+ MapTestUtil::ExpectMapFieldsSet(dest);
+}
+
+TEST(WireFormatForMapFieldTest, MapByteSize) {
+ unittest::TestMap message;
+ MapTestUtil::SetMapFields(&message);
+
+ EXPECT_EQ(message.ByteSize(), WireFormat::ByteSize(message));
+ message.Clear();
+ EXPECT_EQ(0, message.ByteSize());
+ EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatForMapFieldTest, SerializeMap) {
+ unittest::TestMap message;
+ string generated_data;
+ string dynamic_data;
+
+ MapTestUtil::SetMapFields(&message);
+
+ // Serialize using the generated code.
+ {
+ message.ByteSize();
+ io::StringOutputStream raw_output(&generated_data);
+ io::CodedOutputStream output(&raw_output);
+ message.SerializeWithCachedSizes(&output);
+ ASSERT_FALSE(output.HadError());
+ }
+
+ // Serialize using WireFormat.
+ {
+ io::StringOutputStream raw_output(&dynamic_data);
+ io::CodedOutputStream output(&raw_output);
+ int size = WireFormat::ByteSize(message);
+ WireFormat::SerializeWithCachedSizes(message, size, &output);
+ ASSERT_FALSE(output.HadError());
+ }
+
+ // Should be the same.
+ // Don't use EXPECT_EQ here because we're comparing raw binary data and
+ // we really don't want it dumped to stdout on failure.
+ EXPECT_TRUE(dynamic_data == generated_data);
+}
+
+TEST(WireFormatForMapFieldTest, MapParseHelpers) {
+ string data;
+
+ {
+ // Set up.
+ protobuf_unittest::TestMap message;
+ MapTestUtil::SetMapFields(&message);
+ message.SerializeToString(&data);
+ }
+
+ {
+ // Test ParseFromString.
+ protobuf_unittest::TestMap message;
+ EXPECT_TRUE(message.ParseFromString(data));
+ MapTestUtil::ExpectMapFieldsSet(message);
+ }
+
+ {
+ // Test ParseFromIstream.
+ protobuf_unittest::TestMap message;
+ stringstream stream(data);
+ EXPECT_TRUE(message.ParseFromIstream(&stream));
+ EXPECT_TRUE(stream.eof());
+ MapTestUtil::ExpectMapFieldsSet(message);
+ }
+
+ {
+ // Test ParseFromBoundedZeroCopyStream.
+ string data_with_junk(data);
+ data_with_junk.append("some junk on the end");
+ io::ArrayInputStream stream(data_with_junk.data(), data_with_junk.size());
+ protobuf_unittest::TestMap message;
+ EXPECT_TRUE(message.ParseFromBoundedZeroCopyStream(&stream, data.size()));
+ MapTestUtil::ExpectMapFieldsSet(message);
+ }
+
+ {
+ // Test that ParseFromBoundedZeroCopyStream fails (but doesn't crash) if
+ // EOF is reached before the expected number of bytes.
+ io::ArrayInputStream stream(data.data(), data.size());
+ protobuf_unittest::TestAllTypes message;
+ EXPECT_FALSE(
+ message.ParseFromBoundedZeroCopyStream(&stream, data.size() + 1));
+ }
+}
+
+// Text Format Test =================================================
+
+TEST(TextFormatMapTest, SerializeAndParse) {
+ unittest::TestMap source;
+ unittest::TestMap dest;
+ MapTestUtil::SetMapFields(&source);
+ string output;
+
+ // Test compact ASCII
+ TextFormat::Printer printer;
+ printer.PrintToString(source, &output);
+ TextFormat::Parser parser;
+ EXPECT_TRUE(parser.ParseFromString(output, &dest));
+ MapTestUtil::ExpectMapFieldsSet(dest);
+}
+
+
+// arena support =================================================
+TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) {
+ // Allocate a large initial block to avoid mallocs during hooked test.
+ std::vector<char> arena_block(128 * 1024);
+ ArenaOptions options;
+ options.initial_block = arena_block.data();
+ options.initial_block_size = arena_block.size();
+ Arena arena(options);
+ string data;
+ data.reserve(128 * 1024);
+
+ {
+ NoHeapChecker no_heap;
+
+ unittest::TestArenaMap* from =
+ Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+ MapTestUtil::SetArenaMapFields(from);
+ from->SerializeToString(&data);
+
+ unittest::TestArenaMap* to =
+ Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+ to->ParseFromString(data);
+ MapTestUtil::ExpectArenaMapFieldsSet(*to);
+ }
+}
+
+// Use text format parsing and serializing to test reflection api.
+TEST(ArenaTest, RelfectionInTextFormat) {
+ Arena arena;
+ string data;
+
+ TextFormat::Printer printer;
+ TextFormat::Parser parser;
+
+ unittest::TestArenaMap* from =
+ Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+ unittest::TestArenaMap* to =
+ Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+
+ MapTestUtil::SetArenaMapFields(from);
+ printer.PrintToString(*from, &data);
+
+ EXPECT_TRUE(parser.ParseFromString(data, to));
+ MapTestUtil::ExpectArenaMapFieldsSet(*to);
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/map_test_util.cc b/src/google/protobuf/map_test_util.cc
new file mode 100644
index 00000000..1713e373
--- /dev/null
+++ b/src/google/protobuf/map_test_util.cc
@@ -0,0 +1,1265 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/map_test_util.h>
+#include <google/protobuf/map_test_util_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+
+void MapTestUtil::SetMapFields(unittest::TestMap* message) {
+ MapTestUtilImpl::SetMapFields<unittest::MapEnum, unittest::MAP_ENUM_BAR,
+ unittest::MAP_ENUM_BAZ>(message);
+}
+
+void MapTestUtil::SetArenaMapFields(unittest::TestArenaMap* message) {
+ MapTestUtilImpl::SetArenaMapFields<unittest::MapEnum, unittest::MAP_ENUM_BAR,
+ unittest::MAP_ENUM_BAZ>(message);
+}
+
+void MapTestUtil::SetMapFieldsInitialized(unittest::TestMap* message) {
+ MapTestUtilImpl::SetMapFieldsInitialized(message);
+}
+
+void MapTestUtil::ModifyMapFields(unittest::TestMap* message) {
+ MapTestUtilImpl::ModifyMapFields<unittest::MapEnum, unittest::MAP_ENUM_FOO>(
+ message);
+}
+
+void MapTestUtil::ExpectClear(const unittest::TestMap& message) {
+ MapTestUtilImpl::ExpectClear(message);
+}
+
+void MapTestUtil::ExpectMapFieldsSet(const unittest::TestMap& message) {
+ MapTestUtilImpl::ExpectMapFieldsSet<unittest::MapEnum, unittest::MAP_ENUM_BAR,
+ unittest::MAP_ENUM_BAZ>(message);
+}
+
+void MapTestUtil::ExpectArenaMapFieldsSet(
+ const unittest::TestArenaMap& message) {
+ MapTestUtilImpl::ExpectArenaMapFieldsSet<
+ unittest::MapEnum, unittest::MAP_ENUM_BAR, unittest::MAP_ENUM_BAZ>(
+ message);
+}
+
+void MapTestUtil::ExpectMapFieldsSetInitialized(
+ const unittest::TestMap& message) {
+ MapTestUtilImpl::ExpectMapFieldsSetInitialized<unittest::MapEnum,
+ unittest::MAP_ENUM_FOO>(
+ message);
+}
+
+void MapTestUtil::ExpectMapFieldsModified(
+ const unittest::TestMap& message) {
+ MapTestUtilImpl::ExpectMapFieldsModified<
+ unittest::MapEnum, unittest::MAP_ENUM_BAR, unittest::MAP_ENUM_FOO>(
+ message);
+}
+
+void MapTestUtil::ExpectMapsSize(
+ const unittest::TestMap& message, int size) {
+ const Descriptor* descriptor = message.GetDescriptor();
+
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_int32_int32")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_int64_int64")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_uint32_uint32")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_uint64_uint64")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_sint32_sint32")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_sint64_sint64")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_fixed32_fixed32")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_fixed64_fixed64")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_int32_float")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_int32_double")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_bool_bool")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_string_string")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_int32_bytes")));
+ EXPECT_EQ(size, message.GetReflection()->FieldSize(
+ message, descriptor->FindFieldByName("map_int32_foreign_message")));
+}
+
+std::vector<const Message*> MapTestUtil::GetMapEntries(
+ const unittest::TestMap& message, int index) {
+ const Descriptor* descriptor = message.GetDescriptor();
+ std::vector<const Message*> result;
+
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_int32_int32"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_int64_int64"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_uint32_uint32"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_uint64_uint64"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_sint32_sint32"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_sint64_sint64"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_fixed32_fixed32"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_fixed64_fixed64"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_sfixed32_sfixed32"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_sfixed64_sfixed64"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_int32_float"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_int32_double"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_bool_bool"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_string_string"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_int32_bytes"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_int32_enum"), index));
+ result.push_back(&message.GetReflection()->GetRepeatedMessage(
+ message, descriptor->FindFieldByName("map_int32_foreign_message"), index));
+
+ return result;
+}
+
+std::vector<const Message*> MapTestUtil::GetMapEntriesFromRelease(
+ unittest::TestMap* message) {
+ const Descriptor* descriptor = message->GetDescriptor();
+ std::vector<const Message*> result;
+
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_int32_int32")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_int64_int64")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_uint32_uint32")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_uint64_uint64")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_sint32_sint32")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_sint64_sint64")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_fixed32_fixed32")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_fixed64_fixed64")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_int32_float")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_int32_double")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_bool_bool")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_string_string")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_int32_bytes")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_int32_enum")));
+ result.push_back(message->GetReflection()->ReleaseLast(
+ message, descriptor->FindFieldByName("map_int32_foreign_message")));
+
+ return result;
+}
+
+MapTestUtil::MapReflectionTester::MapReflectionTester(
+ const Descriptor* base_descriptor)
+ : base_descriptor_(base_descriptor) {
+ const DescriptorPool* pool = base_descriptor->file()->pool();
+
+ map_enum_foo_ = pool->FindEnumValueByName("protobuf_unittest.MAP_ENUM_FOO");
+ map_enum_bar_ = pool->FindEnumValueByName("protobuf_unittest.MAP_ENUM_BAR");
+ map_enum_baz_ = pool->FindEnumValueByName("protobuf_unittest.MAP_ENUM_BAZ");
+
+ foreign_c_ = pool->FindFieldByName(
+ "protobuf_unittest.ForeignMessage.c");
+ map_int32_int32_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32Int32Entry.key");
+ map_int32_int32_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32Int32Entry.value");
+ map_int64_int64_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt64Int64Entry.key");
+ map_int64_int64_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt64Int64Entry.value");
+ map_uint32_uint32_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapUint32Uint32Entry.key");
+ map_uint32_uint32_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapUint32Uint32Entry.value");
+ map_uint64_uint64_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapUint64Uint64Entry.key");
+ map_uint64_uint64_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapUint64Uint64Entry.value");
+ map_sint32_sint32_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapSint32Sint32Entry.key");
+ map_sint32_sint32_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapSint32Sint32Entry.value");
+ map_sint64_sint64_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapSint64Sint64Entry.key");
+ map_sint64_sint64_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapSint64Sint64Entry.value");
+ map_fixed32_fixed32_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapFixed32Fixed32Entry.key");
+ map_fixed32_fixed32_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapFixed32Fixed32Entry.value");
+ map_fixed64_fixed64_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapFixed64Fixed64Entry.key");
+ map_fixed64_fixed64_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapFixed64Fixed64Entry.value");
+ map_sfixed32_sfixed32_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapSfixed32Sfixed32Entry.key");
+ map_sfixed32_sfixed32_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapSfixed32Sfixed32Entry.value");
+ map_sfixed64_sfixed64_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapSfixed64Sfixed64Entry.key");
+ map_sfixed64_sfixed64_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapSfixed64Sfixed64Entry.value");
+ map_int32_float_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32FloatEntry.key");
+ map_int32_float_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32FloatEntry.value");
+ map_int32_double_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32DoubleEntry.key");
+ map_int32_double_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32DoubleEntry.value");
+ map_bool_bool_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapBoolBoolEntry.key");
+ map_bool_bool_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapBoolBoolEntry.value");
+ map_string_string_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapStringStringEntry.key");
+ map_string_string_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapStringStringEntry.value");
+ map_int32_bytes_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32BytesEntry.key");
+ map_int32_bytes_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32BytesEntry.value");
+ map_int32_enum_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32EnumEntry.key");
+ map_int32_enum_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32EnumEntry.value");
+ map_int32_foreign_message_key_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32ForeignMessageEntry.key");
+ map_int32_foreign_message_val_ = pool->FindFieldByName(
+ "protobuf_unittest.TestMap.MapInt32ForeignMessageEntry.value");
+
+ EXPECT_FALSE(map_enum_foo_ == NULL);
+ EXPECT_FALSE(map_enum_bar_ == NULL);
+ EXPECT_FALSE(map_enum_baz_ == NULL);
+ EXPECT_FALSE(map_int32_int32_key_ == NULL);
+ EXPECT_FALSE(map_int32_int32_val_ == NULL);
+ EXPECT_FALSE(map_int64_int64_key_ == NULL);
+ EXPECT_FALSE(map_int64_int64_val_ == NULL);
+ EXPECT_FALSE(map_uint32_uint32_key_ == NULL);
+ EXPECT_FALSE(map_uint32_uint32_val_ == NULL);
+ EXPECT_FALSE(map_uint64_uint64_key_ == NULL);
+ EXPECT_FALSE(map_uint64_uint64_val_ == NULL);
+ EXPECT_FALSE(map_sint32_sint32_key_ == NULL);
+ EXPECT_FALSE(map_sint32_sint32_val_ == NULL);
+ EXPECT_FALSE(map_sint64_sint64_key_ == NULL);
+ EXPECT_FALSE(map_sint64_sint64_val_ == NULL);
+ EXPECT_FALSE(map_fixed32_fixed32_key_ == NULL);
+ EXPECT_FALSE(map_fixed32_fixed32_val_ == NULL);
+ EXPECT_FALSE(map_fixed64_fixed64_key_ == NULL);
+ EXPECT_FALSE(map_fixed64_fixed64_val_ == NULL);
+ EXPECT_FALSE(map_sfixed32_sfixed32_key_ == NULL);
+ EXPECT_FALSE(map_sfixed32_sfixed32_val_ == NULL);
+ EXPECT_FALSE(map_sfixed64_sfixed64_key_ == NULL);
+ EXPECT_FALSE(map_sfixed64_sfixed64_val_ == NULL);
+ EXPECT_FALSE(map_int32_float_key_ == NULL);
+ EXPECT_FALSE(map_int32_float_val_ == NULL);
+ EXPECT_FALSE(map_int32_double_key_ == NULL);
+ EXPECT_FALSE(map_int32_double_val_ == NULL);
+ EXPECT_FALSE(map_bool_bool_key_ == NULL);
+ EXPECT_FALSE(map_bool_bool_val_ == NULL);
+ EXPECT_FALSE(map_string_string_key_ == NULL);
+ EXPECT_FALSE(map_string_string_val_ == NULL);
+ EXPECT_FALSE(map_int32_bytes_key_ == NULL);
+ EXPECT_FALSE(map_int32_bytes_val_ == NULL);
+ EXPECT_FALSE(map_int32_enum_key_ == NULL);
+ EXPECT_FALSE(map_int32_enum_val_ == NULL);
+ EXPECT_FALSE(map_int32_foreign_message_key_ == NULL);
+ EXPECT_FALSE(map_int32_foreign_message_val_ == NULL);
+}
+
+// Shorthand to get a FieldDescriptor for a field of unittest::TestMap.
+const FieldDescriptor* MapTestUtil::MapReflectionTester::F(const string& name) {
+ const FieldDescriptor* result = NULL;
+ result = base_descriptor_->FindFieldByName(name);
+ GOOGLE_CHECK(result != NULL);
+ return result;
+}
+
+void MapTestUtil::MapReflectionTester::SetMapFieldsViaReflection(
+ Message* message) {
+ const Reflection* reflection = message->GetReflection();
+ Message* sub_message = NULL;
+ Message* sub_foreign_message = NULL;
+
+ // Add first element.
+ sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_int32_key_, 0);
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_int32_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_int64_int64_key_, 0);
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_int64_int64_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_uint32_uint32_key_, 0);
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_uint32_uint32_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_uint64_uint64_key_, 0);
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_uint64_uint64_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sint32_sint32_key_, 0);
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sint32_sint32_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sint64_sint64_key_, 0);
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sint64_sint64_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_fixed32_fixed32_key_, 0);
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_fixed32_fixed32_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_fixed64_fixed64_key_, 0);
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_fixed64_fixed64_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sfixed32_sfixed32_key_, 0);
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sfixed32_sfixed32_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sfixed64_sfixed64_key_, 0);
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sfixed64_sfixed64_val_, 0);
+
+ sub_message = reflection->AddMessage(message, F("map_int32_float"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_float_key_, 0);
+ sub_message->GetReflection()
+ ->SetFloat(sub_message, map_int32_float_val_, 0.0);
+
+ sub_message = reflection->AddMessage(message, F("map_int32_double"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_double_key_, 0);
+ sub_message->GetReflection()
+ ->SetDouble(sub_message, map_int32_double_val_, 0.0);
+
+ sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+ sub_message->GetReflection()
+ ->SetBool(sub_message, map_bool_bool_key_, false);
+ sub_message->GetReflection()
+ ->SetBool(sub_message, map_bool_bool_val_, false);
+
+ sub_message = reflection->AddMessage(message, F("map_string_string"));
+ sub_message->GetReflection()
+ ->SetString(sub_message, map_string_string_key_, "0");
+ sub_message->GetReflection()
+ ->SetString(sub_message, map_string_string_val_, "0");
+
+ sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_bytes_key_, 0);
+ sub_message->GetReflection()
+ ->SetString(sub_message, map_int32_bytes_val_, "0");
+
+ sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_enum_key_, 0);
+ sub_message->GetReflection()
+ ->SetEnum(sub_message, map_int32_enum_val_, map_enum_bar_);
+
+ sub_message = reflection
+ ->AddMessage(message, F("map_int32_foreign_message"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_foreign_message_key_, 0);
+ sub_foreign_message = sub_message->GetReflection()->
+ MutableMessage(sub_message, map_int32_foreign_message_val_, NULL);
+ sub_foreign_message->GetReflection()->
+ SetInt32(sub_foreign_message, foreign_c_, 0);
+
+ // Add second element
+ sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_int32_key_, 1);
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_int32_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_int64_int64_key_, 1);
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_int64_int64_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_uint32_uint32_key_, 1);
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_uint32_uint32_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_uint64_uint64_key_, 1);
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_uint64_uint64_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sint32_sint32_key_, 1);
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sint32_sint32_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sint64_sint64_key_, 1);
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sint64_sint64_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_fixed32_fixed32_key_, 1);
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_fixed32_fixed32_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_fixed64_fixed64_key_, 1);
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_fixed64_fixed64_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sfixed32_sfixed32_key_, 1);
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sfixed32_sfixed32_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sfixed64_sfixed64_key_, 1);
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sfixed64_sfixed64_val_, 1);
+
+ sub_message = reflection->AddMessage(message, F("map_int32_float"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_float_key_, 1);
+ sub_message->GetReflection()
+ ->SetFloat(sub_message, map_int32_float_val_, 1.0);
+
+ sub_message = reflection->AddMessage(message, F("map_int32_double"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_double_key_, 1);
+ sub_message->GetReflection()
+ ->SetDouble(sub_message, map_int32_double_val_, 1.0);
+
+ sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+ sub_message->GetReflection()
+ ->SetBool(sub_message, map_bool_bool_key_, true);
+ sub_message->GetReflection()
+ ->SetBool(sub_message, map_bool_bool_val_, true);
+
+ sub_message = reflection->AddMessage(message, F("map_string_string"));
+ sub_message->GetReflection()
+ ->SetString(sub_message, map_string_string_key_, "1");
+ sub_message->GetReflection()
+ ->SetString(sub_message, map_string_string_val_, "1");
+
+ sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_bytes_key_, 1);
+ sub_message->GetReflection()
+ ->SetString(sub_message, map_int32_bytes_val_, "1");
+
+ sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_enum_key_, 1);
+ sub_message->GetReflection()
+ ->SetEnum(sub_message, map_int32_enum_val_, map_enum_baz_);
+
+ sub_message = reflection
+ ->AddMessage(message, F("map_int32_foreign_message"));
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_foreign_message_key_, 1);
+ sub_foreign_message = sub_message->GetReflection()->
+ MutableMessage(sub_message, map_int32_foreign_message_val_, NULL);
+ sub_foreign_message->GetReflection()->
+ SetInt32(sub_foreign_message, foreign_c_, 1);
+}
+
+void MapTestUtil::MapReflectionTester::ClearMapFieldsViaReflection(
+ Message* message) {
+ const Reflection* reflection = message->GetReflection();
+
+ reflection->ClearField(message, F("map_int32_int32"));
+ reflection->ClearField(message, F("map_int64_int64"));
+ reflection->ClearField(message, F("map_uint32_uint32"));
+ reflection->ClearField(message, F("map_uint64_uint64"));
+ reflection->ClearField(message, F("map_sint32_sint32"));
+ reflection->ClearField(message, F("map_sint64_sint64"));
+ reflection->ClearField(message, F("map_fixed32_fixed32"));
+ reflection->ClearField(message, F("map_fixed64_fixed64"));
+ reflection->ClearField(message, F("map_sfixed32_sfixed32"));
+ reflection->ClearField(message, F("map_sfixed64_sfixed64"));
+ reflection->ClearField(message, F("map_int32_float"));
+ reflection->ClearField(message, F("map_int32_double"));
+ reflection->ClearField(message, F("map_bool_bool"));
+ reflection->ClearField(message, F("map_string_string"));
+ reflection->ClearField(message, F("map_int32_bytes"));
+ reflection->ClearField(message, F("map_int32_enum"));
+ reflection->ClearField(message, F("map_int32_foreign_message"));
+}
+
+void MapTestUtil::MapReflectionTester::ModifyMapFieldsViaReflection(
+ Message* message) {
+ const Reflection* reflection = message->GetReflection();
+ Message* sub_message;
+ Message* sub_foreign_message;
+
+ // Find out which one's key is 0.
+ int size = reflection->FieldSize(*message, F("map_int32_int32"));
+ int target = 0;
+ for (int i = 0; i < size; i++) {
+ const Message& temp_message = reflection
+ ->GetRepeatedMessage(*message, F("map_int32_int32"), i);
+ if (temp_message.GetReflection()
+ ->GetInt32(temp_message, map_int32_int32_key_) == 1) {
+ target = i;
+ }
+ }
+
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_int32_int32"), target);
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_int32_int32_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_int64_int64"), target);
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_int64_int64_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_uint32_uint32"), target);
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_uint32_uint32_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_uint64_uint64"), target);
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_uint64_uint64_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_sint32_sint32"), target);
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sint32_sint32_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_sint64_sint64"), target);
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sint64_sint64_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_fixed32_fixed32"), target);
+ sub_message->GetReflection()
+ ->SetUInt32(sub_message, map_fixed32_fixed32_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_fixed64_fixed64"), target);
+ sub_message->GetReflection()
+ ->SetUInt64(sub_message, map_fixed64_fixed64_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_sfixed32_sfixed32"), target);
+ sub_message->GetReflection()
+ ->SetInt32(sub_message, map_sfixed32_sfixed32_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_sfixed64_sfixed64"), target);
+ sub_message->GetReflection()
+ ->SetInt64(sub_message, map_sfixed64_sfixed64_val_, 2);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_int32_float"), target);
+ sub_message->GetReflection()
+ ->SetFloat(sub_message, map_int32_float_val_, 2.0);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_int32_double"), target);
+ sub_message->GetReflection()
+ ->SetDouble(sub_message, map_int32_double_val_, 2.0);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_bool_bool"), target);
+ sub_message->GetReflection()
+ ->SetBool(sub_message, map_bool_bool_val_, false);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_string_string"), target);
+ sub_message->GetReflection()
+ ->SetString(sub_message, map_string_string_val_, "2");
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_int32_bytes"), target);
+ sub_message->GetReflection()
+ ->SetString(sub_message, map_int32_bytes_val_, "2");
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_int32_enum"), target);
+ sub_message->GetReflection()
+ ->SetEnum(sub_message, map_int32_enum_val_, map_enum_foo_);
+ sub_message = reflection
+ ->MutableRepeatedMessage(message, F("map_int32_foreign_message"), target);
+ sub_foreign_message = sub_message->GetReflection()->
+ MutableMessage(sub_message, map_int32_foreign_message_val_, NULL);
+ sub_foreign_message->GetReflection()->
+ SetInt32(sub_foreign_message, foreign_c_, 2);
+}
+
+void MapTestUtil::MapReflectionTester::RemoveLastMapsViaReflection(
+ Message* message) {
+ const Reflection* reflection = message->GetReflection();
+
+ vector<const FieldDescriptor*> output;
+ reflection->ListFields(*message, &output);
+ for (int i = 0; i < output.size(); ++i) {
+ const FieldDescriptor* field = output[i];
+ if (!field->is_repeated()) continue;
+ reflection->RemoveLast(message, field);
+ }
+}
+
+void MapTestUtil::MapReflectionTester::ReleaseLastMapsViaReflection(
+ Message* message) {
+ const Reflection* reflection = message->GetReflection();
+
+ vector<const FieldDescriptor*> output;
+ reflection->ListFields(*message, &output);
+ for (int i = 0; i < output.size(); ++i) {
+ const FieldDescriptor* field = output[i];
+ if (!field->is_repeated()) continue;
+ if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+ Message* released = reflection->ReleaseLast(message, field);
+ ASSERT_TRUE(released != NULL) << "ReleaseLast returned NULL for: "
+ << field->name();
+ delete released;
+ }
+}
+
+void MapTestUtil::MapReflectionTester::SwapMapsViaReflection(Message* message) {
+ const Reflection* reflection = message->GetReflection();
+ vector<const FieldDescriptor*> output;
+ reflection->ListFields(*message, &output);
+ for (int i = 0; i < output.size(); ++i) {
+ const FieldDescriptor* field = output[i];
+ if (!field->is_repeated()) continue;
+ reflection->SwapElements(message, field, 0, 1);
+ }
+}
+
+void MapTestUtil::MapReflectionTester::
+ MutableUnknownFieldsOfMapFieldsViaReflection(Message* message) {
+ const Reflection* reflection = message->GetReflection();
+ Message* sub_message = NULL;
+
+ sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_int32_float"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_int32_double"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_string_string"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+ sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+ EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+ NULL);
+}
+
+void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection(
+ const Message& message) {
+ string scratch;
+ const Reflection* reflection = message.GetReflection();
+ const Message* sub_message;
+
+ // -----------------------------------------------------------------
+
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_int32")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_int64_int64")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint32_uint32")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint64_uint64")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint32_sint32")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint64_sint64")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed32_fixed32")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed64_fixed64")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_float")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_double")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_bool_bool")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_string_string")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_bytes")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_enum")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_foreign_message")));
+
+ {
+ std::map<int32, int32> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i);
+ int32 key = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_int32_int32_key_);
+ int32 val = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_int32_int32_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int64, int64> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i);
+ int64 key = sub_message->GetReflection()->GetInt64(
+ *sub_message, map_int64_int64_key_);
+ int64 val = sub_message->GetReflection()->GetInt64(
+ *sub_message, map_int64_int64_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<uint32, uint32> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i);
+ uint32 key = sub_message->GetReflection()->GetUInt32(
+ *sub_message, map_uint32_uint32_key_);
+ uint32 val = sub_message->GetReflection()->GetUInt32(
+ *sub_message, map_uint32_uint32_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<uint64, uint64> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i);
+ uint64 key = sub_message->GetReflection()->GetUInt64(
+ *sub_message, map_uint64_uint64_key_);
+ uint64 val = sub_message->GetReflection()->GetUInt64(
+ *sub_message, map_uint64_uint64_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int32, int32> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i);
+ int32 key = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_sint32_sint32_key_);
+ int32 val = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_sint32_sint32_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int64, int64> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i);
+ int64 key = sub_message->GetReflection()->GetInt64(
+ *sub_message, map_sint64_sint64_key_);
+ int64 val = sub_message->GetReflection()->GetInt64(
+ *sub_message, map_sint64_sint64_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<uint32, uint32> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_fixed32_fixed32"), i);
+ uint32 key = sub_message->GetReflection()->GetUInt32(
+ *sub_message, map_fixed32_fixed32_key_);
+ uint32 val = sub_message->GetReflection()->GetUInt32(
+ *sub_message, map_fixed32_fixed32_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<uint64, uint64> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_fixed64_fixed64"), i);
+ uint64 key = sub_message->GetReflection()->GetUInt64(
+ *sub_message, map_fixed64_fixed64_key_);
+ uint64 val = sub_message->GetReflection()->GetUInt64(
+ *sub_message, map_fixed64_fixed64_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int32, int32> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message = &reflection->GetRepeatedMessage(
+ message, F("map_sfixed32_sfixed32"), i);
+ int32 key = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_sfixed32_sfixed32_key_);
+ int32 val = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_sfixed32_sfixed32_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int64, int64> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message = &reflection->GetRepeatedMessage(
+ message, F("map_sfixed64_sfixed64"), i);
+ int64 key = sub_message->GetReflection()->GetInt64(
+ *sub_message, map_sfixed64_sfixed64_key_);
+ int64 val = sub_message->GetReflection()->GetInt64(
+ *sub_message, map_sfixed64_sfixed64_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int32, float> map;
+ map[0] = 0.0;
+ map[1] = 1.0;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_int32_float"), i);
+ int32 key = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_int32_float_key_);
+ float val = sub_message->GetReflection()->GetFloat(
+ *sub_message, map_int32_float_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int32, double> map;
+ map[0] = 0.0;
+ map[1] = 1.0;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_int32_double"), i);
+ int32 key = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_int32_double_key_);
+ double val = sub_message->GetReflection()->GetDouble(
+ *sub_message, map_int32_double_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<bool, bool> map;
+ map[false] = false;
+ map[true] = true;
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i);
+ bool key = sub_message->GetReflection()->GetBool(
+ *sub_message, map_bool_bool_key_);
+ bool val = sub_message->GetReflection()->GetBool(
+ *sub_message, map_bool_bool_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<string, string> map;
+ map["0"] = "0";
+ map["1"] = "1";
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_string_string"), i);
+ string key = sub_message->GetReflection()->GetString(
+ *sub_message, map_string_string_key_);
+ string val = sub_message->GetReflection()->GetString(
+ *sub_message, map_string_string_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int32, string> map;
+ map[0] = "0";
+ map[1] = "1";
+ for (int i = 0; i < 2; i++) {
+ sub_message =
+ &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i);
+ int32 key = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_int32_bytes_key_);
+ string val = sub_message->GetReflection()->GetString(
+ *sub_message, map_int32_bytes_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int32, const EnumValueDescriptor*> map;
+ map[0] = map_enum_bar_;
+ map[1] = map_enum_baz_;
+ for (int i = 0; i < 2; i++) {
+ sub_message = &reflection->GetRepeatedMessage(
+ message, F("map_int32_enum"), i);
+ int32 key = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_int32_enum_key_);
+ const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum(
+ *sub_message, map_int32_enum_val_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+ {
+ std::map<int32, int32> map;
+ map[0] = 0;
+ map[1] = 1;
+ for (int i = 0; i < 2; i++) {
+ sub_message = &reflection->GetRepeatedMessage(
+ message, F("map_int32_foreign_message"), i);
+ int32 key = sub_message->GetReflection()->GetInt32(
+ *sub_message, map_int32_foreign_message_key_);
+ const Message& foreign_message = sub_message->GetReflection()->GetMessage(
+ *sub_message, map_int32_foreign_message_val_);
+ int32 val = foreign_message.GetReflection()->GetInt32(
+ foreign_message, foreign_c_);
+ EXPECT_EQ(map[key], val);
+ }
+ }
+}
+
+void MapTestUtil::MapReflectionTester::ExpectClearViaReflection(
+ const Message& message) {
+ const Reflection* reflection = message.GetReflection();
+ // Map fields are empty.
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_int32")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_int64_int64")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint32_uint32")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint64_uint64")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint32_sint32")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint64_sint64")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed32_fixed32")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed64_fixed64")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_float")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_double")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_bool_bool")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_string_string")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_bytes")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_enum")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message")));
+}
+
+void MapTestUtil::MapReflectionTester::ExpectMapEntryClearViaReflection(
+ Message* message) {
+ const Reflection* reflection = message->GetReflection();
+ const Message* sub_message;
+
+ {
+ const FieldDescriptor* descriptor = F("map_int32_int32");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_int64_int64");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_uint32_uint32");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetUInt32(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetUInt32(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_uint64_uint64");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetUInt64(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetUInt64(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_sint32_sint32");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_sint64_sint64");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_fixed32_fixed32");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetUInt32(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetUInt32(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_fixed64_fixed64");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetUInt64(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetUInt64(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_sfixed32_sfixed32");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_sfixed64_sfixed64");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_int32_float");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_int32_float"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetFloat(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_int32_double");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_int32_double"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetDouble(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_bool_bool");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+ EXPECT_EQ(false, sub_message->GetReflection()->GetBool(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(false, sub_message->GetReflection()->GetBool(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_string_string");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_string_string"));
+ EXPECT_EQ("", sub_message->GetReflection()->GetString(*sub_message,
+ key_descriptor));
+ EXPECT_EQ("", sub_message->GetReflection()->GetString(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_int32_bytes");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ key_descriptor));
+ EXPECT_EQ("", sub_message->GetReflection()->GetString(*sub_message,
+ value_descriptor));
+ }
+ {
+ const FieldDescriptor* descriptor = F("map_int32_enum");
+ const FieldDescriptor* key_descriptor =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* value_descriptor =
+ descriptor->message_type()->FindFieldByName("value");
+ sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+ key_descriptor));
+ EXPECT_EQ(0, sub_message->GetReflection()
+ ->GetEnum(*sub_message, value_descriptor)
+ ->number());
+ }
+ // Map using message as value has been tested in other place. Thus, we don't
+ // test it here.
+}
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h
new file mode 100644
index 00000000..f437e33e
--- /dev/null
+++ b/src/google/protobuf/map_test_util.h
@@ -0,0 +1,156 @@
+// 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_MAP_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
+
+#include <google/protobuf/map_unittest.pb.h>
+
+namespace google {
+namespace protobuf {
+
+namespace unittest = ::protobuf_unittest;
+
+class MapTestUtil {
+ public:
+ // Set every field in the TestMap message to a unique value.
+ static void SetMapFields(unittest::TestMap* message);
+
+ // Set every field in the TestArenaMap message to a unique value.
+ static void SetArenaMapFields(unittest::TestArenaMap* message);
+
+ // Set every field in the message to a default value.
+ static void SetMapFieldsInitialized(unittest::TestMap* message);
+
+ // Modify all the map fields of the messsage (which should already have been
+ // initialized with SetMapFields()).
+ static void ModifyMapFields(unittest::TestMap* message);
+
+ // Check that all fields have the values that they should have after
+ // SetMapFields() is called.
+ static void ExpectMapFieldsSet(const unittest::TestMap& message);
+
+ // Check that all fields have the values that they should have after
+ // SetMapFields() is called for TestArenaMap.
+ static void ExpectArenaMapFieldsSet(const unittest::TestArenaMap& message);
+
+ // Check that all fields have the values that they should have after
+ // SetMapFieldsInitialized() is called.
+ static void ExpectMapFieldsSetInitialized(
+ const unittest::TestMap& message);
+
+ // Expect that the message is modified as would be expected from
+ // ModifyMapFields().
+ static void ExpectMapFieldsModified(const unittest::TestMap& message);
+
+ // Check that all fields are empty.
+ static void ExpectClear(const unittest::TestMap& message);
+
+ // Check that all map fields have the given size.
+ static void ExpectMapsSize(const unittest::TestMap& message, int size);
+
+ // Get pointers of map entries at given index.
+ static std::vector<const Message*> GetMapEntries(
+ const unittest::TestMap& message, int index);
+
+ // Get pointers of map entries from release.
+ static std::vector<const Message*> GetMapEntriesFromRelease(
+ unittest::TestMap* message);
+
+ // Like above, but use the reflection interface.
+ class MapReflectionTester {
+ public:
+ // base_descriptor must be a descriptor for TestMap, which is used for
+ // MapReflectionTester to fetch the FieldDescriptors needed to use the
+ // reflection interface.
+ explicit MapReflectionTester(const Descriptor* base_descriptor);
+
+ void SetMapFieldsViaReflection(Message* message);
+ void ClearMapFieldsViaReflection(Message* message);
+ void ModifyMapFieldsViaReflection(Message* message);
+ void RemoveLastMapsViaReflection(Message* message);
+ void ReleaseLastMapsViaReflection(Message* message);
+ void SwapMapsViaReflection(Message* message);
+ void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message);
+ void ExpectMapFieldsSetViaReflection(const Message& message);
+ void ExpectClearViaReflection(const Message& message);
+ void ExpectMapEntryClearViaReflection(Message* message);
+
+ private:
+ const FieldDescriptor* F(const string& name);
+
+ const Descriptor* base_descriptor_;
+
+ const EnumValueDescriptor* map_enum_bar_;
+ const EnumValueDescriptor* map_enum_baz_;
+ const EnumValueDescriptor* map_enum_foo_;
+
+ const FieldDescriptor* foreign_c_;
+ const FieldDescriptor* map_int32_int32_key_;
+ const FieldDescriptor* map_int32_int32_val_;
+ const FieldDescriptor* map_int64_int64_key_;
+ const FieldDescriptor* map_int64_int64_val_;
+ const FieldDescriptor* map_uint32_uint32_key_;
+ const FieldDescriptor* map_uint32_uint32_val_;
+ const FieldDescriptor* map_uint64_uint64_key_;
+ const FieldDescriptor* map_uint64_uint64_val_;
+ const FieldDescriptor* map_sint32_sint32_key_;
+ const FieldDescriptor* map_sint32_sint32_val_;
+ const FieldDescriptor* map_sint64_sint64_key_;
+ const FieldDescriptor* map_sint64_sint64_val_;
+ const FieldDescriptor* map_fixed32_fixed32_key_;
+ const FieldDescriptor* map_fixed32_fixed32_val_;
+ const FieldDescriptor* map_fixed64_fixed64_key_;
+ const FieldDescriptor* map_fixed64_fixed64_val_;
+ const FieldDescriptor* map_sfixed32_sfixed32_key_;
+ const FieldDescriptor* map_sfixed32_sfixed32_val_;
+ const FieldDescriptor* map_sfixed64_sfixed64_key_;
+ const FieldDescriptor* map_sfixed64_sfixed64_val_;
+ const FieldDescriptor* map_int32_float_key_;
+ const FieldDescriptor* map_int32_float_val_;
+ const FieldDescriptor* map_int32_double_key_;
+ const FieldDescriptor* map_int32_double_val_;
+ const FieldDescriptor* map_bool_bool_key_;
+ const FieldDescriptor* map_bool_bool_val_;
+ const FieldDescriptor* map_string_string_key_;
+ const FieldDescriptor* map_string_string_val_;
+ const FieldDescriptor* map_int32_bytes_key_;
+ const FieldDescriptor* map_int32_bytes_val_;
+ const FieldDescriptor* map_int32_enum_key_;
+ const FieldDescriptor* map_int32_enum_val_;
+ const FieldDescriptor* map_int32_foreign_message_key_;
+ const FieldDescriptor* map_int32_foreign_message_val_;
+ };
+};
+
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
diff --git a/src/google/protobuf/map_test_util_impl.h b/src/google/protobuf/map_test_util_impl.h
new file mode 100644
index 00000000..5e7882a1
--- /dev/null
+++ b/src/google/protobuf/map_test_util_impl.h
@@ -0,0 +1,474 @@
+// 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_MAP_TEST_UTIL_IMPL_H__
+#define GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__
+
+#include <google/protobuf/stubs/common.h>
+
+
+#define EXPECT_TRUE GOOGLE_CHECK
+#define ASSERT_TRUE GOOGLE_CHECK
+#define EXPECT_FALSE(COND) GOOGLE_CHECK(!(COND))
+#define EXPECT_EQ GOOGLE_CHECK_EQ
+#define ASSERT_EQ GOOGLE_CHECK_EQ
+
+namespace google {
+namespace protobuf_unittest {} // forward declaration
+
+namespace protobuf {
+
+namespace unittest = ::protobuf_unittest;
+
+class MapTestUtilImpl {
+ public:
+ // Set every field in the TestMap message to a unique value.
+ template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+ static void SetMapFields(MapMessage* message);
+
+ // Set every field in the TestArenaMap message to a unique value.
+ template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+ static void SetArenaMapFields(MapMessage* message);
+
+ // Set every field in the message to a default value.
+ template <typename MapMessage>
+ static void SetMapFieldsInitialized(MapMessage* message);
+
+ // Modify all the map fields of the messsage (which should already have been
+ // initialized with SetMapFields()).
+ template <typename EnumType, EnumType enum_value, typename MapMessage>
+ static void ModifyMapFields(MapMessage* message);
+
+ // Check that all fields have the values that they should have after
+ // SetMapFields() is called.
+ template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+ static void ExpectMapFieldsSet(const MapMessage& message);
+
+ // Check that all fields have the values that they should have after
+ // SetMapFields() is called for TestArenaMap.
+ template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+ static void ExpectArenaMapFieldsSet(const MapMessage& message);
+
+ // Check that all fields have the values that they should have after
+ // SetMapFieldsInitialized() is called.
+ template <typename EnumType, EnumType enum_value, typename MapMessage>
+ static void ExpectMapFieldsSetInitialized(const MapMessage& message);
+
+ // Expect that the message is modified as would be expected from
+ // ModifyMapFields().
+ template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+ static void ExpectMapFieldsModified(const MapMessage& message);
+
+ // Check that all fields are empty.
+ template <typename MapMessage>
+ static void ExpectClear(const MapMessage& message);
+
+ // // Check that all map fields have the given size.
+ // template <typename MapMessage>
+ // static void ExpectMapsSize(const MapMessage& message, int size);
+
+ // // Get pointers of map entries at given index.
+ // static std::vector<const Message*> GetMapEntries(
+ // const MapMessage& message, int index);
+
+ // // Get pointers of map entries from release.
+ // static std::vector<const Message*> GetMapEntriesFromRelease(
+ // MapMessage* message);
+};
+
+template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::SetMapFields(MapMessage* message) {
+ // Add first element.
+ (*message->mutable_map_int32_int32())[0] = 0;
+ (*message->mutable_map_int64_int64())[0] = 0;
+ (*message->mutable_map_uint32_uint32())[0] = 0;
+ (*message->mutable_map_uint64_uint64())[0] = 0;
+ (*message->mutable_map_sint32_sint32())[0] = 0;
+ (*message->mutable_map_sint64_sint64())[0] = 0;
+ (*message->mutable_map_fixed32_fixed32())[0] = 0;
+ (*message->mutable_map_fixed64_fixed64())[0] = 0;
+ (*message->mutable_map_sfixed32_sfixed32())[0] = 0;
+ (*message->mutable_map_sfixed64_sfixed64())[0] = 0;
+ (*message->mutable_map_int32_float())[0] = 0.0;
+ (*message->mutable_map_int32_double())[0] = 0.0;
+ (*message->mutable_map_bool_bool())[0] = false;
+ (*message->mutable_map_string_string())["0"] = "0";
+ (*message->mutable_map_int32_bytes())[0] = "0";
+ (*message->mutable_map_int32_enum())[0] = enum_value0;
+ (*message->mutable_map_int32_foreign_message())[0].set_c(0);
+
+ // Add second element
+ (*message->mutable_map_int32_int32())[1] = 1;
+ (*message->mutable_map_int64_int64())[1] = 1;
+ (*message->mutable_map_uint32_uint32())[1] = 1;
+ (*message->mutable_map_uint64_uint64())[1] = 1;
+ (*message->mutable_map_sint32_sint32())[1] = 1;
+ (*message->mutable_map_sint64_sint64())[1] = 1;
+ (*message->mutable_map_fixed32_fixed32())[1] = 1;
+ (*message->mutable_map_fixed64_fixed64())[1] = 1;
+ (*message->mutable_map_sfixed32_sfixed32())[1] = 1;
+ (*message->mutable_map_sfixed64_sfixed64())[1] = 1;
+ (*message->mutable_map_int32_float())[1] = 1.0;
+ (*message->mutable_map_int32_double())[1] = 1.0;
+ (*message->mutable_map_bool_bool())[1] = true;
+ (*message->mutable_map_string_string())["1"] = "1";
+ (*message->mutable_map_int32_bytes())[1] = "1";
+ (*message->mutable_map_int32_enum())[1] = enum_value1;
+ (*message->mutable_map_int32_foreign_message())[1].set_c(1);
+}
+
+template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::SetArenaMapFields(MapMessage* message) {
+ // Add first element.
+ (*message->mutable_map_int32_int32())[0] = 0;
+ (*message->mutable_map_int64_int64())[0] = 0;
+ (*message->mutable_map_uint32_uint32())[0] = 0;
+ (*message->mutable_map_uint64_uint64())[0] = 0;
+ (*message->mutable_map_sint32_sint32())[0] = 0;
+ (*message->mutable_map_sint64_sint64())[0] = 0;
+ (*message->mutable_map_fixed32_fixed32())[0] = 0;
+ (*message->mutable_map_fixed64_fixed64())[0] = 0;
+ (*message->mutable_map_sfixed32_sfixed32())[0] = 0;
+ (*message->mutable_map_sfixed64_sfixed64())[0] = 0;
+ (*message->mutable_map_int32_float())[0] = 0.0;
+ (*message->mutable_map_int32_double())[0] = 0.0;
+ (*message->mutable_map_bool_bool())[0] = false;
+ (*message->mutable_map_int32_enum())[0] = enum_value0;
+ (*message->mutable_map_int32_foreign_message())[0].set_c(0);
+
+ // Add second element
+ (*message->mutable_map_int32_int32())[1] = 1;
+ (*message->mutable_map_int64_int64())[1] = 1;
+ (*message->mutable_map_uint32_uint32())[1] = 1;
+ (*message->mutable_map_uint64_uint64())[1] = 1;
+ (*message->mutable_map_sint32_sint32())[1] = 1;
+ (*message->mutable_map_sint64_sint64())[1] = 1;
+ (*message->mutable_map_fixed32_fixed32())[1] = 1;
+ (*message->mutable_map_fixed64_fixed64())[1] = 1;
+ (*message->mutable_map_sfixed32_sfixed32())[1] = 1;
+ (*message->mutable_map_sfixed64_sfixed64())[1] = 1;
+ (*message->mutable_map_int32_float())[1] = 1.0;
+ (*message->mutable_map_int32_double())[1] = 1.0;
+ (*message->mutable_map_bool_bool())[1] = true;
+ (*message->mutable_map_int32_enum())[1] = enum_value1;
+ (*message->mutable_map_int32_foreign_message())[1].set_c(1);
+}
+
+template <typename MapMessage>
+void MapTestUtilImpl::SetMapFieldsInitialized(MapMessage* message) {
+ // Add first element using bracket operator, which should assign default
+ // value automatically.
+ (*message->mutable_map_int32_int32())[0];
+ (*message->mutable_map_int64_int64())[0];
+ (*message->mutable_map_uint32_uint32())[0];
+ (*message->mutable_map_uint64_uint64())[0];
+ (*message->mutable_map_sint32_sint32())[0];
+ (*message->mutable_map_sint64_sint64())[0];
+ (*message->mutable_map_fixed32_fixed32())[0];
+ (*message->mutable_map_fixed64_fixed64())[0];
+ (*message->mutable_map_sfixed32_sfixed32())[0];
+ (*message->mutable_map_sfixed64_sfixed64())[0];
+ (*message->mutable_map_int32_float())[0];
+ (*message->mutable_map_int32_double())[0];
+ (*message->mutable_map_bool_bool())[0];
+ (*message->mutable_map_string_string())["0"];
+ (*message->mutable_map_int32_bytes())[0];
+ (*message->mutable_map_int32_enum())[0];
+ (*message->mutable_map_int32_foreign_message())[0];
+}
+
+template <typename EnumType, EnumType enum_value, typename MapMessage>
+void MapTestUtilImpl::ModifyMapFields(MapMessage* message) {
+ (*message->mutable_map_int32_int32())[1] = 2;
+ (*message->mutable_map_int64_int64())[1] = 2;
+ (*message->mutable_map_uint32_uint32())[1] = 2;
+ (*message->mutable_map_uint64_uint64())[1] = 2;
+ (*message->mutable_map_sint32_sint32())[1] = 2;
+ (*message->mutable_map_sint64_sint64())[1] = 2;
+ (*message->mutable_map_fixed32_fixed32())[1] = 2;
+ (*message->mutable_map_fixed64_fixed64())[1] = 2;
+ (*message->mutable_map_sfixed32_sfixed32())[1] = 2;
+ (*message->mutable_map_sfixed64_sfixed64())[1] = 2;
+ (*message->mutable_map_int32_float())[1] = 2.0;
+ (*message->mutable_map_int32_double())[1] = 2.0;
+ (*message->mutable_map_bool_bool())[1] = false;
+ (*message->mutable_map_string_string())["1"] = "2";
+ (*message->mutable_map_int32_bytes())[1] = "2";
+ (*message->mutable_map_int32_enum())[1] = enum_value;
+ (*message->mutable_map_int32_foreign_message())[1].set_c(2);
+}
+
+template <typename MapMessage>
+void MapTestUtilImpl::ExpectClear(const MapMessage& message) {
+ EXPECT_EQ(0, message.map_int32_int32().size());
+ EXPECT_EQ(0, message.map_int64_int64().size());
+ EXPECT_EQ(0, message.map_uint32_uint32().size());
+ EXPECT_EQ(0, message.map_uint64_uint64().size());
+ EXPECT_EQ(0, message.map_sint32_sint32().size());
+ EXPECT_EQ(0, message.map_sint64_sint64().size());
+ EXPECT_EQ(0, message.map_fixed32_fixed32().size());
+ EXPECT_EQ(0, message.map_fixed64_fixed64().size());
+ EXPECT_EQ(0, message.map_sfixed32_sfixed32().size());
+ EXPECT_EQ(0, message.map_sfixed64_sfixed64().size());
+ EXPECT_EQ(0, message.map_int32_float().size());
+ EXPECT_EQ(0, message.map_int32_double().size());
+ EXPECT_EQ(0, message.map_bool_bool().size());
+ EXPECT_EQ(0, message.map_string_string().size());
+ EXPECT_EQ(0, message.map_int32_bytes().size());
+ EXPECT_EQ(0, message.map_int32_enum().size());
+ EXPECT_EQ(0, message.map_int32_foreign_message().size());
+}
+
+
+
+template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::ExpectMapFieldsSet(const MapMessage& message) {
+ EXPECT_EQ(2, message.map_int32_int32().size());
+ EXPECT_EQ(2, message.map_int64_int64().size());
+ EXPECT_EQ(2, message.map_uint32_uint32().size());
+ EXPECT_EQ(2, message.map_uint64_uint64().size());
+ EXPECT_EQ(2, message.map_sint32_sint32().size());
+ EXPECT_EQ(2, message.map_sint64_sint64().size());
+ EXPECT_EQ(2, message.map_fixed32_fixed32().size());
+ EXPECT_EQ(2, message.map_fixed64_fixed64().size());
+ EXPECT_EQ(2, message.map_sfixed32_sfixed32().size());
+ EXPECT_EQ(2, message.map_sfixed64_sfixed64().size());
+ EXPECT_EQ(2, message.map_int32_float().size());
+ EXPECT_EQ(2, message.map_int32_double().size());
+ EXPECT_EQ(2, message.map_bool_bool().size());
+ EXPECT_EQ(2, message.map_string_string().size());
+ EXPECT_EQ(2, message.map_int32_bytes().size());
+ EXPECT_EQ(2, message.map_int32_enum().size());
+ EXPECT_EQ(2, message.map_int32_foreign_message().size());
+
+ EXPECT_EQ(0, message.map_int32_int32().at(0));
+ EXPECT_EQ(0, message.map_int64_int64().at(0));
+ EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+ EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+ EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+ EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+ EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+ EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+ EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+ EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+ EXPECT_EQ(0, message.map_int32_float().at(0));
+ EXPECT_EQ(0, message.map_int32_double().at(0));
+ EXPECT_EQ(false, message.map_bool_bool().at(0));
+ EXPECT_EQ("0", message.map_string_string().at("0"));
+ EXPECT_EQ("0", message.map_int32_bytes().at(0));
+ EXPECT_EQ(enum_value0, message.map_int32_enum().at(0));
+ EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c());
+
+ EXPECT_EQ(1, message.map_int32_int32().at(1));
+ EXPECT_EQ(1, message.map_int64_int64().at(1));
+ EXPECT_EQ(1, message.map_uint32_uint32().at(1));
+ EXPECT_EQ(1, message.map_uint64_uint64().at(1));
+ EXPECT_EQ(1, message.map_sint32_sint32().at(1));
+ EXPECT_EQ(1, message.map_sint64_sint64().at(1));
+ EXPECT_EQ(1, message.map_fixed32_fixed32().at(1));
+ EXPECT_EQ(1, message.map_fixed64_fixed64().at(1));
+ EXPECT_EQ(1, message.map_sfixed32_sfixed32().at(1));
+ EXPECT_EQ(1, message.map_sfixed64_sfixed64().at(1));
+ EXPECT_EQ(1, message.map_int32_float().at(1));
+ EXPECT_EQ(1, message.map_int32_double().at(1));
+ EXPECT_EQ(true, message.map_bool_bool().at(1));
+ EXPECT_EQ("1", message.map_string_string().at("1"));
+ EXPECT_EQ("1", message.map_int32_bytes().at(1));
+ EXPECT_EQ(enum_value1, message.map_int32_enum().at(1));
+ EXPECT_EQ(1, message.map_int32_foreign_message().at(1).c());
+}
+
+template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::ExpectArenaMapFieldsSet(const MapMessage& message) {
+ EXPECT_EQ(2, message.map_int32_int32().size());
+ EXPECT_EQ(2, message.map_int64_int64().size());
+ EXPECT_EQ(2, message.map_uint32_uint32().size());
+ EXPECT_EQ(2, message.map_uint64_uint64().size());
+ EXPECT_EQ(2, message.map_sint32_sint32().size());
+ EXPECT_EQ(2, message.map_sint64_sint64().size());
+ EXPECT_EQ(2, message.map_fixed32_fixed32().size());
+ EXPECT_EQ(2, message.map_fixed64_fixed64().size());
+ EXPECT_EQ(2, message.map_sfixed32_sfixed32().size());
+ EXPECT_EQ(2, message.map_sfixed64_sfixed64().size());
+ EXPECT_EQ(2, message.map_int32_float().size());
+ EXPECT_EQ(2, message.map_int32_double().size());
+ EXPECT_EQ(2, message.map_bool_bool().size());
+ EXPECT_EQ(2, message.map_int32_enum().size());
+ EXPECT_EQ(2, message.map_int32_foreign_message().size());
+
+ EXPECT_EQ(0, message.map_int32_int32().at(0));
+ EXPECT_EQ(0, message.map_int64_int64().at(0));
+ EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+ EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+ EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+ EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+ EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+ EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+ EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+ EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+ EXPECT_EQ(0, message.map_int32_float().at(0));
+ EXPECT_EQ(0, message.map_int32_double().at(0));
+ EXPECT_EQ(false, message.map_bool_bool().at(0));
+ EXPECT_EQ(enum_value0, message.map_int32_enum().at(0));
+ EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c());
+
+ EXPECT_EQ(1, message.map_int32_int32().at(1));
+ EXPECT_EQ(1, message.map_int64_int64().at(1));
+ EXPECT_EQ(1, message.map_uint32_uint32().at(1));
+ EXPECT_EQ(1, message.map_uint64_uint64().at(1));
+ EXPECT_EQ(1, message.map_sint32_sint32().at(1));
+ EXPECT_EQ(1, message.map_sint64_sint64().at(1));
+ EXPECT_EQ(1, message.map_fixed32_fixed32().at(1));
+ EXPECT_EQ(1, message.map_fixed64_fixed64().at(1));
+ EXPECT_EQ(1, message.map_sfixed32_sfixed32().at(1));
+ EXPECT_EQ(1, message.map_sfixed64_sfixed64().at(1));
+ EXPECT_EQ(1, message.map_int32_float().at(1));
+ EXPECT_EQ(1, message.map_int32_double().at(1));
+ EXPECT_EQ(true, message.map_bool_bool().at(1));
+ EXPECT_EQ(enum_value1, message.map_int32_enum().at(1));
+ EXPECT_EQ(1, message.map_int32_foreign_message().at(1).c());
+}
+
+template <typename EnumType, EnumType enum_value, typename MapMessage>
+void MapTestUtilImpl::ExpectMapFieldsSetInitialized(
+ const MapMessage& message) {
+ EXPECT_EQ(1, message.map_int32_int32().size());
+ EXPECT_EQ(1, message.map_int64_int64().size());
+ EXPECT_EQ(1, message.map_uint32_uint32().size());
+ EXPECT_EQ(1, message.map_uint64_uint64().size());
+ EXPECT_EQ(1, message.map_sint32_sint32().size());
+ EXPECT_EQ(1, message.map_sint64_sint64().size());
+ EXPECT_EQ(1, message.map_fixed32_fixed32().size());
+ EXPECT_EQ(1, message.map_fixed64_fixed64().size());
+ EXPECT_EQ(1, message.map_sfixed32_sfixed32().size());
+ EXPECT_EQ(1, message.map_sfixed64_sfixed64().size());
+ EXPECT_EQ(1, message.map_int32_float().size());
+ EXPECT_EQ(1, message.map_int32_double().size());
+ EXPECT_EQ(1, message.map_bool_bool().size());
+ EXPECT_EQ(1, message.map_string_string().size());
+ EXPECT_EQ(1, message.map_int32_bytes().size());
+ EXPECT_EQ(1, message.map_int32_enum().size());
+ EXPECT_EQ(1, message.map_int32_foreign_message().size());
+
+ EXPECT_EQ(0, message.map_int32_int32().at(0));
+ EXPECT_EQ(0, message.map_int64_int64().at(0));
+ EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+ EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+ EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+ EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+ EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+ EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+ EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+ EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+ EXPECT_EQ(0, message.map_int32_float().at(0));
+ EXPECT_EQ(0, message.map_int32_double().at(0));
+ EXPECT_EQ(false, message.map_bool_bool().at(0));
+ EXPECT_EQ("", message.map_string_string().at("0"));
+ EXPECT_EQ("", message.map_int32_bytes().at(0));
+ EXPECT_EQ(enum_value, message.map_int32_enum().at(0));
+ EXPECT_EQ(0, message.map_int32_foreign_message().at(0).ByteSize());
+}
+
+template <typename EnumType, EnumType enum_value0,
+ EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::ExpectMapFieldsModified(
+ const MapMessage& message) {
+ // ModifyMapFields only sets the second element of each field. In addition to
+ // verifying this, we also verify that the first element and size were *not*
+ // modified.
+ EXPECT_EQ(2, message.map_int32_int32().size());
+ EXPECT_EQ(2, message.map_int64_int64().size());
+ EXPECT_EQ(2, message.map_uint32_uint32().size());
+ EXPECT_EQ(2, message.map_uint64_uint64().size());
+ EXPECT_EQ(2, message.map_sint32_sint32().size());
+ EXPECT_EQ(2, message.map_sint64_sint64().size());
+ EXPECT_EQ(2, message.map_fixed32_fixed32().size());
+ EXPECT_EQ(2, message.map_fixed64_fixed64().size());
+ EXPECT_EQ(2, message.map_sfixed32_sfixed32().size());
+ EXPECT_EQ(2, message.map_sfixed64_sfixed64().size());
+ EXPECT_EQ(2, message.map_int32_float().size());
+ EXPECT_EQ(2, message.map_int32_double().size());
+ EXPECT_EQ(2, message.map_bool_bool().size());
+ EXPECT_EQ(2, message.map_string_string().size());
+ EXPECT_EQ(2, message.map_int32_bytes().size());
+ EXPECT_EQ(2, message.map_int32_enum().size());
+ EXPECT_EQ(2, message.map_int32_foreign_message().size());
+
+ EXPECT_EQ(0, message.map_int32_int32().at(0));
+ EXPECT_EQ(0, message.map_int64_int64().at(0));
+ EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+ EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+ EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+ EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+ EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+ EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+ EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+ EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+ EXPECT_EQ(0, message.map_int32_float().at(0));
+ EXPECT_EQ(0, message.map_int32_double().at(0));
+ EXPECT_EQ(false, message.map_bool_bool().at(0));
+ EXPECT_EQ("0", message.map_string_string().at("0"));
+ EXPECT_EQ("0", message.map_int32_bytes().at(0));
+ EXPECT_EQ(enum_value0, message.map_int32_enum().at(0));
+ EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c());
+
+ // Actually verify the second (modified) elements now.
+ EXPECT_EQ(2, message.map_int32_int32().at(1));
+ EXPECT_EQ(2, message.map_int64_int64().at(1));
+ EXPECT_EQ(2, message.map_uint32_uint32().at(1));
+ EXPECT_EQ(2, message.map_uint64_uint64().at(1));
+ EXPECT_EQ(2, message.map_sint32_sint32().at(1));
+ EXPECT_EQ(2, message.map_sint64_sint64().at(1));
+ EXPECT_EQ(2, message.map_fixed32_fixed32().at(1));
+ EXPECT_EQ(2, message.map_fixed64_fixed64().at(1));
+ EXPECT_EQ(2, message.map_sfixed32_sfixed32().at(1));
+ EXPECT_EQ(2, message.map_sfixed64_sfixed64().at(1));
+ EXPECT_EQ(2, message.map_int32_float().at(1));
+ EXPECT_EQ(2, message.map_int32_double().at(1));
+ EXPECT_EQ(false, message.map_bool_bool().at(1));
+ EXPECT_EQ("2", message.map_string_string().at("1"));
+ EXPECT_EQ("2", message.map_int32_bytes().at(1));
+ EXPECT_EQ(enum_value1, message.map_int32_enum().at(1));
+ EXPECT_EQ(2, message.map_int32_foreign_message().at(1).c());
+}
+
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
new file mode 100644
index 00000000..278b78ae
--- /dev/null
+++ b/src/google/protobuf/map_type_handler.h
@@ -0,0 +1,516 @@
+// 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_TYPE_HANDLER_H__
+#define GOOGLE_PROTOBUF_TYPE_HANDLER_H__
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Used for compile time type selection. MapIf::type will be TrueType if Flag is
+// true and FalseType otherwise.
+template<bool Flag, typename TrueType, typename FalseType>
+struct MapIf;
+
+template<typename TrueType, typename FalseType>
+struct MapIf<true, TrueType, FalseType> {
+ typedef TrueType type;
+};
+
+template<typename TrueType, typename FalseType>
+struct MapIf<false, TrueType, FalseType> {
+ typedef FalseType type;
+};
+
+// In MapField, string and message are stored as pointer while others are stored
+// as object. However, google::protobuf::Map has unified api. Functions in this class
+// convert key/value to type wanted in api regardless how it's stored
+// internally.
+template <typename Type>
+class MapCommonTypeHandler {
+ public:
+ static inline Type& Reference(Type* x) { return *x; }
+ static inline Type& Reference(Type& x) { return x; }
+ static inline const Type& Reference(const Type& x) { return x; }
+ static inline Type* Pointer(Type* x) { return x; }
+ static inline Type* Pointer(Type& x) { return &x; }
+ static inline const Type* Pointer(const Type* x) { return x; }
+ static inline const Type* Pointer(const Type& x) { return &x; }
+};
+
+// In proto2 Map, enum needs to be initialized to given default value, while
+// other types' default value can be inferred from the type.
+template <bool IsEnum, typename Type>
+class MapValueInitializer {
+ public:
+ static inline void Initialize(Type& type, int default_enum_value);
+};
+
+template <typename Type>
+class MapValueInitializer<true, Type> {
+ public:
+ static inline void Initialize(Type& value, int default_enum_value) {
+ value = static_cast<Type>(default_enum_value);
+ }
+};
+
+template <typename Type>
+class MapValueInitializer<false, Type> {
+ public:
+ static inline void Initialize(Type& value, int default_enum_value) {}
+};
+
+template <typename Type, bool is_arena_constructable>
+class MapArenaMessageCreator {
+ public:
+ // Use arena to create message if Type is arena constructable. Otherwise,
+ // create the message on heap.
+ static inline Type* CreateMessage(Arena* arena);
+};
+template <typename Type>
+class MapArenaMessageCreator<Type, true> {
+ public:
+ static inline Type* CreateMessage(Arena* arena) {
+ return Arena::CreateMessage<Type>(arena);
+ }
+};
+template <typename Type>
+class MapArenaMessageCreator<Type, false> {
+ public:
+ static inline Type* CreateMessage(Arena* arena) {
+ return new Type;
+ }
+};
+
+// Handlers for key/value stored type in MapField. ==================
+
+// Handler for message
+template <typename Type>
+class MapCppTypeHandler : public MapCommonTypeHandler<Type> {
+ public:
+ static const bool kIsStringOrMessage = true;
+ // SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding
+ // those already calculate in sizeof(MapField).
+ static int SpaceUsedInMapEntry(const Type* value) {
+ return value->SpaceUsed();
+ }
+ // Return bytes used by value in Map.
+ static int SpaceUsedInMap(const Type& value) { return value.SpaceUsed(); }
+ static inline void Clear(Type** value) {
+ if (*value != NULL) (*value)->Type::Clear();
+ }
+ static inline void ClearMaybeByDefaultEnum(Type** value,
+ int default_enum_value) {
+ if (*value != NULL) (*value)->Type::Clear();
+ }
+ static inline void Merge(const Type& from, Type** to) {
+ (*to)->MergeFrom(from);
+ }
+
+ static void Delete(const Type* ptr) { delete ptr; }
+
+ // Assign default value to given instance.
+ static inline void AssignDefaultValue(Type** value) {
+ *value = const_cast<Type*>(&Type::default_instance());
+ }
+ // Initialize value when constructing MapEntry
+ static inline void Initialize(Type** x, Arena* arena) { *x = NULL; }
+ // Same as above, but use default_enum_value to initialize enum type value.
+ static inline void InitializeMaybeByDefaultEnum(
+ Type** x, int default_enum_value, Arena* arena) {
+ *x = NULL;
+ }
+ // Initialize value for the first time mutable accessor is called.
+ static inline void EnsureMutable(Type** value, Arena* arena) {
+ if (*value == NULL) {
+ *value =
+ MapArenaMessageCreator<Type, Arena::is_arena_constructable<Type>::
+ type::value>::CreateMessage(arena);
+ }
+ }
+ // Return default instance if value is not initialized when calling const
+ // reference accessor.
+ static inline const Type& DefaultIfNotInitialized(const Type* value,
+ const Type* default_value) {
+ return value != NULL ? *value : *default_value;
+ }
+ // Check if all required fields have values set.
+ static inline bool IsInitialized(Type* value) {
+ return value->IsInitialized();
+ }
+};
+
+// Handler for string.
+template <>
+class MapCppTypeHandler<string> : public MapCommonTypeHandler<string> {
+ public:
+ static const bool kIsStringOrMessage = true;
+ static inline void Merge(const string& from, string** to) { **to = from; }
+ static inline void Clear(string** value) { (*value)->clear(); }
+ static inline void ClearMaybeByDefaultEnum(string** value, int default_enum) {
+ (*value)->clear();
+ }
+ static inline int SpaceUsedInMapEntry(const string* value) {
+ return sizeof(*value) + StringSpaceUsedExcludingSelf(*value);
+ }
+ static inline int SpaceUsedInMap(const string& value) {
+ return sizeof(value) + StringSpaceUsedExcludingSelf(value);
+ }
+ static void Delete(const string* ptr) {
+ if (ptr != &::google::protobuf::internal::GetEmptyString()) delete ptr;
+ }
+ static inline void AssignDefaultValue(string** value) {}
+ static inline void Initialize(string** value, Arena* arena) {
+ *value = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyString());
+ if (arena != NULL) arena->Own(*value);
+ }
+ static inline void InitializeMaybeByDefaultEnum(
+ string** value, int default_enum_value, Arena* arena) {
+ *value = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyString());
+ if (arena != NULL) arena->Own(*value);
+ }
+ static inline void EnsureMutable(string** value, Arena* arena) {
+ if (*value == &::google::protobuf::internal::GetEmptyString()) {
+ *value = Arena::Create<string>(arena);
+ }
+ }
+ static inline const string& DefaultIfNotInitialized(
+ const string* value,
+ const string* default_value) {
+ return value != default_value ? *value : *default_value;
+ }
+ static inline bool IsInitialized(string* value) { return true; }
+};
+
+// Base class for primitive type handlers.
+template <typename Type>
+class MapPrimitiveTypeHandler : public MapCommonTypeHandler<Type> {
+ public:
+ static const bool kIsStringOrMessage = false;
+ static inline void Delete(const Type& x) {}
+ static inline void Merge(const Type& from, Type* to) { *to = from; }
+ static inline int SpaceUsedInMapEntry(const Type& value) { return 0; }
+ static inline int SpaceUsedInMap(const Type& value) { return sizeof(Type); }
+ static inline void AssignDefaultValue(Type* value) {}
+ static inline const Type& DefaultIfNotInitialized(
+ const Type& value, const Type& default_value) {
+ return value;
+ }
+ static inline bool IsInitialized(const Type& value) { return true; }
+};
+
+// Handlers for primitive types.
+#define PRIMITIVE_HANDLER(CType) \
+ template <> \
+ class MapCppTypeHandler<CType> : public MapPrimitiveTypeHandler<CType> { \
+ public: \
+ static inline void Clear(CType* value) { *value = 0; } \
+ static inline void ClearMaybeByDefaultEnum(CType* value, \
+ int default_enum_value) { \
+ *value = static_cast<CType>(default_enum_value); \
+ } \
+ static inline void Initialize(CType* value, Arena* arena) { *value = 0; } \
+ static inline void InitializeMaybeByDefaultEnum(CType* value, \
+ int default_enum_value, \
+ Arena* arena) { \
+ *value = static_cast<CType>(default_enum_value); \
+ } \
+ static inline void EnsureMutable(CType* value, Arena* arena) {} \
+ };
+
+PRIMITIVE_HANDLER(int32 )
+PRIMITIVE_HANDLER(int64 )
+PRIMITIVE_HANDLER(uint32)
+PRIMITIVE_HANDLER(uint64)
+PRIMITIVE_HANDLER(double)
+PRIMITIVE_HANDLER(float )
+PRIMITIVE_HANDLER(bool )
+
+#undef PRIMITIVE_HANDLER
+
+// Define constants for given wire field type
+template <WireFormatLite::FieldType field_type>
+class MapWireFieldTypeTraits {};
+
+#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum) \
+ template <> \
+ class MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType> { \
+ public: \
+ typedef CType CppType; \
+ static const bool kIsMessage = IsMessage; \
+ static const bool kIsEnum = IsEnum; \
+ static const WireFormatLite::WireType kWireType = \
+ WireFormatLite::WIRETYPE_##WireFormatType; \
+ };
+
+TYPE_TRAITS(MESSAGE , MessageLite, LENGTH_DELIMITED, true, false)
+TYPE_TRAITS(STRING , string , LENGTH_DELIMITED, false, false)
+TYPE_TRAITS(BYTES , string , LENGTH_DELIMITED, false, false)
+TYPE_TRAITS(INT64 , int64 , VARINT , false, false)
+TYPE_TRAITS(UINT64 , uint64 , VARINT , false, false)
+TYPE_TRAITS(INT32 , int32 , VARINT , false, false)
+TYPE_TRAITS(UINT32 , uint32 , VARINT , false, false)
+TYPE_TRAITS(SINT64 , int64 , VARINT , false, false)
+TYPE_TRAITS(SINT32 , int32 , VARINT , false, false)
+TYPE_TRAITS(ENUM , int , VARINT , false, true )
+TYPE_TRAITS(DOUBLE , double , FIXED64, false, false)
+TYPE_TRAITS(FLOAT , float , FIXED32, false, false)
+TYPE_TRAITS(FIXED64 , uint64 , FIXED64, false, false)
+TYPE_TRAITS(FIXED32 , uint32 , FIXED32, false, false)
+TYPE_TRAITS(SFIXED64, int64 , FIXED64, false, false)
+TYPE_TRAITS(SFIXED32, int32 , FIXED32, false, false)
+TYPE_TRAITS(BOOL , bool , VARINT , false, false)
+
+#undef TYPE_TRAITS
+
+template <WireFormatLite::FieldType field_type>
+class MapWireFieldTypeHandler {
+ public:
+ // Internal stored type in MapEntryLite for given wire field type.
+ typedef typename MapWireFieldTypeTraits<field_type>::CppType CppType;
+ // Corresponding wire type for field type.
+ static const WireFormatLite::WireType kWireType =
+ MapWireFieldTypeTraits<field_type>::kWireType;
+ // Whether wire type is for message.
+ static const bool kIsMessage = MapWireFieldTypeTraits<field_type>::kIsMessage;
+ // Whether wire type is for enum.
+ static const bool kIsEnum = MapWireFieldTypeTraits<field_type>::kIsEnum;
+
+ // Functions used in parsing and serialization. ===================
+ template <typename ValueType>
+ static inline int ByteSize(const ValueType& value);
+ template <typename ValueType>
+ static inline int GetCachedSize(const ValueType& value);
+ template <typename ValueType>
+ static inline bool Read(io::CodedInputStream* input, ValueType* value);
+ static inline void Write(int field, const CppType& value,
+ io::CodedOutputStream* output);
+ static inline uint8* WriteToArray(int field, const CppType& value,
+ uint8* output);
+};
+
+template <>
+template <typename ValueType>
+inline int MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::ByteSize(
+ const ValueType& value) {
+ return WireFormatLite::MessageSizeNoVirtual(value);
+}
+
+#define BYTE_SIZE(FieldType, DeclaredType) \
+ template <> \
+ template <typename ValueType> \
+ inline int \
+ MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::ByteSize( \
+ const ValueType& value) { \
+ return WireFormatLite::DeclaredType##Size(value); \
+ }
+
+BYTE_SIZE(STRING, String)
+BYTE_SIZE(BYTES , Bytes)
+BYTE_SIZE(INT64 , Int64)
+BYTE_SIZE(UINT64, UInt64)
+BYTE_SIZE(INT32 , Int32)
+BYTE_SIZE(UINT32, UInt32)
+BYTE_SIZE(SINT64, SInt64)
+BYTE_SIZE(SINT32, SInt32)
+BYTE_SIZE(ENUM , Enum)
+
+#undef BYTE_SIZE
+
+#define FIXED_BYTE_SIZE(FieldType, DeclaredType) \
+ template <> \
+ template <typename ValueType> \
+ inline int \
+ MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::ByteSize( \
+ const ValueType& value) { \
+ return WireFormatLite::k##DeclaredType##Size; \
+ }
+
+FIXED_BYTE_SIZE(DOUBLE , Double)
+FIXED_BYTE_SIZE(FLOAT , Float)
+FIXED_BYTE_SIZE(FIXED64 , Fixed64)
+FIXED_BYTE_SIZE(FIXED32 , Fixed32)
+FIXED_BYTE_SIZE(SFIXED64, SFixed64)
+FIXED_BYTE_SIZE(SFIXED32, SFixed32)
+FIXED_BYTE_SIZE(BOOL , Bool)
+
+#undef FIXED_BYTE_SIZE
+
+template <>
+template <typename ValueType>
+inline int MapWireFieldTypeHandler<
+ WireFormatLite::TYPE_MESSAGE>::GetCachedSize(const ValueType& value) {
+ return WireFormatLite::LengthDelimitedSize(value.GetCachedSize());
+}
+
+#define GET_CACHED_SIZE(FieldType, DeclaredType) \
+ template <> \
+ template <typename ValueType> \
+ inline int \
+ MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::GetCachedSize( \
+ const ValueType& value) { \
+ return WireFormatLite::DeclaredType##Size(value); \
+ }
+
+GET_CACHED_SIZE(STRING, String)
+GET_CACHED_SIZE(BYTES , Bytes)
+GET_CACHED_SIZE(INT64 , Int64)
+GET_CACHED_SIZE(UINT64, UInt64)
+GET_CACHED_SIZE(INT32 , Int32)
+GET_CACHED_SIZE(UINT32, UInt32)
+GET_CACHED_SIZE(SINT64, SInt64)
+GET_CACHED_SIZE(SINT32, SInt32)
+GET_CACHED_SIZE(ENUM , Enum)
+
+#undef GET_CACHED_SIZE
+
+#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType) \
+ template <> \
+ template <typename ValueType> \
+ inline int \
+ MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::GetCachedSize( \
+ const ValueType& value) { \
+ return WireFormatLite::k##DeclaredType##Size; \
+ }
+
+GET_FIXED_CACHED_SIZE(DOUBLE , Double)
+GET_FIXED_CACHED_SIZE(FLOAT , Float)
+GET_FIXED_CACHED_SIZE(FIXED64 , Fixed64)
+GET_FIXED_CACHED_SIZE(FIXED32 , Fixed32)
+GET_FIXED_CACHED_SIZE(SFIXED64, SFixed64)
+GET_FIXED_CACHED_SIZE(SFIXED32, SFixed32)
+GET_FIXED_CACHED_SIZE(BOOL , Bool)
+
+#undef GET_FIXED_CACHED_SIZE
+
+template <>
+inline void MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::Write(
+ int field, const MessageLite& value, io::CodedOutputStream* output) {
+ WireFormatLite::WriteMessageMaybeToArray(field, value, output);
+}
+
+template <>
+inline uint8*
+MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::WriteToArray(
+ int field, const MessageLite& value, uint8* output) {
+ return WireFormatLite::WriteMessageToArray(field, value, output);
+}
+
+#define WRITE_METHOD(FieldType, DeclaredType) \
+ template <> \
+ inline void \
+ MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::Write( \
+ int field, const CppType& value, io::CodedOutputStream* output) { \
+ return WireFormatLite::Write##DeclaredType(field, value, output); \
+ } \
+ template <> \
+ inline uint8* \
+ MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::WriteToArray( \
+ int field, const CppType& value, uint8* output) { \
+ return WireFormatLite::Write##DeclaredType##ToArray(field, value, output); \
+ }
+
+WRITE_METHOD(STRING , String)
+WRITE_METHOD(BYTES , Bytes)
+WRITE_METHOD(INT64 , Int64)
+WRITE_METHOD(UINT64 , UInt64)
+WRITE_METHOD(INT32 , Int32)
+WRITE_METHOD(UINT32 , UInt32)
+WRITE_METHOD(SINT64 , SInt64)
+WRITE_METHOD(SINT32 , SInt32)
+WRITE_METHOD(ENUM , Enum)
+WRITE_METHOD(DOUBLE , Double)
+WRITE_METHOD(FLOAT , Float)
+WRITE_METHOD(FIXED64 , Fixed64)
+WRITE_METHOD(FIXED32 , Fixed32)
+WRITE_METHOD(SFIXED64, SFixed64)
+WRITE_METHOD(SFIXED32, SFixed32)
+WRITE_METHOD(BOOL , Bool)
+
+#undef WRITE_METHOD
+
+template <>
+template <typename ValueType>
+inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::Read(
+ io::CodedInputStream* input, ValueType* value) {
+ return WireFormatLite::ReadMessageNoVirtual(input, value);
+}
+
+template <>
+template <typename ValueType>
+inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_STRING>::Read(
+ io::CodedInputStream* input, ValueType* value) {
+ return WireFormatLite::ReadString(input, value);
+}
+
+template <>
+template <typename ValueType>
+inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_BYTES>::Read(
+ io::CodedInputStream* input, ValueType* value) {
+ return WireFormatLite::ReadBytes(input, value);
+}
+
+#define READ_METHOD(FieldType) \
+ template <> \
+ template <typename ValueType> \
+ inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::Read( \
+ io::CodedInputStream* input, ValueType* value) { \
+ return WireFormatLite::ReadPrimitive<CppType, \
+ WireFormatLite::TYPE_##FieldType>( \
+ input, value); \
+ }
+
+READ_METHOD(INT64)
+READ_METHOD(UINT64)
+READ_METHOD(INT32)
+READ_METHOD(UINT32)
+READ_METHOD(SINT64)
+READ_METHOD(SINT32)
+READ_METHOD(ENUM)
+READ_METHOD(DOUBLE)
+READ_METHOD(FLOAT)
+READ_METHOD(FIXED64)
+READ_METHOD(FIXED32)
+READ_METHOD(SFIXED64)
+READ_METHOD(SFIXED32)
+READ_METHOD(BOOL)
+
+#undef READ_METHOD
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_TYPE_HANDLER_H__
diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto
new file mode 100644
index 00000000..830f672b
--- /dev/null
+++ b/src/google/protobuf/map_unittest.proto
@@ -0,0 +1,105 @@
+// 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";
+
+option cc_enable_arenas = true;
+
+import "google/protobuf/unittest.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 map_test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+// Tests maps.
+message TestMap {
+ map<int32 , int32 > map_int32_int32 = 1;
+ map<int64 , int64 > map_int64_int64 = 2;
+ map<uint32 , uint32 > map_uint32_uint32 = 3;
+ map<uint64 , uint64 > map_uint64_uint64 = 4;
+ map<sint32 , sint32 > map_sint32_sint32 = 5;
+ map<sint64 , sint64 > map_sint64_sint64 = 6;
+ map<fixed32 , fixed32 > map_fixed32_fixed32 = 7;
+ map<fixed64 , fixed64 > map_fixed64_fixed64 = 8;
+ map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+ map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+ map<int32 , float > map_int32_float = 11;
+ map<int32 , double > map_int32_double = 12;
+ map<bool , bool > map_bool_bool = 13;
+ map<string , string > map_string_string = 14;
+ map<int32 , bytes > map_int32_bytes = 15;
+ map<int32 , MapEnum > map_int32_enum = 16;
+ map<int32 , ForeignMessage> map_int32_foreign_message = 17;
+}
+
+message TestMapSubmessage {
+ optional TestMap test_map = 1;
+}
+
+message TestMessageMap {
+ map<int32, TestAllTypes> map_int32_message = 1;
+}
+
+// Two map fields share the same entry default instance.
+message TestSameTypeMap {
+ map<int32, int32> map1 = 1;
+ map<int32, int32> map2 = 2;
+}
+
+
+enum MapEnum {
+ MAP_ENUM_FOO = 0;
+ MAP_ENUM_BAR = 1;
+ MAP_ENUM_BAZ = 2;
+}
+
+// Test embeded message with required fields
+message TestRequiredMessageMap {
+ map<int32, TestRequired> map_field = 1;
+}
+
+message TestArenaMap {
+ map<int32 , int32 > map_int32_int32 = 1;
+ map<int64 , int64 > map_int64_int64 = 2;
+ map<uint32 , uint32 > map_uint32_uint32 = 3;
+ map<uint64 , uint64 > map_uint64_uint64 = 4;
+ map<sint32 , sint32 > map_sint32_sint32 = 5;
+ map<sint64 , sint64 > map_sint64_sint64 = 6;
+ map<fixed32 , fixed32 > map_fixed32_fixed32 = 7;
+ map<fixed64 , fixed64 > map_fixed64_fixed64 = 8;
+ map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+ map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+ map<int32 , float > map_int32_float = 11;
+ map<int32 , double > map_int32_double = 12;
+ map<bool , bool > map_bool_bool = 13;
+ map<int32 , MapEnum > map_int32_enum = 14;
+ map<int32 , ForeignMessage> map_int32_foreign_message = 15;
+}
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 91e6878e..f58be848 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,6 +32,7 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <iostream>
#include <stack>
#include <google/protobuf/stubs/hash.h>
@@ -39,15 +40,18 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/reflection_internal.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/map-util.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/singleton.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -73,7 +77,7 @@ void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
void Message::CopyFrom(const Message& from) {
const Descriptor* descriptor = GetDescriptor();
GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
- << ": Tried to copy from a message with a different type."
+ << ": Tried to copy from a message with a different type. "
"to: " << descriptor->full_name() << ", "
"from:" << from.GetDescriptor()->full_name();
ReflectionOps::Copy(from, this);
@@ -98,7 +102,7 @@ void Message::FindInitializationErrors(vector<string>* errors) const {
string Message::InitializationErrorString() const {
vector<string> errors;
FindInitializationErrors(&errors);
- return JoinStrings(errors, ", ");
+ return Join(errors, ", ");
}
void Message::CheckInitialized() const {
@@ -147,7 +151,7 @@ int Message::ByteSize() const {
return size;
}
-void Message::SetCachedSize(int size) const {
+void Message::SetCachedSize(int /* size */) const {
GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
<< "\" implements neither SetCachedSize() nor ByteSize(). "
"Must implement one or the other.";
@@ -181,9 +185,78 @@ bool Message::SerializePartialToOstream(ostream* output) const {
}
+// =============================================================================
+// Reflection and associated Template Specializations
+
Reflection::~Reflection() {}
-// ===================================================================
+#define HANDLE_TYPE(TYPE, CPPTYPE, CTYPE) \
+template<> \
+const RepeatedField<TYPE>& Reflection::GetRepeatedField<TYPE>( \
+ const Message& message, const FieldDescriptor* field) const { \
+ return *static_cast<RepeatedField<TYPE>* >( \
+ MutableRawRepeatedField(const_cast<Message*>(&message), \
+ field, CPPTYPE, CTYPE, NULL)); \
+} \
+ \
+template<> \
+RepeatedField<TYPE>* Reflection::MutableRepeatedField<TYPE>( \
+ Message* message, const FieldDescriptor* field) const { \
+ return static_cast<RepeatedField<TYPE>* >( \
+ MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, NULL)); \
+}
+
+HANDLE_TYPE(int32, FieldDescriptor::CPPTYPE_INT32, -1);
+HANDLE_TYPE(int64, FieldDescriptor::CPPTYPE_INT64, -1);
+HANDLE_TYPE(uint32, FieldDescriptor::CPPTYPE_UINT32, -1);
+HANDLE_TYPE(uint64, FieldDescriptor::CPPTYPE_UINT64, -1);
+HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1);
+HANDLE_TYPE(double, FieldDescriptor::CPPTYPE_DOUBLE, -1);
+HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1);
+
+
+#undef HANDLE_TYPE
+
+void* Reflection::MutableRawRepeatedString(
+ Message* message, const FieldDescriptor* field, bool is_string) const {
+ return MutableRawRepeatedField(message, field,
+ FieldDescriptor::CPPTYPE_STRING, FieldOptions::STRING, NULL);
+}
+
+
+// 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
MessageFactory::~MessageFactory() {}
@@ -257,6 +330,7 @@ void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
}
}
+
const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
{
ReaderMutexLock lock(&mutex_);
@@ -314,5 +388,88 @@ 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<internal::RepeatedFieldPrimitiveAccessor<type> >::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<internal::RepeatedPtrFieldStringAccessor>::get();
+ }
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ if (field->is_map()) {
+ return internal::Singleton<internal::MapFieldAccessor>::get();
+ } else {
+ return internal::Singleton<internal::RepeatedPtrFieldMessageAccessor>::get();
+ }
+ }
+ GOOGLE_LOG(FATAL) << "Should not reach here.";
+ return NULL;
+}
+
+namespace internal {
+namespace {
+void ShutdownRepeatedFieldAccessor() {
+ internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<int32> >::ShutDown();
+ internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<uint32> >::ShutDown();
+ internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<int64> >::ShutDown();
+ internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<uint64> >::ShutDown();
+ internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<float> >::ShutDown();
+ internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<double> >::ShutDown();
+ internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<bool> >::ShutDown();
+ internal::Singleton<internal::RepeatedPtrFieldStringAccessor>::ShutDown();
+ internal::Singleton<internal::RepeatedPtrFieldMessageAccessor>::ShutDown();
+ internal::Singleton<internal::MapFieldAccessor>::ShutDown();
+}
+
+struct ShutdownRepeatedFieldRegister {
+ ShutdownRepeatedFieldRegister() {
+ OnShutdown(&ShutdownRepeatedFieldAccessor);
+ }
+} shutdown_;
+
+} // namespace
+} // namespace internal
+
+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 4bbc6418..6e1929e5 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -79,18 +79,19 @@
// // Same as the last block, but do it dynamically via the Message
// // reflection interface.
// Message* foo = new Foo;
-// Descriptor* descriptor = foo->GetDescriptor();
+// const Descriptor* descriptor = foo->GetDescriptor();
//
// // Get the descriptors for the fields we're interested in and verify
// // their types.
-// FieldDescriptor* text_field = descriptor->FindFieldByName("text");
+// const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
// assert(text_field != NULL);
// assert(text_field->type() == FieldDescriptor::TYPE_STRING);
-// assert(text_field->label() == FieldDescriptor::TYPE_OPTIONAL);
-// FieldDescriptor* numbers_field = descriptor->FindFieldByName("numbers");
+// assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
+// const FieldDescriptor* numbers_field = descriptor->
+// FindFieldByName("numbers");
// assert(numbers_field != NULL);
// assert(numbers_field->type() == FieldDescriptor::TYPE_INT32);
-// assert(numbers_field->label() == FieldDescriptor::TYPE_REPEATED);
+// assert(numbers_field->label() == FieldDescriptor::LABEL_REPEATED);
//
// // Parse the message.
// foo->ParseFromString(data);
@@ -109,21 +110,21 @@
#ifndef GOOGLE_PROTOBUF_MESSAGE_H__
#define GOOGLE_PROTOBUF_MESSAGE_H__
-#include <vector>
-#include <string>
-
-#ifdef __DECCXX
-// HP C++'s iosfwd doesn't work.
-#include <iostream>
-#else
#include <iosfwd>
-#endif
+#include <string>
+#include <google/protobuf/stubs/type_traits.h>
+#include <vector>
+#include <google/protobuf/arena.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#define GOOGLE_PROTOBUF_HAS_ONEOF
+#define GOOGLE_PROTOBUF_HAS_ARENAS
+
namespace google {
namespace protobuf {
@@ -133,17 +134,20 @@ class Reflection;
class MessageFactory;
// Defined in other files.
-class Descriptor; // descriptor.h
-class FieldDescriptor; // descriptor.h
-class EnumDescriptor; // descriptor.h
-class EnumValueDescriptor; // descriptor.h
+class UnknownFieldSet; // unknown_field_set.h
namespace io {
class ZeroCopyInputStream; // zero_copy_stream.h
class ZeroCopyOutputStream; // zero_copy_stream.h
class CodedInputStream; // coded_stream.h
class CodedOutputStream; // coded_stream.h
}
-class UnknownFieldSet; // unknown_field_set.h
+
+
+template<typename T>
+class RepeatedField; // repeated_field.h
+
+template<typename T>
+class RepeatedPtrField; // repeated_field.h
// A container to hold message metadata.
struct Metadata {
@@ -151,12 +155,6 @@ struct Metadata {
const Reflection* reflection;
};
-// Returns the EnumDescriptor for enum type E, which must be a
-// proto-declared enum type. Code generated by the protocol compiler
-// will include specializations of this template for each enum type declared.
-template <typename E>
-const EnumDescriptor* GetEnumDescriptor();
-
// Abstract interface for protocol messages.
//
// See also MessageLite, which contains most every-day operations. Message
@@ -179,15 +177,27 @@ 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);".
virtual void CopyFrom(const Message& from);
// Merge the fields from the given message into this message. Singular
- // fields will be overwritten, except for embedded messages which will
- // be merged. Repeated fields will be concatenated. The given message
- // must be of the same type as this message (i.e. the exact same class).
+ // fields will be overwritten, if specified in from, except for embedded
+ // messages which will be merged. Repeated fields will be concatenated.
+ // The given message must be of the same type as this message (i.e. the
+ // exact same class).
virtual void MergeFrom(const Message& from);
// Verifies that IsInitialized() returns true. GOOGLE_CHECK-fails otherwise, with
@@ -198,7 +208,7 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite {
// This is much, much slower than IsInitialized() as it is implemented
// purely via reflection. Generally, you should not call this unless you
// have already determined that an error exists by calling IsInitialized().
- void FindInitializationErrors(vector<string>* errors) const;
+ void FindInitializationErrors(std::vector<string>* errors) const;
// Like FindInitializationErrors, but joins all the strings, delimited by
// commas, and returns them.
@@ -317,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<typename T, typename Enable = void>
+class RepeatedFieldRef;
+
+template<typename T, typename Enable = void>
+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.
@@ -360,18 +384,20 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite {
// write fields from a Reflection without paying attention to the type.
class LIBPROTOBUF_EXPORT Reflection {
public:
- // TODO(kenton): Remove parameter.
inline Reflection() {}
virtual ~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.
@@ -390,7 +416,27 @@ class LIBPROTOBUF_EXPORT Reflection {
virtual void ClearField(Message* message,
const FieldDescriptor* field) const = 0;
- // Remove the last element of a repeated field.
+ // 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.
+ virtual bool HasOneof(const Message& /*message*/,
+ const OneofDescriptor* /*oneof_descriptor*/) const {
+ return false;
+ }
+
+ virtual void ClearOneof(Message* /*message*/,
+ const OneofDescriptor* /*oneof_descriptor*/) const {}
+
+ // Returns the field descriptor if the oneof is set. NULL otherwise.
+ // TODO(jieluo) - make it pure virtual.
+ virtual const FieldDescriptor* GetOneofFieldDescriptor(
+ const Message& /*message*/,
+ const OneofDescriptor* /*oneof_descriptor*/) const {
+ return NULL;
+ }
+
+ // Removes the last element of a repeated field.
// We don't provide a way to remove any element other than the last
// because it invites inefficient use, such as O(n^2) filtering loops
// that should have been O(n). If you want to remove an element other
@@ -399,23 +445,34 @@ class LIBPROTOBUF_EXPORT Reflection {
// call RemoveLast().
virtual void RemoveLast(Message* message,
const FieldDescriptor* field) const = 0;
+ // Removes the last element of a repeated message field, and returns the
+ // pointer to the caller. Caller takes ownership of the returned pointer.
+ virtual Message* ReleaseLast(Message* message,
+ const FieldDescriptor* field) const = 0;
// Swap the complete contents of two messages.
virtual void Swap(Message* message1, Message* message2) const = 0;
+ // Swap fields listed in fields vector of two messages.
+ virtual void SwapFields(Message* message1,
+ Message* message2,
+ const std::vector<const FieldDescriptor*>& fields)
+ const = 0;
+
// Swap two elements of a repeated field.
virtual void SwapElements(Message* message,
- const FieldDescriptor* field,
- int index1,
- int index2) const = 0;
+ const FieldDescriptor* field,
+ int index1,
+ int index2) const = 0;
// List all fields of the message which are currently set. This includes
// extensions. Singular fields will only be listed if HasField(field) would
// return true and repeated fields will only be listed if FieldSize(field)
// would return non-zero. Fields (both normal fields and extension fields)
// will be listed ordered by field number.
- virtual void ListFields(const Message& message,
- vector<const FieldDescriptor*>* output) const = 0;
+ virtual void ListFields(
+ const Message& message,
+ std::vector<const FieldDescriptor*>* output) const = 0;
// Singular field getters ------------------------------------------
// These get the value of a non-repeated field. They return the default
@@ -439,6 +496,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,
@@ -458,7 +524,7 @@ class LIBPROTOBUF_EXPORT Reflection {
// regardless of the field's underlying representation. When initializing
// a newly-constructed string, though, it's just as fast and more readable
// to use code like:
- // string str = reflection->GetString(field);
+ // string str = reflection->GetString(message, field);
virtual const string& GetStringReference(const Message& message,
const FieldDescriptor* field,
string* scratch) const = 0;
@@ -487,6 +553,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
@@ -500,6 +574,23 @@ class LIBPROTOBUF_EXPORT Reflection {
virtual Message* MutableMessage(Message* message,
const FieldDescriptor* field,
MessageFactory* factory = NULL) const = 0;
+ // Replaces the message specified by 'field' with the already-allocated object
+ // sub_message, passing ownership to the message. If the field contained a
+ // message, that message is deleted. If sub_message is NULL, the field is
+ // cleared.
+ virtual void SetAllocatedMessage(Message* message,
+ Message* sub_message,
+ const FieldDescriptor* field) const = 0;
+ // Releases the message specified by 'field' and returns the pointer,
+ // ReleaseMessage() will return the message the message object if it exists.
+ // Otherwise, it may or may not return NULL. In any case, if the return value
+ // is non-NULL, the caller takes ownership of the pointer.
+ // If the field existed (HasField() is true), then the returned pointer will
+ // be the same as the pointer returned by MutableMessage().
+ // This function has the same effect as ClearField().
+ virtual Message* ReleaseMessage(Message* message,
+ const FieldDescriptor* field,
+ MessageFactory* factory = NULL) const = 0;
// Repeated field getters ------------------------------------------
@@ -532,6 +623,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;
@@ -572,6 +671,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(
@@ -601,13 +707,98 @@ 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;
- // Extensions ------------------------------------------------------
+ // 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<typename T>
+ RepeatedFieldRef<T> 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<typename T>
+ MutableRepeatedFieldRef<T> 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
+ // access by exposing the RepeatedField object itself with the Message.
+ // Applying these templates to inappropriate types will lead to an undefined
+ // reference at link time (e.g. GetRepeatedField<***double>), or possibly a
+ // template matching error at compile time (e.g. GetRepeatedPtrField<File>).
+ //
+ // Usage example: my_doubs = refl->GetRepeatedField<double>(msg, fd);
+
+ // DEPRECATED. Please use GetRepeatedFieldRef().
+ //
+ // for T = Cord and all protobuf scalar types except enums.
+ template<typename T>
+ const RepeatedField<T>& GetRepeatedField(
+ const Message&, const FieldDescriptor*) const;
+
+ // DEPRECATED. Please use GetMutableRepeatedFieldRef().
+ //
+ // for T = Cord and all protobuf scalar types except enums.
+ template<typename T>
+ RepeatedField<T>* MutableRepeatedField(
+ Message*, const FieldDescriptor*) const;
+
+ // DEPRECATED. Please use GetRepeatedFieldRef().
+ //
+ // for T = string, google::protobuf::internal::StringPieceField
+ // google::protobuf::Message & descendants.
+ template<typename T>
+ const RepeatedPtrField<T>& GetRepeatedPtrField(
+ const Message&, const FieldDescriptor*) const;
+
+ // DEPRECATED. Please use GetMutableRepeatedFieldRef().
+ //
+ // for T = string, google::protobuf::internal::StringPieceField
+ // google::protobuf::Message & descendants.
+ template<typename T>
+ RepeatedPtrField<T>* MutableRepeatedPtrField(
+ Message*, const FieldDescriptor*) const;
+
+ // Extensions ----------------------------------------------------------------
// Try to find an extension of this message type by fully-qualified field
// name. Returns NULL if no extension is known for this name or number.
@@ -619,7 +810,101 @@ 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; }
+
+ // Returns the MessageFactory associated with this message. This can be
+ // useful for determining if a message is a generated message or not, for
+ // example:
+ //
+ // if (message->GetReflection()->GetMessageFactory() ==
+ // google::protobuf::MessageFactory::generated_factory()) {
+ // // This is a generated message.
+ // }
+ //
+ // It can also be used to create more messages of this type, though
+ // Message::New() is an easier way to accomplish this.
+ virtual MessageFactory* GetMessageFactory() const;
+
+ // ---------------------------------------------------------------------------
+
+ protected:
+ // Obtain a pointer to a Repeated Field Structure and do some type checking:
+ // on field->cpp_type(),
+ // on field->field_option().ctype() (if ctype >= 0)
+ // of field->message_type() (if message_type != NULL).
+ // We use 1 routine rather than 4 (const vs mutable) x (scalar vs pointer).
+ virtual void* MutableRawRepeatedField(
+ Message* message, const FieldDescriptor* field, FieldDescriptor::CppType,
+ int ctype, const Descriptor* message_type) const = 0;
+
+ // 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<typename T, typename Enable>
+ friend class RepeatedFieldRef;
+ template<typename T, typename Enable>
+ 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
+ // file here is not possible because it would cause a circular include cycle.
+ void* MutableRawRepeatedString(
+ Message* message, const FieldDescriptor* field, bool is_string) const;
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection);
};
@@ -636,7 +921,7 @@ class LIBPROTOBUF_EXPORT MessageFactory {
// Calling this method twice with the same Descriptor returns the same
// object. The returned object remains property of the factory. Also, any
// objects created by calling the prototype's New() method share some data
- // with the prototype, so these must be destoyed before the MessageFactory
+ // with the prototype, so these must be destroyed before the MessageFactory
// is destroyed.
//
// The given descriptor must outlive the returned message, and hence must
@@ -682,10 +967,91 @@ class LIBPROTOBUF_EXPORT MessageFactory {
static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
const Message* prototype);
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory);
};
+#define DECLARE_GET_REPEATED_FIELD(TYPE) \
+template<> \
+LIBPROTOBUF_EXPORT \
+const RepeatedField<TYPE>& Reflection::GetRepeatedField<TYPE>( \
+ const Message& message, const FieldDescriptor* field) const; \
+ \
+template<> \
+LIBPROTOBUF_EXPORT \
+RepeatedField<TYPE>* Reflection::MutableRepeatedField<TYPE>( \
+ Message* message, const FieldDescriptor* field) const;
+
+DECLARE_GET_REPEATED_FIELD(int32)
+DECLARE_GET_REPEATED_FIELD(int64)
+DECLARE_GET_REPEATED_FIELD(uint32)
+DECLARE_GET_REPEATED_FIELD(uint64)
+DECLARE_GET_REPEATED_FIELD(float)
+DECLARE_GET_REPEATED_FIELD(double)
+DECLARE_GET_REPEATED_FIELD(bool)
+
+#undef DECLARE_GET_REPEATED_FIELD
+
+// =============================================================================
+// Implementation details for {Get,Mutable}RawRepeatedPtrField. We provide
+// specializations for <string>, <StringPieceField> and <Message> and handle
+// everything else with the default template which will match any type having
+// a method with signature "static const google::protobuf::Descriptor* descriptor()".
+// Such a type presumably is a descendant of google::protobuf::Message.
+
+template<>
+inline const RepeatedPtrField<string>& Reflection::GetRepeatedPtrField<string>(
+ const Message& message, const FieldDescriptor* field) const {
+ return *static_cast<RepeatedPtrField<string>* >(
+ MutableRawRepeatedString(const_cast<Message*>(&message), field, true));
+}
+
+template<>
+inline RepeatedPtrField<string>* Reflection::MutableRepeatedPtrField<string>(
+ Message* message, const FieldDescriptor* field) const {
+ return static_cast<RepeatedPtrField<string>* >(
+ MutableRawRepeatedString(message, field, true));
+}
+
+
+// -----
+
+template<>
+inline const RepeatedPtrField<Message>& Reflection::GetRepeatedPtrField(
+ const Message& message, const FieldDescriptor* field) const {
+ return *static_cast<RepeatedPtrField<Message>* >(
+ MutableRawRepeatedField(const_cast<Message*>(&message), field,
+ FieldDescriptor::CPPTYPE_MESSAGE, -1,
+ NULL));
+}
+
+template<>
+inline RepeatedPtrField<Message>* Reflection::MutableRepeatedPtrField(
+ Message* message, const FieldDescriptor* field) const {
+ return static_cast<RepeatedPtrField<Message>* >(
+ MutableRawRepeatedField(message, field,
+ FieldDescriptor::CPPTYPE_MESSAGE, -1,
+ NULL));
+}
+
+template<typename PB>
+inline const RepeatedPtrField<PB>& Reflection::GetRepeatedPtrField(
+ const Message& message, const FieldDescriptor* field) const {
+ return *static_cast<RepeatedPtrField<PB>* >(
+ MutableRawRepeatedField(const_cast<Message*>(&message), field,
+ FieldDescriptor::CPPTYPE_MESSAGE, -1,
+ PB::default_instance().GetDescriptor()));
+}
+
+template<typename PB>
+inline RepeatedPtrField<PB>* Reflection::MutableRepeatedPtrField(
+ Message* message, const FieldDescriptor* field) const {
+ return static_cast<RepeatedPtrField<PB>* >(
+ MutableRawRepeatedField(message, field,
+ 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 7c8f37dc..63be0e9b 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,11 +34,12 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/message_lite.h>
+#include <google/protobuf/arena.h>
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -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,8 +293,15 @@ 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<uint8*>(string_as_array(output) + old_size);
+ uint8* start =
+ reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size);
uint8* end = SerializeWithCachedSizesToArray(start);
if (end - start != byte_size) {
ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index ebf4ba3c..eab61c14 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -40,10 +40,17 @@
#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/io/coded_stream.h>
+
namespace google {
namespace protobuf {
+ class Arena;
+namespace io {
+ class CodedInputStream;
+ class CodedOutputStream;
+ class ZeroCopyInputStream;
+ class ZeroCopyOutputStream;
+}
// Interface to light weight protocol messages.
//
@@ -82,6 +89,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
@@ -103,11 +131,13 @@ class LIBPROTOBUF_EXPORT MessageLite {
// Parsing ---------------------------------------------------------
// Methods for parsing in protocol buffer format. Most of these are
- // just simple wrappers around MergeFromCodedStream().
+ // just simple wrappers around MergeFromCodedStream(). Clear() will be called
+ // before merging the input.
- // Fill the message with a protocol buffer parsed from the given input
- // stream. Returns false on a read error or if the input is in the
- // wrong format.
+ // Fill the message with a protocol buffer parsed from the given input stream.
+ // Returns false on a read error or if the input is in the wrong format. A
+ // successful return does not indicate the entire input is consumed, ensure
+ // you call ConsumedEntireMessage() to check that if applicable.
bool ParseFromCodedStream(io::CodedInputStream* input);
// Like ParseFromCodedStream(), but accepts messages that are missing
// required fields.
@@ -126,7 +156,11 @@ class LIBPROTOBUF_EXPORT MessageLite {
// missing required fields.
bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
int size);
- // Parse a protocol buffer contained in a string.
+ // Parses a protocol buffer contained in a string. Returns true on success.
+ // This function takes a string in the (non-human-readable) binary wire
+ // format, matching the encoding output by MessageLite::SerializeToString().
+ // If you'd like to convert a human-readable string into a protocol buffer
+ // object, see google::protobuf::TextFormat::ParseFromString().
bool ParseFromString(const string& data);
// Like ParseFromString(), but accepts messages that are missing
// required fields.
@@ -158,6 +192,7 @@ class LIBPROTOBUF_EXPORT MessageLite {
// followed by IsInitialized().
virtual bool MergePartialFromCodedStream(io::CodedInputStream* input) = 0;
+
// Serialization ---------------------------------------------------
// Methods for serializing in protocol buffer format. Most of these
// are just simple wrappers around ByteSize() and SerializeWithCachedSizes().
diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc
index 33b9e77c..ebfb4321 100644
--- a/src/google/protobuf/message_unittest.cc
+++ b/src/google/protobuf/message_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -45,7 +45,6 @@
#include <sstream>
#include <fstream>
-#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/descriptor.h>
@@ -53,6 +52,7 @@
#include <google/protobuf/unittest.pb.h>
#include <google/protobuf/test_util.h>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
@@ -205,7 +205,7 @@ TEST(MessageTest, InitializationErrorString) {
EXPECT_EQ("a, b, c", message.InitializationErrorString());
}
-#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet.
+#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet.
TEST(MessageTest, SerializeFailsIfNotInitialized) {
unittest::TestRequired message;
@@ -222,7 +222,44 @@ TEST(MessageTest, CheckInitialized) {
"fields: a, b, c");
}
-#endif // GTEST_HAS_DEATH_TEST
+TEST(MessageTest, CheckOverflow) {
+ unittest::TestAllTypes message;
+ // Create a message with size just over 2GB. This triggers integer overflow
+ // when computing message size.
+ const string data(1024, 'x');
+ Cord one_megabyte;
+ for (int i = 0; i < 1024; i++) {
+ one_megabyte.Append(data);
+ }
+
+ for (int i = 0; i < 2 * 1024 + 1; ++i) {
+ message.add_repeated_cord()->CopyFrom(one_megabyte);
+ }
+
+ Cord serialized;
+ EXPECT_FALSE(message.AppendToCord(&serialized));
+}
+
+#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;
@@ -257,6 +294,133 @@ TEST(MessageTest, ParseFailsOnInvalidMessageEnd) {
EXPECT_FALSE(message.ParseFromArray("\014", 1));
}
+namespace {
+
+void ExpectMessageMerged(const unittest::TestAllTypes& message) {
+ EXPECT_EQ(3, message.optional_int32());
+ EXPECT_EQ(2, message.optional_int64());
+ EXPECT_EQ("hello", message.optional_string());
+}
+
+void AssignParsingMergeMessages(
+ unittest::TestAllTypes* msg1,
+ unittest::TestAllTypes* msg2,
+ unittest::TestAllTypes* msg3) {
+ msg1->set_optional_int32(1);
+ msg2->set_optional_int64(2);
+ msg3->set_optional_int32(3);
+ msg3->set_optional_string("hello");
+}
+
+} // namespace
+
+// Test that if an optional or required message/group field appears multiple
+// times in the input, they need to be merged.
+TEST(MessageTest, ParsingMerge) {
+ unittest::TestParsingMerge::RepeatedFieldsGenerator generator;
+ unittest::TestAllTypes* msg1;
+ unittest::TestAllTypes* msg2;
+ unittest::TestAllTypes* msg3;
+
+#define ASSIGN_REPEATED_FIELD(FIELD) \
+ msg1 = generator.add_##FIELD(); \
+ msg2 = generator.add_##FIELD(); \
+ msg3 = generator.add_##FIELD(); \
+ AssignParsingMergeMessages(msg1, msg2, msg3)
+
+ ASSIGN_REPEATED_FIELD(field1);
+ ASSIGN_REPEATED_FIELD(field2);
+ ASSIGN_REPEATED_FIELD(field3);
+ ASSIGN_REPEATED_FIELD(ext1);
+ ASSIGN_REPEATED_FIELD(ext2);
+
+#undef ASSIGN_REPEATED_FIELD
+#define ASSIGN_REPEATED_GROUP(FIELD) \
+ msg1 = generator.add_##FIELD()->mutable_field1(); \
+ msg2 = generator.add_##FIELD()->mutable_field1(); \
+ msg3 = generator.add_##FIELD()->mutable_field1(); \
+ AssignParsingMergeMessages(msg1, msg2, msg3)
+
+ ASSIGN_REPEATED_GROUP(group1);
+ ASSIGN_REPEATED_GROUP(group2);
+
+#undef ASSIGN_REPEATED_GROUP
+
+ string buffer;
+ generator.SerializeToString(&buffer);
+ unittest::TestParsingMerge parsing_merge;
+ parsing_merge.ParseFromString(buffer);
+
+ // Required and optional fields should be merged.
+ ExpectMessageMerged(parsing_merge.required_all_types());
+ ExpectMessageMerged(parsing_merge.optional_all_types());
+ ExpectMessageMerged(
+ parsing_merge.optionalgroup().optional_group_all_types());
+ ExpectMessageMerged(
+ parsing_merge.GetExtension(unittest::TestParsingMerge::optional_ext));
+
+ // Repeated fields should not be merged.
+ EXPECT_EQ(3, parsing_merge.repeated_all_types_size());
+ EXPECT_EQ(3, parsing_merge.repeatedgroup_size());
+ EXPECT_EQ(3, parsing_merge.ExtensionSize(
+ unittest::TestParsingMerge::repeated_ext));
+}
+
+TEST(MessageTest, MergeFrom) {
+ unittest::TestAllTypes source;
+ unittest::TestAllTypes dest;
+
+ // Optional fields
+ source.set_optional_int32(1); // only source
+ source.set_optional_int64(2); // both source and dest
+ dest.set_optional_int64(3);
+ dest.set_optional_uint32(4); // only dest
+
+ // Optional fields with defaults
+ source.set_default_int32(13); // only source
+ source.set_default_int64(14); // both source and dest
+ dest.set_default_int64(15);
+ dest.set_default_uint32(16); // only dest
+
+ // Repeated fields
+ source.add_repeated_int32(5); // only source
+ source.add_repeated_int32(6);
+ source.add_repeated_int64(7); // both source and dest
+ source.add_repeated_int64(8);
+ dest.add_repeated_int64(9);
+ dest.add_repeated_int64(10);
+ dest.add_repeated_uint32(11); // only dest
+ dest.add_repeated_uint32(12);
+
+ dest.MergeFrom(source);
+
+ // Optional fields: source overwrites dest if source is specified
+ EXPECT_EQ(1, dest.optional_int32()); // only source: use source
+ EXPECT_EQ(2, dest.optional_int64()); // source and dest: use source
+ EXPECT_EQ(4, dest.optional_uint32()); // only dest: use dest
+ EXPECT_EQ(0, dest.optional_uint64()); // neither: use default
+
+ // Optional fields with defaults
+ EXPECT_EQ(13, dest.default_int32()); // only source: use source
+ EXPECT_EQ(14, dest.default_int64()); // source and dest: use source
+ EXPECT_EQ(16, dest.default_uint32()); // only dest: use dest
+ EXPECT_EQ(44, dest.default_uint64()); // neither: use default
+
+ // Repeated fields: concatenate source onto the end of dest
+ ASSERT_EQ(2, dest.repeated_int32_size());
+ EXPECT_EQ(5, dest.repeated_int32(0));
+ EXPECT_EQ(6, dest.repeated_int32(1));
+ ASSERT_EQ(4, dest.repeated_int64_size());
+ EXPECT_EQ(9, dest.repeated_int64(0));
+ EXPECT_EQ(10, dest.repeated_int64(1));
+ EXPECT_EQ(7, dest.repeated_int64(2));
+ EXPECT_EQ(8, dest.repeated_int64(3));
+ ASSERT_EQ(2, dest.repeated_uint32_size());
+ EXPECT_EQ(11, dest.repeated_uint32(0));
+ EXPECT_EQ(12, dest.repeated_uint32(1));
+ ASSERT_EQ(0, dest.repeated_uint64_size());
+}
+
TEST(MessageFactoryTest, GeneratedFactoryLookup) {
EXPECT_EQ(
MessageFactory::generated_factory()->GetPrototype(
@@ -277,5 +441,6 @@ TEST(MessageFactoryTest, GeneratedFactoryUnknownType) {
MessageFactory::generated_factory()->GetPrototype(descriptor) == NULL);
}
+
} // namespace protobuf
} // namespace google
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 <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/unknown_field_set.h>
+
+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<Container>();
+ }
+ ptr_ = NULL;
+ }
+
+ inline const UnknownFieldSet& unknown_fields() const
+ GOOGLE_ATTRIBUTE_ALWAYS_INLINE {
+ if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) {
+ return PtrValue<Container>()->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<Container>()->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<Container>()->arena_;
+ } else {
+ return PtrValue<Arena>();
+ }
+ }
+
+ 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<intptr_t>(ptr_) & kPtrTagMask;
+ }
+
+ template<typename T> T* PtrValue() const {
+ return reinterpret_cast<T*>(
+ reinterpret_cast<intptr_t>(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<Container>(my_arena);
+ ptr_ = reinterpret_cast<void*>(
+ reinterpret_cast<intptr_t>(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/no_field_presence_test.cc b/src/google/protobuf/no_field_presence_test.cc
new file mode 100644
index 00000000..4b7b31d9
--- /dev/null
+++ b/src/google/protobuf/no_field_presence_test.cc
@@ -0,0 +1,537 @@
+// 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 <string>
+
+#include <google/protobuf/unittest_no_field_presence.pb.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <gtest/gtest.h>
+
+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 field presence of a message field on the default instance.
+ EXPECT_EQ(false, proto2_nofieldpresence_unittest::TestAllTypes::
+ default_instance().has_optional_nested_message());
+}
+
+TEST(NoFieldPresenceTest, ReflectionHasFieldTest) {
+ // 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));
+ }
+
+ // Test field presence of a message field on the default instance.
+ const google::protobuf::FieldDescriptor* msg_field =
+ desc->FindFieldByName("optional_nested_message");
+ EXPECT_EQ(false, r->HasField(
+ proto2_nofieldpresence_unittest::TestAllTypes::
+ default_instance(), msg_field));
+
+ // Fill all fields, expect everything to report true (check oneofs below).
+ FillValues(&message);
+ for (int i = 0; i < desc->field_count(); i++) {
+ 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<char>(0x8a), serialized.at(0));
+ EXPECT_EQ(static_cast<char>(0x07), serialized.at(1));
+ EXPECT_EQ(static_cast<char>(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/package_info.h b/src/google/protobuf/package_info.h
index 60cd3994..935e9639 100644
--- a/src/google/protobuf/package_info.h
+++ b/src/google/protobuf/package_info.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
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..9f8703ae
--- /dev/null
+++ b/src/google/protobuf/preserve_unknown_enum_test.cc
@@ -0,0 +1,289 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_preserve_unknown_enum.pb.h>
+#include <google/protobuf/unittest_preserve_unknown_enum2.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/descriptor.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+void FillMessage(
+ proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra* message) {
+ message->set_e(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA);
+ message->add_repeated_e(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA);
+ message->add_repeated_packed_e(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA);
+ message->add_repeated_packed_unexpected_e(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA);
+ message->set_oneof_e_1(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA);
+}
+
+void CheckMessage(
+ const proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra& message) {
+ EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+ message.e());
+ EXPECT_EQ(1, message.repeated_e_size());
+ EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+ message.repeated_e(0));
+ EXPECT_EQ(1, message.repeated_packed_e_size());
+ EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+ message.repeated_packed_e(0));
+ EXPECT_EQ(1, message.repeated_packed_unexpected_e_size());
+ EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+ message.repeated_packed_unexpected_e(0));
+ EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+ message.oneof_e_1());
+}
+
+void CheckMessage(
+ const proto3_preserve_unknown_enum_unittest::MyMessage& message) {
+ EXPECT_EQ(static_cast<int>(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA),
+ static_cast<int>(message.e()));
+ EXPECT_EQ(1, message.repeated_e_size());
+ EXPECT_EQ(static_cast<int>(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA),
+ static_cast<int>(message.repeated_e(0)));
+ EXPECT_EQ(1, message.repeated_packed_e_size());
+ EXPECT_EQ(static_cast<int>(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA),
+ static_cast<int>(message.repeated_packed_e(0)));
+ EXPECT_EQ(1, message.repeated_packed_unexpected_e_size());
+ EXPECT_EQ(static_cast<int>(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA),
+ static_cast<int>(message.repeated_packed_unexpected_e(0)));
+ EXPECT_EQ(static_cast<int>(
+ proto3_preserve_unknown_enum_unittest::E_EXTRA),
+ static_cast<int>(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) {
+ proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+ FillMessage(&orig_message);
+ string serialized;
+ orig_message.SerializeToString(&serialized);
+
+ proto3_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) {
+ proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+ FillMessage(&orig_message);
+ string serialized = orig_message.SerializeAsString();
+
+ google::protobuf::DynamicMessageFactory factory;
+ google::protobuf::scoped_ptr<google::protobuf::Message> message(factory.GetPrototype(
+ proto3_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 for proto2 messages, unknown values are in unknown fields.
+TEST(PreserveUnknownEnumTest, Proto2HidesUnknownValues) {
+ proto3_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));
+ // The intermediate message has everything in its "unknown fields".
+ proto2_preserve_unknown_enum_unittest::MyMessage message2 = message;
+ message2.DiscardUnknownFields();
+ EXPECT_EQ(0, message2.ByteSize());
+
+ // But when we pass it to the correct structure, all values are there.
+ serialized.clear();
+ message.SerializeToString(&serialized);
+ EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+ CheckMessage(orig_message);
+}
+
+// Same as before, for a dynamic message.
+TEST(PreserveUnknownEnumTest, DynamicProto2HidesUnknownValues) {
+ proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+ FillMessage(&orig_message);
+
+ string serialized;
+ orig_message.SerializeToString(&serialized);
+
+ google::protobuf::DynamicMessageFactory factory;
+ google::protobuf::scoped_ptr<google::protobuf::Message> message(factory.GetPrototype(
+ proto2_preserve_unknown_enum_unittest::MyMessage::descriptor())->New());
+ EXPECT_EQ(true, message->ParseFromString(serialized));
+ // The intermediate message has everything in its "unknown fields".
+ proto2_preserve_unknown_enum_unittest::MyMessage message2;
+ message2.CopyFrom(*message);
+ message2.DiscardUnknownFields();
+ EXPECT_EQ(0, message2.ByteSize());
+
+ // But when we pass it to the correct structure, all values are there.
+ serialized.clear();
+ message->SerializeToString(&serialized);
+ EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+ CheckMessage(orig_message);
+}
+
+// Test that reflection provides EnumValueDescriptors for unknown values.
+TEST(PreserveUnknownEnumTest, DynamicEnumValueDescriptors) {
+ proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+ FillMessage(&orig_message);
+ string serialized;
+ orig_message.SerializeToString(&serialized);
+
+ proto3_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<int>(proto3_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<int>(proto3_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) {
+ proto3_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);
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+ // 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");
+#endif // PROTOBUF_HAS_DEATH_TEST
+}
+
+TEST(PreserveUnknownEnumTest, SupportsUnknownEnumValuesAPI) {
+ protobuf_unittest::TestAllTypes proto2_message;
+ proto3_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..c3b5996f
--- /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 <string>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_proto3_arena.pb.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+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<TestAllTypes>(&arena);
+ arena_message->ParseFromString(original.SerializeAsString());
+ ExpectAllFieldsSet(*arena_message);
+}
+
+TEST(ArenaTest, UnknownFields) {
+ TestAllTypes original;
+ SetAllFields(&original);
+
+ Arena arena;
+ TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&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<TestAllTypes>(&arena1);
+ TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&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<TestAllTypes>(&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<TestAllTypes>(&arena);
+ arena_message->mutable_optional_nested_message()->set_bb(118);
+ google::protobuf::scoped_ptr<TestAllTypes::NestedMessage> 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 <string>
+
+#include <google/protobuf/stubs/common.h>
+
+// 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<NewMessage>(old_message);
+namespace google {
+template<typename NewProto,
+ typename OldProto>
+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 <google/protobuf/util/proto_cast.h>
+
+#include <google/protobuf/util/unknown_enum_test.pb.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/testing/gmock.h>
+
+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<DownRevision>(sender);
+ ASSERT_EQ(DownRevision::NONDEFAULT_VALUE, receiver.value());
+}
+
+TEST(ProtoCastTest, V2UnknownValue) {
+ UpRevision sender;
+ sender.set_value(UpRevision::NEW_VALUE);
+
+ DownRevision receiver = proto_cast<DownRevision>(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 100755
index 00000000..03c761c1
--- /dev/null
+++ b/src/google/protobuf/reflection.h
@@ -0,0 +1,599 @@
+// 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 <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<typename T, typename Enable = void>
+struct RefTypeTraits;
+} // namespace internal
+
+template<typename T>
+RepeatedFieldRef<T> Reflection::GetRepeatedFieldRef(
+ const Message& message, const FieldDescriptor* field) const {
+ return RepeatedFieldRef<T>(message, field);
+}
+
+template<typename T>
+MutableRepeatedFieldRef<T> Reflection::GetMutableRepeatedFieldRef(
+ Message* message, const FieldDescriptor* field) const {
+ return MutableRepeatedFieldRef<T>(message, field);
+}
+
+// RepeatedFieldRef definition for non-message types.
+template<typename T>
+class RepeatedFieldRef<
+ T, typename internal::enable_if<!internal::is_base_of<Message, T>::value>::type> {
+ typedef typename internal::RefTypeTraits<T>::iterator IteratorType;
+ typedef typename internal::RefTypeTraits<T>::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<T>(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*>(&message), field,
+ internal::RefTypeTraits<T>::cpp_type, NULL);
+ accessor_ = reflection->RepeatedFieldAccessor(field);
+ }
+
+ const void* data_;
+ const AccessorType* accessor_;
+};
+
+// MutableRepeatedFieldRef definition for non-message types.
+template<typename T>
+class MutableRepeatedFieldRef<
+ T, typename internal::enable_if<!internal::is_base_of<Message, T>::value>::type> {
+ typedef typename internal::RefTypeTraits<T>::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<T>(data_, index);
+ }
+
+ void Set(int index, const T& value) const {
+ accessor_->template Set<T>(data_, index, value);
+ }
+ void Add(const T& value) const {
+ accessor_->template Add<T>(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<typename Container>
+ void MergeFrom(const Container& container) const {
+ typedef typename Container::const_iterator Iterator;
+ for (Iterator it = container.begin(); it != container.end(); ++it) {
+ Add(*it);
+ }
+ }
+ template<typename Container>
+ 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<T>::cpp_type, NULL);
+ accessor_ = reflection->RepeatedFieldAccessor(field);
+ }
+
+ void* data_;
+ const AccessorType* accessor_;
+};
+
+// RepeatedFieldRef definition for message types.
+template<typename T>
+class RepeatedFieldRef<
+ T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> {
+ typedef typename internal::RefTypeTraits<T>::iterator IteratorType;
+ typedef typename internal::RefTypeTraits<T>::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<Message> h = ...
+ // unique_ptr<Message> 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<const T*>(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<T*>(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*>(&message), field,
+ internal::RefTypeTraits<T>::cpp_type,
+ internal::RefTypeTraits<T>::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 message types.
+template<typename T>
+class MutableRepeatedFieldRef<
+ T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> {
+ typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+ bool empty() const {
+ return accessor_->IsEmpty(data_);
+ }
+ int size() const {
+ return accessor_->Size(data_);
+ }
+ // See comments for RepeatedFieldRef<Message>::Get()
+ const T& Get(int index, T* scratch_space) const {
+ return *static_cast<const T*>(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<T*>(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<typename Container>
+ void MergeFrom(const Container& container) const {
+ typedef typename Container::const_iterator Iterator;
+ for (Iterator it = container.begin(); it != container.end(); ++it) {
+ Add(*it);
+ }
+ }
+ template<typename Container>
+ 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<T>::cpp_type,
+ internal::RefTypeTraits<T>::GetMessageFieldDescriptor());
+ accessor_ = reflection->RepeatedFieldAccessor(field);
+ default_instance_ =
+ reflection->GetMessageFactory()->GetPrototype(field->message_type());
+ }
+
+ void* data_;
+ const AccessorType* accessor_;
+ const Message* default_instance_;
+};
+
+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<T>::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<typename T>
+ T Get(const Field* data, int index) const {
+ typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+ ActualType scratch_space;
+ return static_cast<T>(
+ *reinterpret_cast<const ActualType*>(
+ Get(data, index, static_cast<Value*>(&scratch_space))));
+ }
+
+ template<typename T, typename ValueType>
+ void Set(Field* data, int index, const ValueType& value) const {
+ typedef typename RefTypeTraits<T>::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<ActualType>(value);
+ Set(data, index, static_cast<const Value*>(&tmp));
+ }
+
+ template<typename T, typename ValueType>
+ void Add(Field* data, const ValueType& value) const {
+ typedef typename RefTypeTraits<T>::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<ActualType>(value);
+ Add(data, static_cast<const Value*>(&tmp));
+ }
+};
+
+// Implement (Mutable)RepeatedFieldRef::iterator
+template<typename T>
+class RepeatedFieldRefIterator
+ : public std::iterator<std::forward_iterator_tag, T> {
+ typedef typename RefTypeTraits<T>::AccessorValueType AccessorValueType;
+ typedef typename RefTypeTraits<T>::IteratorValueType IteratorValueType;
+ typedef typename RefTypeTraits<T>::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<IteratorValueType>(
+ *static_cast<const AccessorValueType*>(
+ accessor_->GetIteratorValue(
+ data_, iterator_, scratch_space_.get())));
+ }
+ IteratorPointerType operator->() const {
+ return static_cast<IteratorPointerType>(
+ 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_;
+ google::protobuf::scoped_ptr<AccessorValueType> scratch_space_;
+};
+
+// TypeTraits that maps the type parameter T of RepeatedFieldRef or
+// MutableRepeatedFieldRef to corresponding iterator type,
+// RepeatedFieldAccessor type, etc.
+template<typename T>
+struct PrimitiveTraits {
+ static const bool is_primitive = false;
+};
+#define DEFINE_PRIMITIVE(TYPE, type) \
+ template<> struct PrimitiveTraits<type> { \
+ 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<typename T>
+struct RefTypeTraits<
+ T, typename internal::enable_if<PrimitiveTraits<T>::is_primitive>::type> {
+ typedef RepeatedFieldRefIterator<T> iterator;
+ typedef RepeatedFieldAccessor AccessorType;
+ typedef T AccessorValueType;
+ typedef T IteratorValueType;
+ typedef T* IteratorPointerType;
+ static const FieldDescriptor::CppType cpp_type =
+ PrimitiveTraits<T>::cpp_type;
+ static const Descriptor* GetMessageFieldDescriptor() {
+ return NULL;
+ }
+};
+
+template<typename T>
+struct RefTypeTraits<
+ T, typename internal::enable_if<is_proto_enum<T>::value>::type> {
+ typedef RepeatedFieldRefIterator<T> 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<typename T>
+struct RefTypeTraits<
+ T, typename internal::enable_if<internal::is_same<string, T>::value>::type> {
+ typedef RepeatedFieldRefIterator<T> 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<typename T>
+struct MessageDescriptorGetter {
+ static const Descriptor* get() {
+ return T::default_instance().GetDescriptor();
+ }
+};
+template<>
+struct MessageDescriptorGetter<Message> {
+ static const Descriptor* get() {
+ return NULL;
+ }
+};
+
+template<typename T>
+struct RefTypeTraits<
+ T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> {
+ typedef RepeatedFieldRefIterator<T> 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<T>::get();
+ }
+};
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#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..fcb42471
--- /dev/null
+++ b/src/google/protobuf/reflection_internal.h
@@ -0,0 +1,378 @@
+// 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 <google/protobuf/map_field.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/repeated_field.h>
+
+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*>(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<int>(IteratorToPosition(iterator)),
+ scratch_space);
+ }
+
+ private:
+ static intptr_t IteratorToPosition(const Iterator* iterator) {
+ return reinterpret_cast<intptr_t>(iterator);
+ }
+ static Iterator* PositionToIterator(intptr_t position) {
+ return reinterpret_cast<Iterator*>(position);
+ }
+};
+
+// Base class for RepeatedFieldAccessor implementations that manipulates
+// RepeatedField<T>.
+template<typename T>
+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<T> RepeatedFieldType;
+ static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+ return reinterpret_cast<const RepeatedFieldType*>(data);
+ }
+ static RepeatedFieldType* MutableRepeatedField(Field* data) {
+ return reinterpret_cast<RepeatedFieldType*>(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<T>.
+template<typename T>
+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<T> RepeatedFieldType;
+ static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+ return reinterpret_cast<const RepeatedFieldType*>(data);
+ }
+ static RepeatedFieldType* MutableRepeatedField(Field* data) {
+ return reinterpret_cast<RepeatedFieldType*>(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;
+};
+
+// An implementation of RandomAccessRepeatedFieldAccessor that manipulates
+// MapFieldBase.
+class MapFieldAccessor : public RandomAccessRepeatedFieldAccessor {
+ public:
+ MapFieldAccessor() {}
+ virtual ~MapFieldAccessor() {}
+ 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 ConvertFromEntry(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 {
+ ConvertToEntry(value, MutableRepeatedField(data)->Mutable(index));
+ }
+ virtual void Add(Field* data, const Value* value) const {
+ Message* allocated = New(value);
+ ConvertToEntry(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);
+ }
+ 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:
+ typedef RepeatedPtrField<Message> RepeatedFieldType;
+ static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+ return reinterpret_cast<const RepeatedFieldType*>(
+ (&reinterpret_cast<const MapFieldBase*>(data)->GetRepeatedField()));
+ }
+ static RepeatedFieldType* MutableRepeatedField(Field* data) {
+ return reinterpret_cast<RepeatedFieldType*>(
+ reinterpret_cast<MapFieldBase*>(data)->MutableRepeatedField());
+ }
+ virtual Message* New(const Value* value) const {
+ return static_cast<const Message*>(value)->New();
+ }
+ // Convert an object received by this accessor to an MapEntry message to be
+ // stored in the underlying MapFieldBase.
+ virtual void ConvertToEntry(const Value* value, Message* result) const {
+ result->CopyFrom(*static_cast<const Message*>(value));
+ }
+ // Convert a MapEntry message stored in the underlying MapFieldBase to an
+ // object that will be returned by this accessor.
+ virtual const Value* ConvertFromEntry(const Message& value,
+ Value* scratch_space) const {
+ return static_cast<const Value*>(&value);
+ }
+};
+
+// Default implementations of RepeatedFieldAccessor for primitive types.
+template<typename T>
+class RepeatedFieldPrimitiveAccessor : public RepeatedFieldWrapper<T> {
+ typedef void Field;
+ typedef void Value;
+ using RepeatedFieldWrapper<T>::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<const T*>(value);
+ }
+ virtual const Value* ConvertFromT(const T& value,
+ Value* scratch_space) const {
+ return static_cast<const Value*>(&value);
+ }
+};
+
+// Default implementation of RepeatedFieldAccessor for string fields with
+// ctype=STRING.
+class RepeatedPtrFieldStringAccessor : public RepeatedPtrFieldWrapper<string> {
+ 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<string> tmp;
+ tmp.Swap(MutableRepeatedField(data));
+ int other_size = other_mutator->Size(other_data);
+ for (int i = 0; i < other_size; ++i) {
+ Add<string>(data, other_mutator->Get<string>(other_data, i));
+ }
+ int size = Size(data);
+ other_mutator->Clear(other_data);
+ for (int i = 0; i < size; ++i) {
+ other_mutator->Add<string>(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<const string*>(value);
+ }
+ virtual const Value* ConvertFromT(const string& value,
+ Value* scratch_space) const {
+ return static_cast<const Value*>(&value);
+ }
+};
+
+
+class RepeatedPtrFieldMessageAccessor
+ : public RepeatedPtrFieldWrapper<Message> {
+ 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<const Message*>(value)->New();
+ }
+ virtual void ConvertToT(const Value* value, Message* result) const {
+ result->CopyFrom(*static_cast<const Message*>(value));
+ }
+ virtual const Value* ConvertFromT(const Message& value,
+ Value* scratch_space) const {
+ return static_cast<const Value*>(&value);
+ }
+};
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc
index 897c0d7c..4629dec2 100644
--- a/src/google/protobuf/reflection_ops.cc
+++ b/src/google/protobuf/reflection_ops.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,8 +32,12 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <string>
+#include <vector>
+
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/stubs/strutil.h>
@@ -52,7 +56,9 @@ void ReflectionOps::Merge(const Message& from, Message* to) {
const Descriptor* descriptor = from.GetDescriptor();
GOOGLE_CHECK_EQ(to->GetDescriptor(), descriptor)
- << "Tried to merge messages of different types.";
+ << "Tried to merge messages of different types "
+ << "(merge " << descriptor->full_name()
+ << " to " << to->GetDescriptor()->full_name() << ")";
const Reflection* from_reflection = from.GetReflection();
const Reflection* to_reflection = to->GetReflection();
@@ -151,11 +157,12 @@ bool ReflectionOps::IsInitialized(const Message& message) {
for (int i = 0; i < fields.size(); i++) {
const FieldDescriptor* field = fields[i];
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
if (field->is_repeated()) {
int size = reflection->FieldSize(message, field);
- for (int i = 0; i < size; i++) {
- if (!reflection->GetRepeatedMessage(message, field, i)
+ for (int j = 0; j < size; j++) {
+ if (!reflection->GetRepeatedMessage(message, field, j)
.IsInitialized()) {
return false;
}
@@ -183,8 +190,8 @@ void ReflectionOps::DiscardUnknownFields(Message* message) {
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
if (field->is_repeated()) {
int size = reflection->FieldSize(*message, field);
- for (int i = 0; i < size; i++) {
- reflection->MutableRepeatedMessage(message, field, i)
+ for (int j = 0; j < size; j++) {
+ reflection->MutableRepeatedMessage(message, field, j)
->DiscardUnknownFields();
}
} else {
@@ -240,11 +247,11 @@ void ReflectionOps::FindInitializationErrors(
if (field->is_repeated()) {
int size = reflection->FieldSize(message, field);
- for (int i = 0; i < size; i++) {
+ for (int j = 0; j < size; j++) {
const Message& sub_message =
- reflection->GetRepeatedMessage(message, field, i);
+ reflection->GetRepeatedMessage(message, field, j);
FindInitializationErrors(sub_message,
- SubMessagePrefix(prefix, field, i),
+ SubMessagePrefix(prefix, field, j),
errors);
}
} else {
diff --git a/src/google/protobuf/reflection_ops.h b/src/google/protobuf/reflection_ops.h
index 355a0a5d..4775911e 100644
--- a/src/google/protobuf/reflection_ops.h
+++ b/src/google/protobuf/reflection_ops.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -38,6 +38,7 @@
#ifndef GOOGLE_PROTOBUF_REFLECTION_OPS_H__
#define GOOGLE_PROTOBUF_REFLECTION_OPS_H__
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message.h>
namespace google {
diff --git a/src/google/protobuf/reflection_ops_unittest.cc b/src/google/protobuf/reflection_ops_unittest.cc
index 1cd56f1e..32740ea4 100644
--- a/src/google/protobuf/reflection_ops_unittest.cc
+++ b/src/google/protobuf/reflection_ops_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -78,6 +78,18 @@ TEST(ReflectionOpsTest, CopyExtensions) {
TestUtil::ExpectAllExtensionsSet(message2);
}
+TEST(ReflectionOpsTest, CopyOneof) {
+ unittest::TestOneof2 message, message2;
+ TestUtil::SetOneof1(&message);
+ ReflectionOps::Copy(message, &message2);
+ TestUtil::ExpectOneofSet1(message2);
+
+ TestUtil::SetOneof2(&message);
+ TestUtil::ExpectOneofSet2(message);
+ ReflectionOps::Copy(message, &message2);
+ TestUtil::ExpectOneofSet2(message2);
+}
+
TEST(ReflectionOpsTest, Merge) {
// Note: Copy is implemented in terms of Merge() so technically the Copy
// test already tested most of this.
@@ -152,7 +164,25 @@ TEST(ReflectionOpsTest, MergeUnknown) {
EXPECT_EQ(2, message1.unknown_fields().field(1).varint());
}
-#ifdef GTEST_HAS_DEATH_TEST
+TEST(ReflectionOpsTest, MergeOneof) {
+ unittest::TestOneof2 message1, message2;
+ TestUtil::SetOneof1(&message1);
+
+ // Merge to empty message
+ ReflectionOps::Merge(message1, &message2);
+ TestUtil::ExpectOneofSet1(message2);
+
+ // Merge with the same oneof fields
+ ReflectionOps::Merge(message1, &message2);
+ TestUtil::ExpectOneofSet1(message2);
+
+ // Merge with different oneof fields
+ TestUtil::SetOneof2(&message1);
+ ReflectionOps::Merge(message1, &message2);
+ TestUtil::ExpectOneofSet2(message2);
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
TEST(ReflectionOpsTest, MergeFromSelf) {
// Note: Copy is implemented in terms of Merge() so technically the Copy
@@ -165,7 +195,7 @@ TEST(ReflectionOpsTest, MergeFromSelf) {
"&from");
}
-#endif // GTEST_HAS_DEATH_TEST
+#endif // PROTOBUF_HAS_DEATH_TEST
TEST(ReflectionOpsTest, Clear) {
unittest::TestAllTypes message;
@@ -220,6 +250,23 @@ TEST(ReflectionOpsTest, ClearUnknown) {
EXPECT_EQ(0, message.unknown_fields().field_count());
}
+TEST(ReflectionOpsTest, ClearOneof) {
+ unittest::TestOneof2 message;
+
+ TestUtil::ExpectOneofClear(message);
+ TestUtil::SetOneof1(&message);
+ TestUtil::ExpectOneofSet1(message);
+ ReflectionOps::Clear(&message);
+ TestUtil::ExpectOneofClear(message);
+
+ TestUtil::SetOneof1(&message);
+ TestUtil::ExpectOneofSet1(message);
+ TestUtil::SetOneof2(&message);
+ TestUtil::ExpectOneofSet2(message);
+ ReflectionOps::Clear(&message);
+ TestUtil::ExpectOneofClear(message);
+}
+
TEST(ReflectionOpsTest, DiscardUnknownFields) {
unittest::TestAllTypes message;
TestUtil::SetAllFields(&message);
@@ -354,10 +401,26 @@ TEST(ReflectionOpsTest, ExtensionIsInitialized) {
EXPECT_TRUE(ReflectionOps::IsInitialized(message));
}
+TEST(ReflectionOpsTest, OneofIsInitialized) {
+ unittest::TestRequiredOneof message;
+ EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+
+ message.mutable_foo_message();
+ EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+
+ message.set_foo_int(1);
+ EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+
+ message.mutable_foo_message();
+ EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+ message.mutable_foo_message()->set_required_double(0.1);
+ EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+}
+
static string FindInitializationErrors(const Message& message) {
vector<string> errors;
ReflectionOps::FindInitializationErrors(message, "", &errors);
- return JoinStrings(errors, ",");
+ return Join(errors, ",");
}
TEST(ReflectionOpsTest, FindInitializationErrors) {
@@ -399,6 +462,13 @@ TEST(ReflectionOpsTest, FindExtensionInitializationErrors) {
FindInitializationErrors(message));
}
+TEST(ReflectionOpsTest, FindOneofInitializationErrors) {
+ unittest::TestRequiredOneof message;
+ message.mutable_foo_message();
+ EXPECT_EQ("foo_message.required_double",
+ FindInitializationErrors(message));
+}
+
} // namespace
} // namespace internal
} // namespace protobuf
diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc
index 09377742..e5aedadc 100644
--- a/src/google/protobuf/repeated_field.cc
+++ b/src/google/protobuf/repeated_field.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -42,53 +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(total_size_ * 2, new_size);
- elements_ = new void*[total_size_];
- memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0]));
- if (old_elements != initial_space_) {
- 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_];
}
-}
-
-void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) {
- void** swap_elements = elements_;
- int swap_current_size = current_size_;
- int swap_allocated_size = allocated_size_;
- int swap_total_size = total_size_;
- // We may not be using initial_space_ but it's not worth checking. Just
- // copy it anyway.
- void* swap_initial_space[kInitialSize];
- memcpy(swap_initial_space, initial_space_, sizeof(initial_space_));
-
- elements_ = other->elements_;
- current_size_ = other->current_size_;
- allocated_size_ = other->allocated_size_;
- total_size_ = other->total_size_;
- memcpy(initial_space_, other->initial_space_, sizeof(initial_space_));
-
- other->elements_ = swap_elements;
- other->current_size_ = swap_current_size;
- other->allocated_size_ = swap_allocated_size;
- other->total_size_ = swap_total_size;
- memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space));
-
- if (elements_ == other->initial_space_) {
- elements_ = initial_space_;
+ Rep* old_rep = rep_;
+ Arena* arena = GetArenaNoVirtual();
+ new_size = max(kMinRepeatedFieldAllocationSize,
+ max(total_size_ * 2, new_size));
+ if (arena == NULL) {
+ rep_ = reinterpret_cast<Rep*>(
+ new char[kRepHeaderSize + sizeof(old_rep->elements[0])*new_size]);
+ } else {
+ rep_ = reinterpret_cast<Rep*>(
+ ::google::protobuf::Arena::CreateArray<char>(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 (other->elements_ == initial_space_) {
- other->elements_ = other->initial_space_;
+ if (arena == NULL) {
+ delete [] reinterpret_cast<char*>(old_rep);
}
+ return &rep_->elements[current_size_];
}
-string* StringTypeHandlerBase::New() {
- return new string;
+void RepeatedPtrFieldBase::Reserve(int new_size) {
+ if (new_size > current_size_) {
+ InternalExtend(new_size - current_size_);
+ }
}
-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 6080ddcc..f5f5d3f4 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,24 +46,58 @@
#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__
#define GOOGLE_PROTOBUF_REPEATED_FIELD_H__
+#ifdef _MSC_VER
+// This is required for min/max on VS2013 only.
+#include <algorithm>
+#endif
+
#include <string>
#include <iterator>
+#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/type_traits.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message_lite.h>
namespace google {
+namespace upb {
+namespace google_opensource {
+class GMR_Handlers;
+} // namespace google_opensource
+} // namespace upb
+
namespace protobuf {
class Message;
namespace internal {
-// We need this (from generated_message_reflection.cc).
-LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str);
+static const int kMinRepeatedFieldAllocationSize = 4;
+
+// A utility function for logging that doesn't need any template types.
+void LogIndexOutOfBounds(int index, int size);
+template <typename Iter>
+inline int CalculateReserve(Iter begin, Iter end, std::forward_iterator_tag) {
+ return std::distance(begin, end);
+}
+
+template <typename Iter>
+inline int CalculateReserve(Iter /*begin*/, Iter /*end*/,
+ std::input_iterator_tag /*unused*/) {
+ return -1;
+}
+
+template <typename Iter>
+inline int CalculateReserve(Iter begin, Iter end) {
+ typedef typename std::iterator_traits<Iter>::iterator_category Category;
+ return CalculateReserve(begin, end, Category());
+}
} // namespace internal
+
// RepeatedField is used to represent repeated fields of a primitive type (in
// other words, everything except strings and nested Messages). Most users will
// not ever use a RepeatedField directly; they will use the get-by-index,
@@ -72,11 +106,15 @@ template <typename Element>
class RepeatedField {
public:
RepeatedField();
+ explicit RepeatedField(Arena* arena);
RepeatedField(const RepeatedField& other);
+ template <typename Iter>
+ RepeatedField(Iter begin, const Iter& end);
~RepeatedField();
RepeatedField& operator=(const RepeatedField& other);
+ bool empty() const;
int size() const;
const Element& Get(int index) const;
@@ -85,12 +123,14 @@ class RepeatedField {
void Add(const Element& value);
Element* Add();
// Remove the last element in the array.
- // We don't provide a way to remove any element other than the last
- // because it invites inefficient use, such as O(n^2) filtering loops
- // that should have been O(n). If you want to remove an element other
- // than the last, the best way to do it is to re-arrange the elements
- // so that the one you want removed is at the end, then call RemoveLast().
void RemoveLast();
+
+ // Extract elements with indices in "[start .. start+num-1]".
+ // Copy them into "elements[0 .. num-1]" if "elements" is not NULL.
+ // Caution: implementation also moves elements with indices [start+num ..].
+ // Calling this routine inside a loop can cause quadratic behavior.
+ void ExtractSubrange(int start, int num, Element* elements);
+
void Clear();
void MergeFrom(const RepeatedField& other);
void CopyFrom(const RepeatedField& other);
@@ -106,14 +146,26 @@ class RepeatedField {
Element* AddAlreadyReserved();
int Capacity() const;
+ // Like STL resize. Uses value to fill appended elements.
+ // Like Truncate() if new_size <= size(), otherwise this is
+ // O(new_size - size()).
+ void Resize(int new_size, const Element& value);
+
// Gets the underlying array. This pointer is possibly invalidated by
// any add or remove operation.
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);
@@ -121,41 +173,157 @@ class RepeatedField {
typedef Element* iterator;
typedef const Element* const_iterator;
typedef Element value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef int size_type;
+ typedef ptrdiff_t difference_type;
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_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ reverse_iterator rbegin() {
+ return reverse_iterator(end());
+ }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+ reverse_iterator rend() {
+ return reverse_iterator(begin());
+ }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
// Returns the number of bytes used by the repeated field, excluding
// sizeof(*this)
int SpaceUsedExcludingSelf() const;
- private:
- static const int kInitialSize = 4;
+ // Remove the element referenced by position.
+ iterator erase(const_iterator position);
- Element* elements_;
- int current_size_;
- int total_size_;
+ // Remove the elements in the range [first, last).
+ iterator erase(const_iterator first, const_iterator last);
- Element initial_space_[kInitialSize];
+ // Get the Arena on which this RepeatedField stores its elements.
+ ::google::protobuf::Arena* GetArena() const {
+ return GetArenaNoVirtual();
+ }
+
+ private:
+ static const int kInitialSize = 0;
+ // 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];
+ };
+ // We can not use sizeof(Rep) - sizeof(Element) due to the trailing padding on
+ // the struct. We can not use sizeof(Arena*) as well because there might be
+ // a "gap" after the field arena and before the field elements (e.g., when
+ // Element is double and pointer is 32bit).
+ static const size_t kRepHeaderSize;
+ // 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;
+ }
};
+template<typename Element>
+const size_t RepeatedField<Element>::kRepHeaderSize =
+ reinterpret_cast<size_t>(&reinterpret_cast<Rep*>(16)->elements[0]) - 16;
+
namespace internal {
template <typename It> class RepeatedPtrIterator;
-template <typename It> class RepeatedPtrOverPtrsIterator;
+template <typename It, typename VoidPtr> class RepeatedPtrOverPtrsIterator;
} // namespace internal
namespace internal {
+// This is a helper template to copy an array of elements effeciently when they
+// have a trivial copy constructor, and correctly otherwise. This really
+// shouldn't be necessary, but our compiler doesn't optimize std::copy very
+// effectively.
+template <typename Element,
+ bool HasTrivialCopy = has_trivial_copy<Element>::value>
+struct ElementCopier {
+ 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<typename T>
+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<typename U, typename RetType, RetType (U::*)(const U& arg)>
+ struct CheckType;
+ template<typename U> static HasMerge Check(
+ CheckType<U, void, &U::MergeFrom>*);
+ template<typename U> static HasMerge Check(
+ CheckType<U, bool, &U::MergeFrom>*);
+ template<typename U> static HasNoMerge Check(...);
+
+ // Resovles to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
+ typedef google::protobuf::internal::integral_constant<bool,
+ (sizeof(Check<T>(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.
//
@@ -186,12 +354,24 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
// use of AddFromCleared(), which is not part of the public interface.
friend class ExtensionSet;
+ // The MapFieldBase implementation needs to call protected methods directly,
+ // reinterpreting pointers as being to Message instead of a specific Message
+ // subclass.
+ friend class MapFieldBase;
+
+ // To parse directly into a proto2 generated class, the upb class GMR_Handlers
+ // needs to be able to modify a RepeatedPtrFieldBase directly.
+ friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers;
+
RepeatedPtrFieldBase();
+ explicit RepeatedPtrFieldBase(::google::protobuf::Arena* arena);
+ ~RepeatedPtrFieldBase() {}
// Must be called from destructor.
template <typename TypeHandler>
void Destroy();
+ bool empty() const;
int size() const;
template <typename TypeHandler>
@@ -199,7 +379,10 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename TypeHandler>
typename TypeHandler::Type* Mutable(int index);
template <typename TypeHandler>
- typename TypeHandler::Type* Add();
+ void Delete(int index);
+ template <typename TypeHandler>
+ typename TypeHandler::Type* Add(typename TypeHandler::Type* prototype = NULL);
+
template <typename TypeHandler>
void RemoveLast();
template <typename TypeHandler>
@@ -209,6 +392,8 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename TypeHandler>
void CopyFrom(const RepeatedPtrFieldBase& other);
+ void CloseGap(int start, int num);
+
void Reserve(int new_size);
int Capacity() const;
@@ -222,7 +407,8 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename TypeHandler>
const typename TypeHandler::Type* const* data() const;
- void Swap(RepeatedPtrFieldBase* other);
+ template <typename TypeHandler>
+ inline void Swap(RepeatedPtrFieldBase* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
void SwapElements(int index1, int index2);
@@ -236,10 +422,25 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename TypeHandler>
typename TypeHandler::Type* AddFromCleared();
+ template<typename TypeHandler>
+ void AddAllocated(typename TypeHandler::Type* value) {
+ typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
+ AddAllocatedInternal<TypeHandler>(value, t);
+ }
+
template <typename TypeHandler>
- void AddAllocated(typename TypeHandler::Type* value);
+ void UnsafeArenaAddAllocated(typename TypeHandler::Type* value);
+
template <typename TypeHandler>
- typename TypeHandler::Type* ReleaseLast();
+ typename TypeHandler::Type* ReleaseLast() {
+ typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
+ return ReleaseLastInternal<TypeHandler>(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>
+ typename TypeHandler::Type* UnsafeArenaReleaseLast();
int ClearedCount() const;
template <typename TypeHandler>
@@ -247,17 +448,61 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename TypeHandler>
typename TypeHandler::Type* ReleaseCleared();
- private:
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase);
+ protected:
+ inline void InternalSwap(RepeatedPtrFieldBase* other);
+
+ template <typename TypeHandler>
+ void AddAllocatedInternal(typename TypeHandler::Type* value,
+ google::protobuf::internal::true_type);
+ template <typename TypeHandler>
+ void AddAllocatedInternal(typename TypeHandler::Type* value,
+ google::protobuf::internal::false_type);
+
+ template <typename TypeHandler>
+ void AddAllocatedSlowWithCopy(typename TypeHandler::Type* value,
+ Arena* value_arena,
+ Arena* my_arena)
+ GOOGLE_ATTRIBUTE_NOINLINE;
+ template <typename TypeHandler>
+ void AddAllocatedSlowWithoutCopy(typename TypeHandler::Type* value)
+ GOOGLE_ATTRIBUTE_NOINLINE;
+
+ template <typename TypeHandler>
+ typename TypeHandler::Type* ReleaseLastInternal(google::protobuf::internal::true_type);
+ template <typename TypeHandler>
+ typename TypeHandler::Type* ReleaseLastInternal(google::protobuf::internal::false_type);
- static const int kInitialSize = 4;
+ template<typename TypeHandler>
+ inline void SwapFallback(RepeatedPtrFieldBase* other) GOOGLE_ATTRIBUTE_NOINLINE;
- void** elements_;
+ inline Arena* GetArenaNoVirtual() const {
+ return arena_;
+ }
+
+ private:
+ static const int kInitialSize = 0;
+ // 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_;
-
- void* initial_space_[kInitialSize];
+ 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 <typename TypeHandler>
static inline typename TypeHandler::Type* cast(void* element) {
@@ -267,27 +512,141 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
static inline const typename TypeHandler::Type* cast(const void* element) {
return reinterpret_cast<const typename TypeHandler::Type*>(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<typename TypeHandler>
+ 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);
};
template <typename GenericType>
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<Type>(
+ arena, static_cast<GenericType*>(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<Type>(value);
+ }
+ static inline void* GetMaybeArenaPointer(GenericType* value) {
+ return ::google::protobuf::Arena::GetArena<Type>(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 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<TypeName>::NewFromPrototype( \
+ const TypeName* prototype, google::protobuf::Arena* arena) { \
+ return prototype->New(arena); \
+ } \
+ template<> \
+ Inline google::protobuf::Arena* GenericTypeHandler<TypeName>::GetArena( \
+ TypeName* value) { \
+ return value->GetArena(); \
+ } \
+ template<> \
+ Inline void* GenericTypeHandler<TypeName>::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<MessageLite>::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<TypeName>::NewFromPrototype( \
+ const TypeName* prototype, google::protobuf::Arena* arena); \
+ template<> \
+ google::protobuf::Arena* GenericTypeHandler<TypeName>::GetArena( \
+ TypeName* value); \
+ template<> \
+ void* GenericTypeHandler<TypeName>::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<MessageLite>::default_instance() {
+ // Yes, the behavior of the code is undefined, but this function is only
+ // called when we're already deep into the world of undefined, because the
+ // caller called Get(index) out of bounds.
+ MessageLite* null = NULL;
+ return *null;
+}
+
+template <>
+inline const Message& GenericTypeHandler<Message>::default_instance() {
+ // Yes, the behavior of the code is undefined, but this function is only
+ // called when we're already deep into the world of undefined, because the
+ // caller called Get(index) out of bounds.
+ Message* null = NULL;
+ return *null;
+}
+
+
// HACK: If a class is declared as DLL-exported in MSVC, it insists on
// generating copies of all its methods -- even inline ones -- to include
// in the DLL. But SpaceUsed() calls StringSpaceUsedExcludingSelf() which
@@ -299,13 +658,33 @@ inline void GenericTypeHandler<MessageLite>::Merge(
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 inline string* New(Arena* arena) {
+ return Arena::Create<string>(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();
+ }
};
-class LIBPROTOBUF_EXPORT StringTypeHandler : public StringTypeHandlerBase {
+class StringTypeHandler : public StringTypeHandlerBase {
public:
static int SpaceUsed(const string& value) {
return sizeof(value) + StringSpaceUsedExcludingSelf(value);
@@ -321,17 +700,31 @@ template <typename Element>
class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
public:
RepeatedPtrField();
+ explicit RepeatedPtrField(::google::protobuf::Arena* arena);
+
RepeatedPtrField(const RepeatedPtrField& other);
+ template <typename Iter>
+ RepeatedPtrField(Iter begin, const Iter& end);
~RepeatedPtrField();
RepeatedPtrField& operator=(const RepeatedPtrField& other);
+ bool empty() const;
int size() const;
const Element& Get(int index) const;
Element* Mutable(int index);
Element* Add();
- void RemoveLast(); // Remove the last element in the array.
+
+ // Remove the last element in the array.
+ // Ownership of the element is retained by the array.
+ void RemoveLast();
+
+ // Delete elements with indices in the range [start .. start+num-1].
+ // Caution: implementation moves all elements with indices [start+num .. ].
+ // Calling this routine inside a loop can cause quadratic behavior.
+ void DeleteSubrange(int start, int num);
+
void Clear();
void MergeFrom(const RepeatedPtrField& other);
void CopyFrom(const RepeatedPtrField& other);
@@ -348,9 +741,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);
@@ -358,42 +758,117 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
typedef internal::RepeatedPtrIterator<Element> iterator;
typedef internal::RepeatedPtrIterator<const Element> const_iterator;
typedef Element value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef int size_type;
+ typedef ptrdiff_t difference_type;
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_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ reverse_iterator rbegin() {
+ return reverse_iterator(end());
+ }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+ reverse_iterator rend() {
+ return reverse_iterator(begin());
+ }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
// Custom STL-like iterator that iterates over and returns the underlying
// pointers to Element rather than Element itself.
- typedef internal::RepeatedPtrOverPtrsIterator<Element> pointer_iterator;
+ typedef internal::RepeatedPtrOverPtrsIterator<Element, void*>
+ pointer_iterator;
+ typedef internal::RepeatedPtrOverPtrsIterator<const Element, const void*>
+ const_pointer_iterator;
pointer_iterator pointer_begin();
+ const_pointer_iterator pointer_begin() const;
pointer_iterator pointer_end();
+ const_pointer_iterator pointer_end() const;
// Returns (an estimate of) the number of bytes used by the repeated field,
// excluding sizeof(*this).
int SpaceUsedExcludingSelf() const;
// Advanced memory management --------------------------------------
- // When hardcore memory management becomes necessary -- as it often
+ // When hardcore memory management becomes necessary -- as it sometimes
// does here at Google -- the following methods may be useful.
// 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.
+
+ // 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.
+ // If "elements" is non-NULL, then pointers to the extracted elements
+ // are stored in "elements[0 .. num-1]" for the convenience of the caller.
+ // If "elements" is NULL, then the caller must use some other mechanism
+ // 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
// repeatedly reusing a protocol message for similar purposes.
//
- // Really, extremely hardcore programs may actually want to manipulate
- // these objects to better-optimize memory management. These methods
- // allow that.
+ // Hardcore programs may choose to manipulate these cleared objects
+ // to better optimize memory management using the following routines.
// Get the number of cleared objects that are currently being kept
// around for reuse.
@@ -401,12 +876,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
@@ -414,40 +907,106 @@ 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 <typename Element>
inline RepeatedField<Element>::RepeatedField()
- : elements_(initial_space_),
- current_size_(0),
- total_size_(kInitialSize) {
+ : current_size_(0),
+ total_size_(0),
+ rep_(NULL) {
+}
+
+template <typename Element>
+inline RepeatedField<Element>::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<Rep*>(
+ ::google::protobuf::Arena::CreateArray<char>(arena, kRepHeaderSize));
+ rep_->arena = arena;
+ }
}
template <typename Element>
inline RepeatedField<Element>::RepeatedField(const RepeatedField& other)
- : elements_(initial_space_),
- current_size_(0),
- total_size_(kInitialSize) {
+ : current_size_(0),
+ total_size_(0),
+ rep_(NULL) {
CopyFrom(other);
}
template <typename Element>
+template <typename Iter>
+RepeatedField<Element>::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);
+ for (; begin != end; ++begin) {
+ AddAlreadyReserved(*begin);
+ }
+ } else {
+ for (; begin != end; ++begin) {
+ Add(*begin);
+ }
+ }
+}
+
+template <typename Element>
RepeatedField<Element>::~RepeatedField() {
- if (elements_ != initial_space_) {
- 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<char*>(rep_);
+ }
}
}
template <typename Element>
inline RepeatedField<Element>&
RepeatedField<Element>::operator=(const RepeatedField& other) {
- CopyFrom(other);
+ if (this != &other)
+ CopyFrom(other);
return *this;
}
template <typename Element>
+inline bool RepeatedField<Element>::empty() const {
+ return current_size_ == 0;
+}
+
+template <typename Element>
inline int RepeatedField<Element>::size() const {
return current_size_;
}
@@ -459,50 +1018,85 @@ inline int RepeatedField<Element>::Capacity() const {
template<typename Element>
inline void RepeatedField<Element>::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<typename Element>
inline Element* RepeatedField<Element>::AddAlreadyReserved() {
- GOOGLE_DCHECK_LT(size(), Capacity());
- return &elements_[current_size_++];
+ GOOGLE_DCHECK_LT(current_size_, total_size_);
+ return &rep_->elements[current_size_++];
+}
+
+template<typename Element>
+inline void RepeatedField<Element>::Resize(int new_size, const Element& value) {
+ GOOGLE_DCHECK_GE(new_size, 0);
+ if (new_size > current_size_) {
+ Reserve(new_size);
+ std::fill(&rep_->elements[current_size_],
+ &rep_->elements[new_size], value);
+ }
+ current_size_ = new_size;
}
template <typename Element>
inline const Element& RepeatedField<Element>::Get(int index) const {
- GOOGLE_DCHECK_LT(index, size());
- return elements_[index];
+ GOOGLE_DCHECK_GE(index, 0);
+ GOOGLE_DCHECK_LT(index, current_size_);
+ return rep_->elements[index];
}
template <typename Element>
inline Element* RepeatedField<Element>::Mutable(int index) {
- GOOGLE_DCHECK_LT(index, size());
- return elements_ + index;
+ GOOGLE_DCHECK_GE(index, 0);
+ GOOGLE_DCHECK_LT(index, current_size_);
+ return &rep_->elements[index];
}
template <typename Element>
inline void RepeatedField<Element>::Set(int index, const Element& value) {
- GOOGLE_DCHECK_LT(index, size());
- elements_[index] = value;
+ GOOGLE_DCHECK_GE(index, 0);
+ GOOGLE_DCHECK_LT(index, current_size_);
+ rep_->elements[index] = value;
}
template <typename Element>
inline void RepeatedField<Element>::Add(const Element& value) {
if (current_size_ == total_size_) Reserve(total_size_ + 1);
- elements_[current_size_++] = value;
+ rep_->elements[current_size_++] = value;
}
template <typename Element>
inline Element* RepeatedField<Element>::Add() {
if (current_size_ == total_size_) Reserve(total_size_ + 1);
- return &elements_[current_size_++];
+ return &rep_->elements[current_size_++];
}
template <typename Element>
inline void RepeatedField<Element>::RemoveLast() {
GOOGLE_DCHECK_GT(current_size_, 0);
- --current_size_;
+ current_size_--;
+}
+
+template <typename Element>
+void RepeatedField<Element>::ExtractSubrange(
+ int start, int num, Element* elements) {
+ GOOGLE_DCHECK_GE(start, 0);
+ GOOGLE_DCHECK_GE(num, 0);
+ GOOGLE_DCHECK_LE(start + num, this->current_size_);
+
+ // Save the values of the removed elements if requested.
+ if (elements != NULL) {
+ for (int i = 0; i < num; ++i)
+ elements[i] = this->Get(i + start);
+ }
+
+ // Slide remaining elements down to fill the gap.
+ if (num > 0) {
+ for (int i = start + num; i < this->current_size_; ++i)
+ this->Set(i - num, this->Get(i));
+ this->Truncate(this->current_size_ - num);
+ }
}
template <typename Element>
@@ -512,197 +1106,386 @@ inline void RepeatedField<Element>::Clear() {
template <typename Element>
inline void RepeatedField<Element>::MergeFrom(const RepeatedField& other) {
- Reserve(current_size_ + other.current_size_);
- CopyArray(elements_ + current_size_, other.elements_, other.current_size_);
- current_size_ += other.current_size_;
+ GOOGLE_CHECK_NE(&other, this);
+ if (other.current_size_ != 0) {
+ Reserve(current_size_ + other.current_size_);
+ CopyArray(rep_->elements + current_size_,
+ other.rep_->elements, other.current_size_);
+ current_size_ += other.current_size_;
+ }
}
template <typename Element>
inline void RepeatedField<Element>::CopyFrom(const RepeatedField& other) {
+ if (&other == this) return;
Clear();
MergeFrom(other);
}
template <typename Element>
-inline Element* RepeatedField<Element>::mutable_data() {
- return elements_;
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::erase(
+ const_iterator position) {
+ return erase(position, position + 1);
}
template <typename Element>
-inline const Element* RepeatedField<Element>::data() const {
- return elements_;
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::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 <typename Element>
+inline Element* RepeatedField<Element>::mutable_data() {
+ return rep_ ? rep_->elements : NULL;
+}
template <typename Element>
-void RepeatedField<Element>::Swap(RepeatedField* other) {
- Element* swap_elements = elements_;
- int swap_current_size = current_size_;
- int swap_total_size = total_size_;
- // We may not be using initial_space_ but it's not worth checking. Just
- // copy it anyway.
- Element swap_initial_space[kInitialSize];
- MoveArray(swap_initial_space, initial_space_, kInitialSize);
+inline const Element* RepeatedField<Element>::data() const {
+ return rep_ ? rep_->elements : NULL;
+}
- elements_ = other->elements_;
- current_size_ = other->current_size_;
- total_size_ = other->total_size_;
- MoveArray(initial_space_, other->initial_space_, kInitialSize);
- other->elements_ = swap_elements;
- other->current_size_ = swap_current_size;
- other->total_size_ = swap_total_size;
- MoveArray(other->initial_space_, swap_initial_space, kInitialSize);
+template <typename Element>
+inline void RepeatedField<Element>::InternalSwap(RepeatedField* other) {
+ std::swap(rep_, other->rep_);
+ std::swap(current_size_, other->current_size_);
+ std::swap(total_size_, other->total_size_);
+}
- if (elements_ == other->initial_space_) {
- elements_ = initial_space_;
- }
- if (other->elements_ == initial_space_) {
- other->elements_ = other->initial_space_;
+template <typename Element>
+void RepeatedField<Element>::Swap(RepeatedField* other) {
+ if (this == other) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ RepeatedField<Element> temp(other->GetArenaNoVirtual());
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->UnsafeArenaSwap(&temp);
}
}
template <typename Element>
+void RepeatedField<Element>::UnsafeArenaSwap(RepeatedField* other) {
+ if (this == other) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+ InternalSwap(other);
+}
+
+template <typename Element>
void RepeatedField<Element>::SwapElements(int index1, int index2) {
- std::swap(elements_[index1], elements_[index2]);
+ using std::swap; // enable ADL with fallback
+ swap(rep_->elements[index1], rep_->elements[index2]);
}
template <typename Element>
inline typename RepeatedField<Element>::iterator
RepeatedField<Element>::begin() {
- return elements_;
+ return rep_ ? rep_->elements : NULL;
}
template <typename Element>
inline typename RepeatedField<Element>::const_iterator
RepeatedField<Element>::begin() const {
- return elements_;
+ return rep_ ? rep_->elements : NULL;
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::cbegin() const {
+ return rep_ ? rep_->elements : NULL;
}
template <typename Element>
inline typename RepeatedField<Element>::iterator
RepeatedField<Element>::end() {
- return elements_ + current_size_;
+ return rep_ ? rep_->elements + current_size_ : NULL;
}
template <typename Element>
inline typename RepeatedField<Element>::const_iterator
RepeatedField<Element>::end() const {
- return elements_ + current_size_;
+ return rep_ ? rep_->elements + current_size_ : NULL;
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::cend() const {
+ return rep_ ? rep_->elements + current_size_ : NULL;
}
template <typename Element>
inline int RepeatedField<Element>::SpaceUsedExcludingSelf() const {
- return (elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0;
+ return rep_ ?
+ (total_size_ * sizeof(Element) + kRepHeaderSize) : 0;
}
-// Avoid inlining of Reserve(): new, memcpy, and delete[] lead to a significant
+// Avoid inlining of Reserve(): new, copy, and delete[] lead to a significant
// amount of code bloat.
template <typename Element>
void RepeatedField<Element>::Reserve(int new_size) {
if (total_size_ >= new_size) return;
-
- Element* old_elements = elements_;
- total_size_ = max(total_size_ * 2, new_size);
- elements_ = new Element[total_size_];
- MoveArray(elements_, old_elements, current_size_);
- if (old_elements != initial_space_) {
- 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<Rep*>(
+ new char[kRepHeaderSize + sizeof(Element)*new_size]);
+ } else {
+ rep_ = reinterpret_cast<Rep*>(
+ ::google::protobuf::Arena::CreateArray<char>(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<char*>(old_rep);
}
}
template <typename Element>
inline void RepeatedField<Element>::Truncate(int new_size) {
GOOGLE_DCHECK_LE(new_size, current_size_);
- current_size_ = new_size;
+ if (current_size_ > 0) {
+ current_size_ = new_size;
+ }
}
template <typename Element>
inline void RepeatedField<Element>::MoveArray(
- Element to[], Element from[], int array_size) {
- memcpy(to, from, array_size * sizeof(Element));
+ Element* to, Element* from, int array_size) {
+ CopyArray(to, from, array_size);
}
template <typename Element>
inline void RepeatedField<Element>::CopyArray(
- Element to[], const Element from[], int array_size) {
- memcpy(to, from, array_size * sizeof(Element));
+ Element* to, const Element* from, int array_size) {
+ internal::ElementCopier<Element>()(to, from, array_size);
}
+namespace internal {
+
+template <typename Element, bool HasTrivialCopy>
+void ElementCopier<Element, HasTrivialCopy>::operator()(
+ Element* to, const Element* from, int array_size) {
+ std::copy(from, from + array_size, to);
+}
+
+template <typename Element>
+struct ElementCopier<Element, true> {
+ void operator()(Element* to, const Element* from, int array_size) {
+ memcpy(to, from, array_size * sizeof(Element));
+ }
+};
+
+} // namespace internal
+
// -------------------------------------------------------------------
namespace internal {
inline RepeatedPtrFieldBase::RepeatedPtrFieldBase()
- : elements_(initial_space_),
+ : arena_(NULL),
+ current_size_(0),
+ total_size_(0),
+ rep_(NULL) {
+}
+
+inline RepeatedPtrFieldBase::RepeatedPtrFieldBase(::google::protobuf::Arena* arena)
+ : arena_(arena),
current_size_(0),
- allocated_size_(0),
- total_size_(kInitialSize) {
+ total_size_(0),
+ rep_(NULL) {
}
template <typename TypeHandler>
void RepeatedPtrFieldBase::Destroy() {
- for (int i = 0; i < allocated_size_; i++) {
- TypeHandler::Delete(cast<TypeHandler>(elements_[i]));
+ if (rep_ != NULL) {
+ for (int i = 0; i < rep_->allocated_size; i++) {
+ TypeHandler::Delete(cast<TypeHandler>(rep_->elements[i]), arena_);
+ }
+ if (arena_ == NULL) {
+ delete [] reinterpret_cast<char*>(rep_);
+ }
}
- if (elements_ != initial_space_) {
- delete [] elements_;
+ rep_ = NULL;
+}
+
+template <typename TypeHandler>
+inline void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) {
+ if (other->GetArenaNoVirtual() == GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ SwapFallback<TypeHandler>(other);
}
}
+template <typename TypeHandler>
+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<TypeHandler>(*this);
+ this->Clear<TypeHandler>();
+ this->MergeFrom<TypeHandler>(*other);
+ other->Clear<TypeHandler>();
+ other->InternalSwap(&temp);
+ temp.Destroy<TypeHandler>(); // Frees rep_ if `other` had no arena.
+}
+
+inline bool RepeatedPtrFieldBase::empty() const {
+ return current_size_ == 0;
+}
+
inline int RepeatedPtrFieldBase::size() const {
return current_size_;
}
-
template <typename TypeHandler>
inline const typename TypeHandler::Type&
RepeatedPtrFieldBase::Get(int index) const {
- GOOGLE_DCHECK_LT(index, size());
- return *cast<TypeHandler>(elements_[index]);
+ GOOGLE_DCHECK_GE(index, 0);
+ GOOGLE_DCHECK_LT(index, current_size_);
+ return *cast<TypeHandler>(rep_->elements[index]);
}
+
template <typename TypeHandler>
inline typename TypeHandler::Type*
RepeatedPtrFieldBase::Mutable(int index) {
- GOOGLE_DCHECK_LT(index, size());
- return cast<TypeHandler>(elements_[index]);
+ GOOGLE_DCHECK_GE(index, 0);
+ GOOGLE_DCHECK_LT(index, current_size_);
+ return cast<TypeHandler>(rep_->elements[index]);
+}
+
+template <typename TypeHandler>
+inline void RepeatedPtrFieldBase::Delete(int index) {
+ GOOGLE_DCHECK_GE(index, 0);
+ GOOGLE_DCHECK_LT(index, current_size_);
+ TypeHandler::Delete(cast<TypeHandler>(rep_->elements[index]), arena_);
}
template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add() {
- if (current_size_ < allocated_size_) {
- return cast<TypeHandler>(elements_[current_size_++]);
- }
- if (allocated_size_ == total_size_) Reserve(total_size_ + 1);
- ++allocated_size_;
- typename TypeHandler::Type* result = TypeHandler::New();
- elements_[current_size_++] = result;
+inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add(
+ typename TypeHandler::Type* prototype) {
+ if (rep_ != NULL && current_size_ < rep_->allocated_size) {
+ return cast<TypeHandler>(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 <typename TypeHandler>
inline void RepeatedPtrFieldBase::RemoveLast() {
GOOGLE_DCHECK_GT(current_size_, 0);
- TypeHandler::Clear(cast<TypeHandler>(elements_[--current_size_]));
+ TypeHandler::Clear(cast<TypeHandler>(rep_->elements[--current_size_]));
}
template <typename TypeHandler>
void RepeatedPtrFieldBase::Clear() {
- for (int i = 0; i < current_size_; i++) {
- TypeHandler::Clear(cast<TypeHandler>(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<TypeHandler>(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 <typename TypeHandler>
inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) {
- Reserve(current_size_ + other.current_size_);
- for (int i = 0; i < other.current_size_; i++) {
- TypeHandler::Merge(other.template Get<TypeHandler>(i), Add<TypeHandler>());
+ GOOGLE_DCHECK_NE(&other, this);
+ if (other.current_size_ == 0) return;
+ MergeFromInternal(
+ other, &RepeatedPtrFieldBase::MergeFromInnerLoop<TypeHandler>);
+}
+
+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<typename TypeHandler>
+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<typename TypeHandler::Type*>(other_elems[i]);
+ typename TypeHandler::Type* new_elem =
+ reinterpret_cast<typename TypeHandler::Type*>(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<typename TypeHandler::Type*>(other_elems[i]);
+ typename TypeHandler::Type* new_elem =
+ TypeHandler::NewFromPrototype(other_elem, arena);
+ TypeHandler::Merge(*other_elem, new_elem);
+ our_elems[i] = new_elem;
}
}
template <typename TypeHandler>
inline void RepeatedPtrFieldBase::CopyFrom(const RepeatedPtrFieldBase& other) {
+ if (&other == this) return;
RepeatedPtrFieldBase::Clear<TypeHandler>();
RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
}
@@ -712,18 +1495,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<void**>(rep_->elements) : NULL;
}
template <typename TypeHandler>
inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() {
// TODO(kenton): Breaks C++ aliasing rules. We should probably remove this
// method entirely.
- return reinterpret_cast<typename TypeHandler::Type**>(elements_);
+ return reinterpret_cast<typename TypeHandler::Type**>(raw_mutable_data());
}
template <typename TypeHandler>
@@ -731,89 +1514,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<const typename TypeHandler::Type* const*>(elements_);
+ return reinterpret_cast<const typename TypeHandler::Type* const*>(raw_data());
}
inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) {
- std::swap(elements_[index1], elements_[index2]);
+ using std::swap; // enable ADL with fallback
+ swap(rep_->elements[index1], rep_->elements[index2]);
}
template <typename TypeHandler>
inline int RepeatedPtrFieldBase::SpaceUsedExcludingSelf() const {
- int allocated_bytes =
- (elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0;
- for (int i = 0; i < allocated_size_; ++i) {
- allocated_bytes += TypeHandler::SpaceUsed(*cast<TypeHandler>(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<TypeHandler>(rep_->elements[i]));
+ }
+ allocated_bytes += kRepHeaderSize;
}
return allocated_bytes;
}
template <typename TypeHandler>
inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() {
- if (current_size_ < allocated_size_) {
- return cast<TypeHandler>(elements_[current_size_++]);
+ if (rep_ != NULL && current_size_ < rep_->allocated_size) {
+ return cast<TypeHandler>(rep_->elements[current_size_++]);
} else {
return NULL;
}
}
+// AddAllocated version that implements arena-safe copying behavior.
+template <typename TypeHandler>
+void RepeatedPtrFieldBase::AddAllocatedInternal(
+ typename TypeHandler::Type* value,
+ google::protobuf::internal::true_type) {
+ Arena* element_arena = reinterpret_cast<Arena*>(
+ 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<TypeHandler>(
+ value, TypeHandler::GetArena(value), arena);
+ }
+}
+
+// Slowpath handles all cases, copying if necessary.
+template<typename TypeHandler>
+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<TypeHandler>(value);
+}
+
+// AddAllocated version that does not implement arena-safe copying behavior.
template <typename TypeHandler>
-void RepeatedPtrFieldBase::AddAllocated(
+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<TypeHandler>(value);
+ }
+}
+
+template <typename TypeHandler>
+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<TypeHandler>(elements_[current_size_]));
- } else if (current_size_ < allocated_size_) {
+ TypeHandler::Delete(
+ cast<TypeHandler>(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;
}
- elements_[current_size_++] = value;
+ rep_->elements[current_size_++] = value;
}
+// ReleaseLast() for types that implement merge/copy behavior.
template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() {
+inline typename TypeHandler::Type*
+RepeatedPtrFieldBase::ReleaseLastInternal(google::protobuf::internal::true_type) {
+ // First, release an element.
+ typename TypeHandler::Type* result = UnsafeArenaReleaseLast<TypeHandler>();
+ // 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;
+ }
+}
+
+// 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 <typename TypeHandler>
+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<TypeHandler>();
+}
+
+template <typename TypeHandler>
+inline typename TypeHandler::Type*
+ RepeatedPtrFieldBase::UnsafeArenaReleaseLast() {
GOOGLE_DCHECK_GT(current_size_, 0);
typename TypeHandler::Type* result =
- cast<TypeHandler>(elements_[--current_size_]);
- --allocated_size_;
- if (current_size_ < allocated_size_) {
+ cast<TypeHandler>(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 <typename TypeHandler>
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 <typename TypeHandler>
inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() {
- GOOGLE_DCHECK_GT(allocated_size_, current_size_);
- return cast<TypeHandler>(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<TypeHandler>(rep_->elements[--rep_->allocated_size]);
}
} // namespace internal
@@ -822,23 +1728,44 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() {
template <typename Element>
class RepeatedPtrField<Element>::TypeHandler
- : public internal::GenericTypeHandler<Element> {};
+ : public internal::GenericTypeHandler<Element> {
+};
template <>
class RepeatedPtrField<string>::TypeHandler
- : public internal::StringTypeHandler {};
+ : public internal::StringTypeHandler {
+};
+
+template <typename Element>
+inline RepeatedPtrField<Element>::RepeatedPtrField()
+ : RepeatedPtrFieldBase() {}
template <typename Element>
-inline RepeatedPtrField<Element>::RepeatedPtrField() {}
+inline RepeatedPtrField<Element>::RepeatedPtrField(::google::protobuf::Arena* arena) :
+ RepeatedPtrFieldBase(arena) {}
template <typename Element>
inline RepeatedPtrField<Element>::RepeatedPtrField(
- const RepeatedPtrField& other) {
+ const RepeatedPtrField& other)
+ : RepeatedPtrFieldBase() {
CopyFrom(other);
}
template <typename Element>
+template <typename Iter>
+inline RepeatedPtrField<Element>::RepeatedPtrField(
+ Iter begin, const Iter& end) {
+ int reserve = internal::CalculateReserve(begin, end);
+ if (reserve != -1) {
+ Reserve(reserve);
+ }
+ for (; begin != end; ++begin) {
+ *Add() = *begin;
+ }
+}
+
+template <typename Element>
RepeatedPtrField<Element>::~RepeatedPtrField() {
Destroy<TypeHandler>();
}
@@ -846,11 +1773,17 @@ RepeatedPtrField<Element>::~RepeatedPtrField() {
template <typename Element>
inline RepeatedPtrField<Element>& RepeatedPtrField<Element>::operator=(
const RepeatedPtrField& other) {
- CopyFrom(other);
+ if (this != &other)
+ CopyFrom(other);
return *this;
}
template <typename Element>
+inline bool RepeatedPtrField<Element>::empty() const {
+ return RepeatedPtrFieldBase::empty();
+}
+
+template <typename Element>
inline int RepeatedPtrField<Element>::size() const {
return RepeatedPtrFieldBase::size();
}
@@ -860,6 +1793,7 @@ inline const Element& RepeatedPtrField<Element>::Get(int index) const {
return RepeatedPtrFieldBase::Get<TypeHandler>(index);
}
+
template <typename Element>
inline Element* RepeatedPtrField<Element>::Mutable(int index) {
return RepeatedPtrFieldBase::Mutable<TypeHandler>(index);
@@ -876,6 +1810,91 @@ inline void RepeatedPtrField<Element>::RemoveLast() {
}
template <typename Element>
+inline void RepeatedPtrField<Element>::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) {
+ RepeatedPtrFieldBase::Delete<TypeHandler>(start + i);
+ }
+ ExtractSubrange(start, num, NULL);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::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 <typename Element>
+inline void RepeatedPtrField<Element>::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());
+
+ if (num > 0) {
+ // Save the values of the removed elements if requested.
+ if (elements != NULL) {
+ 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<TypeHandler>(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<TypeHandler>(i + start);
+ }
+ }
+ }
+ CloseGap(start, num);
+ }
+}
+
+// ExtractSubrange() implementation for types that do not implement merge/copy
+// behavior.
+template<typename Element>
+inline void RepeatedPtrField<Element>::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 <typename Element>
+inline void RepeatedPtrField<Element>::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<TypeHandler>(i + start);
+ }
+ }
+ CloseGap(start, num);
+ }
+}
+
+template <typename Element>
inline void RepeatedPtrField<Element>::Clear() {
RepeatedPtrFieldBase::Clear<TypeHandler>();
}
@@ -893,6 +1912,21 @@ inline void RepeatedPtrField<Element>::CopyFrom(
}
template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::erase(const_iterator position) {
+ return erase(position, position + 1);
+}
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::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 <typename Element>
inline Element** RepeatedPtrField<Element>::mutable_data() {
return RepeatedPtrFieldBase::mutable_data<TypeHandler>();
}
@@ -903,16 +1937,32 @@ inline const Element* const* RepeatedPtrField<Element>::data() const {
}
template <typename Element>
-void RepeatedPtrField<Element>::Swap(RepeatedPtrField* other) {
- RepeatedPtrFieldBase::Swap(other);
+inline void RepeatedPtrField<Element>::Swap(RepeatedPtrField* other) {
+ if (this == other)
+ return;
+ RepeatedPtrFieldBase::Swap<TypeHandler>(other);
}
template <typename Element>
-void RepeatedPtrField<Element>::SwapElements(int index1, int index2) {
+inline void RepeatedPtrField<Element>::UnsafeArenaSwap(
+ RepeatedPtrField* other) {
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+ if (this == other)
+ return;
+ RepeatedPtrFieldBase::InternalSwap(other);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::SwapElements(int index1, int index2) {
RepeatedPtrFieldBase::SwapElements(index1, index2);
}
template <typename Element>
+inline Arena* RepeatedPtrField<Element>::GetArenaNoVirtual() const {
+ return RepeatedPtrFieldBase::GetArenaNoVirtual();
+}
+
+template <typename Element>
inline int RepeatedPtrField<Element>::SpaceUsedExcludingSelf() const {
return RepeatedPtrFieldBase::SpaceUsedExcludingSelf<TypeHandler>();
}
@@ -923,10 +1973,19 @@ inline void RepeatedPtrField<Element>::AddAllocated(Element* value) {
}
template <typename Element>
+inline void RepeatedPtrField<Element>::UnsafeArenaAddAllocated(Element* value) {
+ RepeatedPtrFieldBase::UnsafeArenaAddAllocated<TypeHandler>(value);
+}
+
+template <typename Element>
inline Element* RepeatedPtrField<Element>::ReleaseLast() {
return RepeatedPtrFieldBase::ReleaseLast<TypeHandler>();
}
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::UnsafeArenaReleaseLast() {
+ return RepeatedPtrFieldBase::UnsafeArenaReleaseLast<TypeHandler>();
+}
template <typename Element>
inline int RepeatedPtrField<Element>::ClearedCount() const {
@@ -961,7 +2020,7 @@ namespace internal {
// refer to this class directly; use RepeatedPtrField<T>::iterator instead.
//
// The iterator for RepeatedPtrField<T>, RepeatedPtrIterator<T>, is
-// very similar to iterator_ptr<T**> in util/gtl/iterator_adaptors-inl.h,
+// very similar to iterator_ptr<T**> in util/gtl/iterator_adaptors.h,
// but adds random-access operators and is modified to wrap a void** base
// iterator (since RepeatedPtrField stores its array as a void* array and
// casting void** to T** would violate C++ aliasing rules).
@@ -977,6 +2036,10 @@ class RepeatedPtrIterator
typedef std::iterator<
std::random_access_iterator_tag, Element> superclass;
+ // Shadow the value_type in std::iterator<> because const_iterator::value_type
+ // needs to be T, not const T.
+ typedef typename remove_const<Element>::type value_type;
+
// Let the compiler know that these are type names, so we don't have to
// write "typename" in front of them everywhere.
typedef typename superclass::reference reference;
@@ -1022,11 +2085,11 @@ class RepeatedPtrIterator
it_ += d;
return *this;
}
- friend iterator operator+(iterator it, difference_type d) {
+ friend iterator operator+(iterator it, const difference_type d) {
it += d;
return it;
}
- friend iterator operator+(difference_type d, iterator it) {
+ friend iterator operator+(const difference_type d, iterator it) {
it += d;
return it;
}
@@ -1057,14 +2120,21 @@ class RepeatedPtrIterator
// rather than the objects themselves as RepeatedPtrIterator does.
// Consider using this when working with stl algorithms that change
// the array.
-template<typename Element>
+// The VoidPtr template parameter holds the type-agnostic pointer value
+// referenced by the iterator. It should either be "void *" for a mutable
+// iterator, or "const void *" for a constant iterator.
+template<typename Element, typename VoidPtr>
class RepeatedPtrOverPtrsIterator
: public std::iterator<std::random_access_iterator_tag, Element*> {
public:
- typedef RepeatedPtrOverPtrsIterator<Element> iterator;
+ typedef RepeatedPtrOverPtrsIterator<Element, VoidPtr> iterator;
typedef std::iterator<
std::random_access_iterator_tag, Element*> superclass;
+ // Shadow the value_type in std::iterator<> because const_iterator::value_type
+ // needs to be T, not const T.
+ typedef typename remove_const<Element*>::type value_type;
+
// Let the compiler know that these are type names, so we don't have to
// write "typename" in front of them everywhere.
typedef typename superclass::reference reference;
@@ -1072,7 +2142,7 @@ class RepeatedPtrOverPtrsIterator
typedef typename superclass::difference_type difference_type;
RepeatedPtrOverPtrsIterator() : it_(NULL) {}
- explicit RepeatedPtrOverPtrsIterator(void** it) : it_(it) {}
+ explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {}
// dereferenceable
reference operator*() const { return *reinterpret_cast<Element**>(it_); }
@@ -1127,9 +2197,14 @@ class RepeatedPtrOverPtrsIterator
friend class RepeatedPtrIterator;
// The internal iterator.
- void** it_;
+ 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
@@ -1144,6 +2219,11 @@ RepeatedPtrField<Element>::begin() const {
return iterator(raw_data());
}
template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::cbegin() const {
+ return begin();
+}
+template <typename Element>
inline typename RepeatedPtrField<Element>::iterator
RepeatedPtrField<Element>::end() {
return iterator(raw_data() + size());
@@ -1153,6 +2233,11 @@ inline typename RepeatedPtrField<Element>::const_iterator
RepeatedPtrField<Element>::end() const {
return iterator(raw_data() + size());
}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::cend() const {
+ return end();
+}
template <typename Element>
inline typename RepeatedPtrField<Element>::pointer_iterator
@@ -1160,20 +2245,31 @@ RepeatedPtrField<Element>::pointer_begin() {
return pointer_iterator(raw_mutable_data());
}
template <typename Element>
+inline typename RepeatedPtrField<Element>::const_pointer_iterator
+RepeatedPtrField<Element>::pointer_begin() const {
+ return const_pointer_iterator(const_cast<const void**>(raw_mutable_data()));
+}
+template <typename Element>
inline typename RepeatedPtrField<Element>::pointer_iterator
RepeatedPtrField<Element>::pointer_end() {
return pointer_iterator(raw_mutable_data() + size());
}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_pointer_iterator
+RepeatedPtrField<Element>::pointer_end() const {
+ return const_pointer_iterator(
+ const_cast<const void**>(raw_mutable_data() + size()));
+}
// Iterators and helper functions that follow the spirit of the STL
// std::back_insert_iterator and std::back_inserter but are tailor-made
-// for RepeatedField and RepatedPtrField. Typical usage would be:
+// for RepeatedField and RepeatedPtrField. Typical usage would be:
//
// std::copy(some_sequence.begin(), some_sequence.end(),
// google::protobuf::RepeatedFieldBackInserter(proto.mutable_sequence()));
//
-// Ported by johannes from util/gtl/proto-array-iterators-inl.h
+// Ported by johannes from util/gtl/proto-array-iterators.h
namespace internal {
// A back inserter for RepeatedField objects.
@@ -1194,7 +2290,7 @@ template<typename T> class RepeatedFieldBackInsertIterator
RepeatedFieldBackInsertIterator<T>& operator++() {
return *this;
}
- RepeatedFieldBackInsertIterator<T>& operator++(int ignores_parameter) {
+ RepeatedFieldBackInsertIterator<T>& operator++(int /* unused */) {
return *this;
}
@@ -1225,7 +2321,7 @@ template<typename T> class RepeatedPtrFieldBackInsertIterator
RepeatedPtrFieldBackInsertIterator<T>& operator++() {
return *this;
}
- RepeatedPtrFieldBackInsertIterator<T>& operator++(int ignores_parameter) {
+ RepeatedPtrFieldBackInsertIterator<T>& operator++(int /* unused */) {
return *this;
}
@@ -1254,7 +2350,7 @@ template<typename T> class AllocatedRepeatedPtrFieldBackInsertIterator
return *this;
}
AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++(
- int ignores_parameter) {
+ int /* unused */) {
return *this;
}
@@ -1264,16 +2360,22 @@ template<typename T> class AllocatedRepeatedPtrFieldBackInsertIterator
} // namespace internal
// Provides a back insert iterator for RepeatedField instances,
-// similar to std::back_inserter(). Note the identically named
-// function for RepeatedPtrField instances.
+// similar to std::back_inserter().
template<typename T> internal::RepeatedFieldBackInsertIterator<T>
RepeatedFieldBackInserter(RepeatedField<T>* const mutable_field) {
return internal::RepeatedFieldBackInsertIterator<T>(mutable_field);
}
// Provides a back insert iterator for RepeatedPtrField instances,
-// similar to std::back_inserter(). Note the identically named
-// function for RepeatedField instances.
+// similar to std::back_inserter().
+template<typename T> internal::RepeatedPtrFieldBackInsertIterator<T>
+RepeatedPtrFieldBackInserter(RepeatedPtrField<T>* const mutable_field) {
+ return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
+}
+
+// Special back insert iterator for RepeatedPtrField instances, just in
+// case someone wants to write generic template code that can access both
+// RepeatedFields and RepeatedPtrFields using a common name.
template<typename T> internal::RepeatedPtrFieldBackInsertIterator<T>
RepeatedFieldBackInserter(RepeatedPtrField<T>* const mutable_field) {
return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
diff --git a/src/google/protobuf/repeated_field_reflection.h b/src/google/protobuf/repeated_field_reflection.h
new file mode 100644
index 00000000..44d14d5b
--- /dev/null
+++ b/src/google/protobuf/repeated_field_reflection.h
@@ -0,0 +1,337 @@
+// 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 <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/generated_enum_reflection.h>
+
+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<T>::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<typename T>
+ T Get(const Field* data, int index) const {
+ typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+ ActualType scratch_space;
+ return static_cast<T>(
+ *reinterpret_cast<const ActualType*>(
+ Get(data, index, static_cast<Value*>(&scratch_space))));
+ }
+
+ template<typename T, typename ValueType>
+ void Set(Field* data, int index, const ValueType& value) const {
+ typedef typename RefTypeTraits<T>::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<ActualType>(value);
+ Set(data, index, static_cast<const Value*>(&tmp));
+ }
+
+ template<typename T, typename ValueType>
+ void Add(Field* data, const ValueType& value) const {
+ typedef typename RefTypeTraits<T>::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<ActualType>(value);
+ Add(data, static_cast<const Value*>(&tmp));
+ }
+};
+
+// Implement (Mutable)RepeatedFieldRef::iterator
+template<typename T>
+class RepeatedFieldRefIterator
+ : public std::iterator<std::forward_iterator_tag, T> {
+ typedef typename RefTypeTraits<T>::AccessorValueType AccessorValueType;
+ typedef typename RefTypeTraits<T>::IteratorValueType IteratorValueType;
+ typedef typename RefTypeTraits<T>::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<IteratorValueType>(
+ *static_cast<const AccessorValueType*>(
+ accessor_->GetIteratorValue(
+ data_, iterator_, scratch_space_.get())));
+ }
+ IteratorPointerType operator->() const {
+ return static_cast<IteratorPointerType>(
+ 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_;
+ google::protobuf::scoped_ptr<AccessorValueType> scratch_space_;
+};
+
+// TypeTraits that maps the type parameter T of RepeatedFieldRef or
+// MutableRepeatedFieldRef to corresponding iterator type,
+// RepeatedFieldAccessor type, etc.
+template<typename T>
+struct PrimitiveTraits {
+ static const bool is_primitive = false;
+};
+#define DEFINE_PRIMITIVE(TYPE, type) \
+ template<> struct PrimitiveTraits<type> { \
+ 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<typename T>
+struct RefTypeTraits<
+ T, typename internal::enable_if<PrimitiveTraits<T>::is_primitive>::type> {
+ typedef RepeatedFieldRefIterator<T> iterator;
+ typedef RepeatedFieldAccessor AccessorType;
+ typedef T AccessorValueType;
+ typedef T IteratorValueType;
+ typedef T* IteratorPointerType;
+ static const FieldDescriptor::CppType cpp_type =
+ PrimitiveTraits<T>::cpp_type;
+ static const Descriptor* GetMessageFieldDescriptor() {
+ return NULL;
+ }
+};
+
+template<typename T>
+struct RefTypeTraits<
+ T, typename internal::enable_if<is_proto_enum<T>::value>::type> {
+ typedef RepeatedFieldRefIterator<T> 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<typename T>
+struct RefTypeTraits<
+ T, typename internal::enable_if<internal::is_same<string, T>::value>::type> {
+ typedef RepeatedFieldRefIterator<T> 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<typename T>
+struct MessageDescriptorGetter {
+ static const Descriptor* get() {
+ return T::default_instance().GetDescriptor();
+ }
+};
+template<>
+struct MessageDescriptorGetter<Message> {
+ static const Descriptor* get() {
+ return NULL;
+ }
+};
+
+template<typename T>
+struct RefTypeTraits<
+ T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> {
+ typedef RepeatedFieldRefIterator<T> 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<T>::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
new file mode 100644
index 00000000..fcebe5ce
--- /dev/null
+++ b/src/google/protobuf/repeated_field_reflection_unittest.cc
@@ -0,0 +1,706 @@
+// 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: tgs@google.com (Tom Szymanski)
+//
+// Test reflection methods for aggregate access to Repeated[Ptr]Fields.
+// This test proto2 methods on a proto2 layout.
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/reflection.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+using unittest::ForeignMessage;
+using unittest::TestAllTypes;
+using unittest::TestAllExtensions;
+
+namespace {
+
+static int Func(int i, int j) {
+ return i * j;
+}
+
+static string StrFunc(int i, int j) {
+ string str;
+ SStringPrintf(&str, "%d", Func(i, 4));
+ return str;
+}
+
+TEST(RepeatedFieldReflectionTest, RegularFields) {
+ 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 RepeatedField objects for all fields of interest.
+ const RepeatedField<int32>& rf_int32 =
+ refl->GetRepeatedField<int32>(message, fd_repeated_int32);
+ const RepeatedField<double>& rf_double =
+ refl->GetRepeatedField<double>(message, fd_repeated_double);
+
+ // Get mutable RepeatedField objects for all fields of interest.
+ RepeatedField<int32>* mrf_int32 =
+ refl->MutableRepeatedField<int32>(&message, fd_repeated_int32);
+ RepeatedField<double>* mrf_double =
+ refl->MutableRepeatedField<double>(&message, fd_repeated_double);
+
+ // Get RepeatedPtrField objects for all fields of interest.
+ const RepeatedPtrField<string>& rpf_string =
+ refl->GetRepeatedPtrField<string>(message, fd_repeated_string);
+ const RepeatedPtrField<ForeignMessage>& rpf_foreign_message =
+ refl->GetRepeatedPtrField<ForeignMessage>(
+ message, fd_repeated_foreign_message);
+ const RepeatedPtrField<Message>& rpf_message =
+ refl->GetRepeatedPtrField<Message>(
+ message, fd_repeated_foreign_message);
+
+ // Get mutable RepeatedPtrField objects for all fields of interest.
+ RepeatedPtrField<string>* mrpf_string =
+ refl->MutableRepeatedPtrField<string>(&message, fd_repeated_string);
+ RepeatedPtrField<ForeignMessage>* mrpf_foreign_message =
+ refl->MutableRepeatedPtrField<ForeignMessage>(
+ &message, fd_repeated_foreign_message);
+ RepeatedPtrField<Message>* mrpf_message =
+ refl->MutableRepeatedPtrField<Message>(
+ &message, fd_repeated_foreign_message);
+
+ // 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));
+ EXPECT_EQ(rf_double.Get(i), Func(i, 2));
+ EXPECT_EQ(rpf_string.Get(i), StrFunc(i, 5));
+ EXPECT_EQ(rpf_foreign_message.Get(i).c(), Func(i, 6));
+ EXPECT_EQ(down_cast<const ForeignMessage*>(&rpf_message.Get(i))->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(mrpf_string->Get(i), StrFunc(i, 5));
+ EXPECT_EQ(mrpf_foreign_message->Get(i).c(), Func(i, 6));
+ EXPECT_EQ(down_cast<const ForeignMessage*>(&mrpf_message->Get(i))->c(),
+ Func(i, 6));
+
+ // Check sets through mutable objects.
+ mrf_int32->Set(i, Func(i, -1));
+ mrf_double->Set(i, Func(i, -2));
+ mrpf_string->Mutable(i)->assign(StrFunc(i, -5));
+ mrpf_foreign_message->Mutable(i)->set_c(Func(i, -6));
+ 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));
+ down_cast<ForeignMessage*>(mrpf_message->Mutable(i))->set_c(Func(i, 7));
+ EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, 7));
+ }
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+ // Make sure types are checked correctly at runtime.
+ const FieldDescriptor* fd_optional_int32 =
+ desc->FindFieldByName("optional_int32");
+ EXPECT_DEATH(refl->GetRepeatedField<int32>(
+ message, fd_optional_int32), "requires a repeated field");
+ EXPECT_DEATH(refl->GetRepeatedField<double>(
+ message, fd_repeated_int32), "not the right type");
+ EXPECT_DEATH(refl->GetRepeatedPtrField<TestAllTypes>(
+ message, fd_repeated_foreign_message), "wrong submessage type");
+#endif // PROTOBUF_HAS_DEATH_TEST
+}
+
+
+TEST(RepeatedFieldReflectionTest, ExtensionFields) {
+ 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 RepeatedField<int64>& rf_int64_extension =
+ refl->GetRepeatedField<int64>(extended_message,
+ fd_repeated_int64_extension);
+
+ RepeatedField<int64>* mrf_int64_extension =
+ refl->MutableRepeatedField<int64>(&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));
+ }
+}
+
+template<typename Ref, typename MessageType, typename ValueType>
+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) {
+ EXPECT_EQ((message.*GetFunc)(index), *it);
+ ++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<int32> rf_int32 =
+ refl->GetRepeatedFieldRef<int32>(message, fd_repeated_int32);
+ const RepeatedFieldRef<double> rf_double =
+ refl->GetRepeatedFieldRef<double>(message, fd_repeated_double);
+ const RepeatedFieldRef<string> rf_string =
+ refl->GetRepeatedFieldRef<string>(message, fd_repeated_string);
+ const RepeatedFieldRef<ForeignMessage> rf_foreign_message =
+ refl->GetRepeatedFieldRef<ForeignMessage>(
+ message, fd_repeated_foreign_message);
+ const RepeatedFieldRef<Message> rf_message =
+ refl->GetRepeatedFieldRef<Message>(
+ message, fd_repeated_foreign_message);
+
+ // Get MutableRepeatedFieldRef objects for all fields of interest.
+ const MutableRepeatedFieldRef<int32> mrf_int32 =
+ refl->GetMutableRepeatedFieldRef<int32>(&message, fd_repeated_int32);
+ const MutableRepeatedFieldRef<double> mrf_double =
+ refl->GetMutableRepeatedFieldRef<double>(&message, fd_repeated_double);
+ const MutableRepeatedFieldRef<string> mrf_string =
+ refl->GetMutableRepeatedFieldRef<string>(&message, fd_repeated_string);
+ const MutableRepeatedFieldRef<ForeignMessage> mrf_foreign_message =
+ refl->GetMutableRepeatedFieldRef<ForeignMessage>(
+ &message, fd_repeated_foreign_message);
+ const MutableRepeatedFieldRef<Message> mrf_message =
+ refl->GetMutableRepeatedFieldRef<Message>(
+ &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<const ForeignMessage&>(
+ 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<const ForeignMessage&>(
+ 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<ForeignMessage>::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());
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+ // Make sure types are checked correctly at runtime.
+ const FieldDescriptor* fd_optional_int32 =
+ desc->FindFieldByName("optional_int32");
+ EXPECT_DEATH(refl->GetRepeatedFieldRef<int32>(
+ message, fd_optional_int32), "");
+ EXPECT_DEATH(refl->GetRepeatedFieldRef<double>(
+ message, fd_repeated_int32), "");
+ EXPECT_DEATH(refl->GetRepeatedFieldRef<TestAllTypes>(
+ message, fd_repeated_foreign_message), "");
+
+#endif // PROTOBUF_HAS_DEATH_TEST
+}
+
+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<TestAllTypes::NestedEnum> enum_ref =
+ refl->GetRepeatedFieldRef<TestAllTypes::NestedEnum>(
+ message, fd_repeated_nested_enum);
+ const MutableRepeatedFieldRef<TestAllTypes::NestedEnum>
+ mutable_enum_ref =
+ refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
+ &message, fd_repeated_nested_enum);
+ const RepeatedFieldRef<int32> int32_ref =
+ refl->GetRepeatedFieldRef<int32>(
+ message, fd_repeated_nested_enum);
+ const MutableRepeatedFieldRef<int32> mutable_int32_ref =
+ refl->GetMutableRepeatedFieldRef<int32>(
+ &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<int64> rf_int64_extension =
+ refl->GetRepeatedFieldRef<int64>(extended_message,
+ fd_repeated_int64_extension);
+
+ const MutableRepeatedFieldRef<int64> mrf_int64_extension =
+ refl->GetMutableRepeatedFieldRef<int64>(&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<int32> mrf_int32 =
+ refl->GetMutableRepeatedFieldRef<int32>(&m0, fd_repeated_int32);
+ const MutableRepeatedFieldRef<double> mrf_double =
+ refl->GetMutableRepeatedFieldRef<double>(&m0, fd_repeated_double);
+ const MutableRepeatedFieldRef<string> mrf_string =
+ refl->GetMutableRepeatedFieldRef<string>(&m0, fd_repeated_string);
+ const MutableRepeatedFieldRef<ForeignMessage> mrf_foreign_message =
+ refl->GetMutableRepeatedFieldRef<ForeignMessage>(
+ &m0, fd_repeated_foreign_message);
+ const MutableRepeatedFieldRef<TestAllTypes::NestedEnum>
+ mrf_nested_enum =
+ refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
+ &m0, fd_repeated_nested_enum);
+
+ // Test MutableRepeatedRef::CopyFrom
+ mrf_int32.CopyFrom(
+ refl->GetRepeatedFieldRef<int32>(m1, fd_repeated_int32));
+ mrf_double.CopyFrom(
+ refl->GetRepeatedFieldRef<double>(m1, fd_repeated_double));
+ mrf_string.CopyFrom(
+ refl->GetRepeatedFieldRef<string>(m1, fd_repeated_string));
+ mrf_foreign_message.CopyFrom(
+ refl->GetRepeatedFieldRef<ForeignMessage>(
+ m1, fd_repeated_foreign_message));
+ mrf_nested_enum.CopyFrom(
+ refl->GetRepeatedFieldRef<TestAllTypes::NestedEnum>(
+ 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<int32>(m2, fd_repeated_int32));
+ mrf_double.MergeFrom(
+ refl->GetRepeatedFieldRef<double>(m2, fd_repeated_double));
+ mrf_string.MergeFrom(
+ refl->GetRepeatedFieldRef<string>(m2, fd_repeated_string));
+ mrf_foreign_message.MergeFrom(
+ refl->GetRepeatedFieldRef<ForeignMessage>(
+ m2, fd_repeated_foreign_message));
+ mrf_nested_enum.MergeFrom(
+ refl->GetRepeatedFieldRef<TestAllTypes::NestedEnum>(
+ 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<int32>(&m2, fd_repeated_int32));
+ mrf_double.Swap(
+ refl->GetMutableRepeatedFieldRef<double>(&m2, fd_repeated_double));
+ mrf_string.Swap(
+ refl->GetMutableRepeatedFieldRef<string>(&m2, fd_repeated_string));
+ mrf_foreign_message.Swap(
+ refl->GetMutableRepeatedFieldRef<ForeignMessage>(
+ &m2, fd_repeated_foreign_message));
+ mrf_nested_enum.Swap(
+ refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
+ &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;
+ google::protobuf::scoped_ptr<Message> dynamic_message(factory.GetPrototype(desc)->New());
+ const Reflection* refl = dynamic_message->GetReflection();
+
+ MutableRepeatedFieldRef<int32> rf_int32 =
+ refl->GetMutableRepeatedFieldRef<int32>(
+ 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 e7e1e99b..66e74523 100644
--- a/src/google/protobuf/repeated_field_unittest.cc
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -36,6 +36,7 @@
// other proto2 unittests.
#include <algorithm>
+#include <limits>
#include <list>
#include <vector>
@@ -46,7 +47,7 @@
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
using protobuf_unittest::TestAllTypes;
@@ -54,42 +55,49 @@ using protobuf_unittest::TestAllTypes;
namespace protobuf {
namespace {
-// Test operations on a RepeatedField which is small enough that it does
-// not allocate a separate array for storage.
+// Test operations on a small RepeatedField.
TEST(RepeatedField, Small) {
RepeatedField<int> field;
+ EXPECT_TRUE(field.empty());
EXPECT_EQ(field.size(), 0);
field.Add(5);
+ EXPECT_FALSE(field.empty());
EXPECT_EQ(field.size(), 1);
EXPECT_EQ(field.Get(0), 5);
field.Add(42);
+ EXPECT_FALSE(field.empty());
EXPECT_EQ(field.size(), 2);
EXPECT_EQ(field.Get(0), 5);
EXPECT_EQ(field.Get(1), 42);
field.Set(1, 23);
+ EXPECT_FALSE(field.empty());
EXPECT_EQ(field.size(), 2);
EXPECT_EQ(field.Get(0), 5);
EXPECT_EQ(field.Get(1), 23);
- EXPECT_EQ(field.SpaceUsedExcludingSelf(), 0);
field.RemoveLast();
+ EXPECT_FALSE(field.empty());
EXPECT_EQ(field.size(), 1);
EXPECT_EQ(field.Get(0), 5);
field.Clear();
+ EXPECT_TRUE(field.empty());
EXPECT_EQ(field.size(), 0);
- EXPECT_EQ(field.SpaceUsedExcludingSelf(), 0);
+ // Additional bytes are for 'struct Rep' header.
+ int expected_usage = 4 * sizeof(int) + sizeof(Arena*);
+ EXPECT_EQ(field.SpaceUsedExcludingSelf(), expected_usage);
}
+
// Test operations on a RepeatedField which is large enough to allocate a
// separate array.
TEST(RepeatedField, Large) {
@@ -99,6 +107,7 @@ TEST(RepeatedField, Large) {
field.Add(i * i);
}
+ EXPECT_FALSE(field.empty());
EXPECT_EQ(field.size(), 16);
for (int i = 0; i < 16; i++) {
@@ -117,9 +126,20 @@ TEST(RepeatedField, SwapSmallSmall) {
field1.Add(5);
field1.Add(42);
+ EXPECT_FALSE(field1.empty());
+ EXPECT_EQ(field1.size(), 2);
+ EXPECT_EQ(field1.Get(0), 5);
+ EXPECT_EQ(field1.Get(1), 42);
+
+ EXPECT_TRUE(field2.empty());
+ EXPECT_EQ(field2.size(), 0);
+
field1.Swap(&field2);
+ EXPECT_TRUE(field1.empty());
EXPECT_EQ(field1.size(), 0);
+
+ EXPECT_FALSE(field2.empty());
EXPECT_EQ(field2.size(), 2);
EXPECT_EQ(field2.Get(0), 5);
EXPECT_EQ(field2.Get(1), 42);
@@ -211,12 +231,26 @@ TEST(RepeatedField, ReserveLessThanExisting) {
EXPECT_EQ(20, ReservedSpace(&field));
}
+TEST(RepeatedField, Resize) {
+ RepeatedField<int> field;
+ field.Resize(2, 1);
+ EXPECT_EQ(2, field.size());
+ field.Resize(5, 2);
+ EXPECT_EQ(5, field.size());
+ field.Resize(4, 3);
+ ASSERT_EQ(4, field.size());
+ EXPECT_EQ(1, field.Get(0));
+ EXPECT_EQ(1, field.Get(1));
+ EXPECT_EQ(2, field.Get(2));
+ EXPECT_EQ(2, field.Get(3));
+ field.Resize(0, 4);
+ EXPECT_TRUE(field.empty());
+}
+
TEST(RepeatedField, MergeFrom) {
RepeatedField<int> source, destination;
-
source.Add(4);
source.Add(5);
-
destination.Add(1);
destination.Add(2);
destination.Add(3);
@@ -224,7 +258,6 @@ TEST(RepeatedField, MergeFrom) {
destination.MergeFrom(source);
ASSERT_EQ(5, destination.size());
-
EXPECT_EQ(1, destination.Get(0));
EXPECT_EQ(2, destination.Get(1));
EXPECT_EQ(3, destination.Get(2));
@@ -232,12 +265,18 @@ TEST(RepeatedField, MergeFrom) {
EXPECT_EQ(5, destination.Get(4));
}
+#ifdef PROTOBUF_HAS_DEATH_TEST
+TEST(RepeatedField, MergeFromSelf) {
+ RepeatedField<int> me;
+ me.Add(3);
+ EXPECT_DEATH(me.MergeFrom(me), "");
+}
+#endif // PROTOBUF_HAS_DEATH_TEST
+
TEST(RepeatedField, CopyFrom) {
RepeatedField<int> source, destination;
-
source.Add(4);
source.Add(5);
-
destination.Add(1);
destination.Add(2);
destination.Add(3);
@@ -245,11 +284,51 @@ TEST(RepeatedField, CopyFrom) {
destination.CopyFrom(source);
ASSERT_EQ(2, destination.size());
-
EXPECT_EQ(4, destination.Get(0));
EXPECT_EQ(5, destination.Get(1));
}
+TEST(RepeatedField, CopyFromSelf) {
+ RepeatedField<int> me;
+ me.Add(3);
+ me.CopyFrom(me);
+ ASSERT_EQ(1, me.size());
+ EXPECT_EQ(3, me.Get(0));
+}
+
+TEST(RepeatedField, Erase) {
+ RepeatedField<int> me;
+ RepeatedField<int>::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<int> source;
source.Add(1);
@@ -262,12 +341,26 @@ TEST(RepeatedField, CopyConstruct) {
EXPECT_EQ(2, destination.Get(1));
}
+TEST(RepeatedField, IteratorConstruct) {
+ vector<int> values;
+ values.push_back(1);
+ values.push_back(2);
+
+ RepeatedField<int> field(values.begin(), values.end());
+ ASSERT_EQ(values.size(), field.size());
+ EXPECT_EQ(values[0], field.Get(0));
+ EXPECT_EQ(values[1], field.Get(1));
+
+ RepeatedField<int> other(field.begin(), field.end());
+ ASSERT_EQ(values.size(), other.size());
+ EXPECT_EQ(values[0], other.Get(0));
+ EXPECT_EQ(values[1], other.Get(1));
+}
+
TEST(RepeatedField, CopyAssign) {
RepeatedField<int> source, destination;
-
source.Add(4);
source.Add(5);
-
destination.Add(1);
destination.Add(2);
destination.Add(3);
@@ -275,11 +368,24 @@ TEST(RepeatedField, CopyAssign) {
destination = source;
ASSERT_EQ(2, destination.size());
-
EXPECT_EQ(4, destination.Get(0));
EXPECT_EQ(5, destination.Get(1));
}
+TEST(RepeatedField, SelfAssign) {
+ // Verify that assignment to self does not destroy data.
+ RepeatedField<int> source, *p;
+ p = &source;
+ source.Add(7);
+ source.Add(8);
+
+ *p = source;
+
+ ASSERT_EQ(2, source.size());
+ EXPECT_EQ(7, source.Get(0));
+ EXPECT_EQ(8, source.Get(1));
+}
+
TEST(RepeatedField, MutableDataIsMutable) {
RepeatedField<int> field;
field.Add(1);
@@ -309,12 +415,47 @@ TEST(RepeatedField, Truncate) {
// Truncations that don't change the size are allowed, but growing is not
// allowed.
field.Truncate(field.size());
-#ifdef GTEST_HAS_DEATH_TEST
+#ifdef PROTOBUF_HAS_DEATH_TEST
EXPECT_DEBUG_DEATH(field.Truncate(field.size() + 1), "new_size");
#endif
}
+TEST(RepeatedField, ExtractSubrange) {
+ // Exhaustively test every subrange in arrays of all sizes from 0 through 9.
+ for (int sz = 0; sz < 10; ++sz) {
+ for (int num = 0; num <= sz; ++num) {
+ for (int start = 0; start < sz - num; ++start) {
+ // Create RepeatedField with sz elements having values 0 through sz-1.
+ RepeatedField<int32> field;
+ for (int i = 0; i < sz; ++i)
+ field.Add(i);
+ EXPECT_EQ(field.size(), sz);
+
+ // Create a catcher array and call ExtractSubrange.
+ int32 catcher[10];
+ for (int i = 0; i < 10; ++i)
+ catcher[i] = -1;
+ field.ExtractSubrange(start, num, catcher);
+
+ // Does the resulting array have the right size?
+ EXPECT_EQ(field.size(), sz - num);
+
+ // Were the removed elements extracted into the catcher array?
+ for (int i = 0; i < num; ++i)
+ EXPECT_EQ(catcher[i], start + i);
+ EXPECT_EQ(catcher[num], -1);
+
+ // Does the resulting array contain the right values?
+ for (int i = 0; i < start; ++i)
+ EXPECT_EQ(field.Get(i), i);
+ for (int i = start; i < field.size(); ++i)
+ EXPECT_EQ(field.Get(i), i + num);
+ }
+ }
+ }
+}
+
// ===================================================================
// RepeatedPtrField tests. These pretty much just mirror the RepeatedField
// tests above.
@@ -322,32 +463,38 @@ TEST(RepeatedField, Truncate) {
TEST(RepeatedPtrField, Small) {
RepeatedPtrField<string> field;
+ EXPECT_TRUE(field.empty());
EXPECT_EQ(field.size(), 0);
field.Add()->assign("foo");
+ EXPECT_FALSE(field.empty());
EXPECT_EQ(field.size(), 1);
EXPECT_EQ(field.Get(0), "foo");
field.Add()->assign("bar");
+ EXPECT_FALSE(field.empty());
EXPECT_EQ(field.size(), 2);
EXPECT_EQ(field.Get(0), "foo");
EXPECT_EQ(field.Get(1), "bar");
field.Mutable(1)->assign("baz");
+ EXPECT_FALSE(field.empty());
EXPECT_EQ(field.size(), 2);
EXPECT_EQ(field.Get(0), "foo");
EXPECT_EQ(field.Get(1), "baz");
field.RemoveLast();
+ EXPECT_FALSE(field.empty());
EXPECT_EQ(field.size(), 1);
EXPECT_EQ(field.Get(0), "foo");
field.Clear();
+ EXPECT_TRUE(field.empty());
EXPECT_EQ(field.size(), 0);
}
@@ -373,11 +520,27 @@ TEST(RepeatedPtrField, SwapSmallSmall) {
RepeatedPtrField<string> field1;
RepeatedPtrField<string> field2;
+ EXPECT_TRUE(field1.empty());
+ EXPECT_EQ(field1.size(), 0);
+ EXPECT_TRUE(field2.empty());
+ EXPECT_EQ(field2.size(), 0);
+
field1.Add()->assign("foo");
field1.Add()->assign("bar");
+
+ EXPECT_FALSE(field1.empty());
+ EXPECT_EQ(field1.size(), 2);
+ EXPECT_EQ(field1.Get(0), "foo");
+ EXPECT_EQ(field1.Get(1), "bar");
+
+ EXPECT_TRUE(field2.empty());
+ EXPECT_EQ(field2.size(), 0);
+
field1.Swap(&field2);
+ EXPECT_TRUE(field1.empty());
EXPECT_EQ(field1.size(), 0);
+
EXPECT_EQ(field2.size(), 2);
EXPECT_EQ(field2.Get(0), "foo");
EXPECT_EQ(field2.Get(1), "bar");
@@ -565,10 +728,8 @@ TEST(RepeatedPtrField, AddAlocated) {
TEST(RepeatedPtrField, MergeFrom) {
RepeatedPtrField<string> source, destination;
-
source.Add()->assign("4");
source.Add()->assign("5");
-
destination.Add()->assign("1");
destination.Add()->assign("2");
destination.Add()->assign("3");
@@ -576,7 +737,6 @@ TEST(RepeatedPtrField, MergeFrom) {
destination.MergeFrom(source);
ASSERT_EQ(5, destination.size());
-
EXPECT_EQ("1", destination.Get(0));
EXPECT_EQ("2", destination.Get(1));
EXPECT_EQ("3", destination.Get(2));
@@ -584,12 +744,18 @@ TEST(RepeatedPtrField, MergeFrom) {
EXPECT_EQ("5", destination.Get(4));
}
+#ifdef PROTOBUF_HAS_DEATH_TEST
+TEST(RepeatedPtrField, MergeFromSelf) {
+ RepeatedPtrField<string> me;
+ me.Add()->assign("1");
+ EXPECT_DEATH(me.MergeFrom(me), "");
+}
+#endif // PROTOBUF_HAS_DEATH_TEST
+
TEST(RepeatedPtrField, CopyFrom) {
RepeatedPtrField<string> source, destination;
-
source.Add()->assign("4");
source.Add()->assign("5");
-
destination.Add()->assign("1");
destination.Add()->assign("2");
destination.Add()->assign("3");
@@ -597,14 +763,53 @@ TEST(RepeatedPtrField, CopyFrom) {
destination.CopyFrom(source);
ASSERT_EQ(2, destination.size());
-
EXPECT_EQ("4", destination.Get(0));
EXPECT_EQ("5", destination.Get(1));
}
+TEST(RepeatedPtrField, CopyFromSelf) {
+ RepeatedPtrField<string> me;
+ me.Add()->assign("1");
+ me.CopyFrom(me);
+ ASSERT_EQ(1, me.size());
+ EXPECT_EQ("1", me.Get(0));
+}
+
+TEST(RepeatedPtrField, Erase) {
+ RepeatedPtrField<string> me;
+ RepeatedPtrField<string>::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<string> source;
-
source.Add()->assign("1");
source.Add()->assign("2");
@@ -615,12 +820,45 @@ TEST(RepeatedPtrField, CopyConstruct) {
EXPECT_EQ("2", destination.Get(1));
}
+TEST(RepeatedPtrField, IteratorConstruct_String) {
+ vector<string> values;
+ values.push_back("1");
+ values.push_back("2");
+
+ RepeatedPtrField<string> field(values.begin(), values.end());
+ ASSERT_EQ(values.size(), field.size());
+ EXPECT_EQ(values[0], field.Get(0));
+ EXPECT_EQ(values[1], field.Get(1));
+
+ RepeatedPtrField<string> other(field.begin(), field.end());
+ ASSERT_EQ(values.size(), other.size());
+ EXPECT_EQ(values[0], other.Get(0));
+ EXPECT_EQ(values[1], other.Get(1));
+}
+
+TEST(RepeatedPtrField, IteratorConstruct_Proto) {
+ typedef TestAllTypes::NestedMessage Nested;
+ vector<Nested> values;
+ values.push_back(Nested());
+ values.back().set_bb(1);
+ values.push_back(Nested());
+ values.back().set_bb(2);
+
+ RepeatedPtrField<Nested> field(values.begin(), values.end());
+ ASSERT_EQ(values.size(), field.size());
+ EXPECT_EQ(values[0].bb(), field.Get(0).bb());
+ EXPECT_EQ(values[1].bb(), field.Get(1).bb());
+
+ RepeatedPtrField<Nested> other(field.begin(), field.end());
+ ASSERT_EQ(values.size(), other.size());
+ EXPECT_EQ(values[0].bb(), other.Get(0).bb());
+ EXPECT_EQ(values[1].bb(), other.Get(1).bb());
+}
+
TEST(RepeatedPtrField, CopyAssign) {
RepeatedPtrField<string> source, destination;
-
source.Add()->assign("4");
source.Add()->assign("5");
-
destination.Add()->assign("1");
destination.Add()->assign("2");
destination.Add()->assign("3");
@@ -628,11 +866,24 @@ TEST(RepeatedPtrField, CopyAssign) {
destination = source;
ASSERT_EQ(2, destination.size());
-
EXPECT_EQ("4", destination.Get(0));
EXPECT_EQ("5", destination.Get(1));
}
+TEST(RepeatedPtrField, SelfAssign) {
+ // Verify that assignment to self does not destroy data.
+ RepeatedPtrField<string> source, *p;
+ p = &source;
+ source.Add()->assign("7");
+ source.Add()->assign("8");
+
+ *p = source;
+
+ ASSERT_EQ(2, source.size());
+ EXPECT_EQ("7", source.Get(0));
+ EXPECT_EQ("8", source.Get(1));
+}
+
TEST(RepeatedPtrField, MutableDataIsMutable) {
RepeatedPtrField<string> field;
*field.Add() = "1";
@@ -644,6 +895,77 @@ TEST(RepeatedPtrField, MutableDataIsMutable) {
EXPECT_EQ("2", field.Get(0));
}
+TEST(RepeatedPtrField, ExtractSubrange) {
+ // Exhaustively test every subrange in arrays of all sizes from 0 through 9
+ // with 0 through 3 cleared elements at the end.
+ for (int sz = 0; sz < 10; ++sz) {
+ for (int num = 0; num <= sz; ++num) {
+ for (int start = 0; start < sz - num; ++start) {
+ for (int extra = 0; extra < 4; ++extra) {
+ vector<string*> subject;
+
+ // Create an array with "sz" elements and "extra" cleared elements.
+ RepeatedPtrField<string> field;
+ for (int i = 0; i < sz + extra; ++i) {
+ subject.push_back(new string());
+ field.AddAllocated(subject[i]);
+ }
+ EXPECT_EQ(field.size(), sz + extra);
+ for (int i = 0; i < extra; ++i)
+ field.RemoveLast();
+ EXPECT_EQ(field.size(), sz);
+ EXPECT_EQ(field.ClearedCount(), extra);
+
+ // Create a catcher array and call ExtractSubrange.
+ string* catcher[10];
+ for (int i = 0; i < 10; ++i)
+ catcher[i] = NULL;
+ field.ExtractSubrange(start, num, catcher);
+
+ // Does the resulting array have the right size?
+ EXPECT_EQ(field.size(), sz - num);
+
+ // Were the removed elements extracted into the catcher array?
+ for (int i = 0; i < num; ++i)
+ EXPECT_EQ(catcher[i], subject[start + i]);
+ EXPECT_EQ(NULL, catcher[num]);
+
+ // Does the resulting array contain the right values?
+ for (int i = 0; i < start; ++i)
+ EXPECT_EQ(field.Mutable(i), subject[i]);
+ for (int i = start; i < field.size(); ++i)
+ EXPECT_EQ(field.Mutable(i), subject[i + num]);
+
+ // Reinstate the cleared elements.
+ EXPECT_EQ(field.ClearedCount(), extra);
+ for (int i = 0; i < extra; ++i)
+ field.Add();
+ EXPECT_EQ(field.ClearedCount(), 0);
+ EXPECT_EQ(field.size(), sz - num + extra);
+
+ // Make sure the extra elements are all there (in some order).
+ for (int i = sz; i < sz + extra; ++i) {
+ int count = 0;
+ for (int j = sz; j < sz + extra; ++j) {
+ if (field.Mutable(j - num) == subject[i])
+ count += 1;
+ }
+ EXPECT_EQ(count, 1);
+ }
+
+ // Release the caught elements.
+ for (int i = 0; i < num; ++i)
+ delete catcher[i];
+ }
+ }
+ }
+ }
+}
+
+TEST(RepeatedPtrField, DeleteSubrange) {
+ // DeleteSubrange is a trivial extension of ExtendSubrange.
+}
+
// ===================================================================
// Iterator tests stolen from net/proto/proto-array_unittest.
@@ -738,6 +1060,30 @@ TEST_F(RepeatedPtrFieldIteratorTest, ConstIteration) {
EXPECT_EQ("baz", *(--const_proto_array.end()));
}
+TEST_F(RepeatedPtrFieldIteratorTest, MutableReverseIteration) {
+ RepeatedPtrField<string>::reverse_iterator iter = proto_array_.rbegin();
+ EXPECT_EQ("baz", *iter);
+ ++iter;
+ EXPECT_EQ("bar", *(iter++));
+ EXPECT_EQ("foo", *iter);
+ ++iter;
+ EXPECT_TRUE(proto_array_.rend() == iter);
+ EXPECT_EQ("foo", *(--proto_array_.rend()));
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, ConstReverseIteration) {
+ const RepeatedPtrField<string>& const_proto_array = proto_array_;
+ RepeatedPtrField<string>::const_reverse_iterator iter
+ = const_proto_array.rbegin();
+ EXPECT_EQ("baz", *iter);
+ ++iter;
+ EXPECT_EQ("bar", *(iter++));
+ EXPECT_EQ("foo", *iter);
+ ++iter;
+ EXPECT_TRUE(const_proto_array.rend() == iter);
+ EXPECT_EQ("foo", *(--const_proto_array.rend()));
+}
+
TEST_F(RepeatedPtrFieldIteratorTest, RandomAccess) {
RepeatedPtrField<string>::iterator iter = proto_array_.begin();
RepeatedPtrField<string>::iterator iter2 = iter;
@@ -785,7 +1131,7 @@ TEST_F(RepeatedPtrFieldIteratorTest, STLAlgorithms_lower_bound) {
string v = "f";
RepeatedPtrField<string>::const_iterator it =
- lower_bound(proto_array_.begin(), proto_array_.end(), v);
+ std::lower_bound(proto_array_.begin(), proto_array_.end(), v);
EXPECT_EQ(*it, "n");
EXPECT_TRUE(it == proto_array_.begin() + 3);
@@ -805,14 +1151,23 @@ class RepeatedPtrFieldPtrsIteratorTest : public testing::Test {
proto_array_.Add()->assign("foo");
proto_array_.Add()->assign("bar");
proto_array_.Add()->assign("baz");
+ const_proto_array_ = &proto_array_;
}
RepeatedPtrField<string> proto_array_;
+ const RepeatedPtrField<string>* const_proto_array_;
};
TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertiblePtr) {
RepeatedPtrField<string>::pointer_iterator iter =
proto_array_.pointer_begin();
+ static_cast<void>(iter);
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertibleConstPtr) {
+ RepeatedPtrField<string>::const_pointer_iterator iter =
+ const_proto_array_->pointer_begin();
+ static_cast<void>(iter);
}
TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) {
@@ -827,6 +1182,18 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) {
EXPECT_EQ("baz", **(--proto_array_.pointer_end()));
}
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutableConstPtrIteration) {
+ RepeatedPtrField<string>::const_pointer_iterator iter =
+ const_proto_array_->pointer_begin();
+ EXPECT_EQ("foo", **iter);
+ ++iter;
+ EXPECT_EQ("bar", **(iter++));
+ EXPECT_EQ("baz", **iter);
+ ++iter;
+ EXPECT_TRUE(const_proto_array_->pointer_end() == iter);
+ EXPECT_EQ("baz", **(--const_proto_array_->pointer_end()));
+}
+
TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomPtrAccess) {
RepeatedPtrField<string>::pointer_iterator iter =
proto_array_.pointer_begin();
@@ -840,6 +1207,19 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomPtrAccess) {
EXPECT_EQ(3, proto_array_.end() - proto_array_.begin());
}
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomConstPtrAccess) {
+ RepeatedPtrField<string>::const_pointer_iterator iter =
+ const_proto_array_->pointer_begin();
+ RepeatedPtrField<string>::const_pointer_iterator iter2 = iter;
+ ++iter2;
+ ++iter2;
+ EXPECT_TRUE(iter + 2 == iter2);
+ EXPECT_TRUE(iter == iter2 - 2);
+ EXPECT_EQ("baz", *iter[2]);
+ EXPECT_EQ("baz", **(iter + 2));
+ EXPECT_EQ(3, const_proto_array_->end() - const_proto_array_->begin());
+}
+
TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) {
RepeatedPtrField<string>::pointer_iterator iter =
proto_array_.pointer_begin();
@@ -854,6 +1234,20 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) {
EXPECT_TRUE(iter >= iter);
}
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparableConstPtr) {
+ RepeatedPtrField<string>::const_pointer_iterator iter =
+ const_proto_array_->pointer_begin();
+ RepeatedPtrField<string>::const_pointer_iterator iter2 = iter + 1;
+ EXPECT_TRUE(iter == iter);
+ EXPECT_TRUE(iter != iter2);
+ EXPECT_TRUE(iter < iter2);
+ EXPECT_TRUE(iter <= iter2);
+ EXPECT_TRUE(iter <= iter);
+ EXPECT_TRUE(iter2 > iter);
+ EXPECT_TRUE(iter2 >= iter);
+ EXPECT_TRUE(iter >= iter);
+}
+
// Uninitialized iterator does not point to any of the RepeatedPtrOverPtrs.
// Dereferencing an uninitialized iterator crashes the process.
TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) {
@@ -865,6 +1259,14 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) {
EXPECT_TRUE(iter != proto_array_.pointer_end());
}
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedConstPtrIterator) {
+ RepeatedPtrField<string>::const_pointer_iterator iter;
+ EXPECT_TRUE(iter != const_proto_array_->pointer_begin());
+ EXPECT_TRUE(iter != const_proto_array_->pointer_begin() + 1);
+ EXPECT_TRUE(iter != const_proto_array_->pointer_begin() + 2);
+ EXPECT_TRUE(iter != const_proto_array_->pointer_begin() + 3);
+ EXPECT_TRUE(iter != const_proto_array_->pointer_end());
+}
// This comparison functor is required by the tests for RepeatedPtrOverPtrs.
// They operate on strings and need to compare strings as strings in
@@ -874,9 +1276,7 @@ struct StringLessThan {
bool operator()(const string* z, const string& y) {
return *z < y;
}
- bool operator()(const string* z, const string* y) {
- return *z < *y;
- }
+ bool operator()(const string* z, const string* y) const { return *z < *y; }
};
TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrSTLAlgorithms_lower_bound) {
@@ -889,17 +1289,28 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrSTLAlgorithms_lower_bound) {
proto_array_.Add()->assign("x");
proto_array_.Add()->assign("y");
- RepeatedPtrField<string>::pointer_iterator iter =
- proto_array_.pointer_begin();
- string v = "f";
- RepeatedPtrField<string>::pointer_iterator it =
- lower_bound(proto_array_.pointer_begin(), proto_array_.pointer_end(),
- &v, StringLessThan());
+ {
+ string v = "f";
+ RepeatedPtrField<string>::pointer_iterator it =
+ std::lower_bound(proto_array_.pointer_begin(),
+ proto_array_.pointer_end(), &v, StringLessThan());
+
+ GOOGLE_CHECK(*it != NULL);
+
+ EXPECT_EQ(**it, "n");
+ EXPECT_TRUE(it == proto_array_.pointer_begin() + 3);
+ }
+ {
+ string v = "f";
+ RepeatedPtrField<string>::const_pointer_iterator it = std::lower_bound(
+ const_proto_array_->pointer_begin(), const_proto_array_->pointer_end(),
+ &v, StringLessThan());
- GOOGLE_CHECK(*it != NULL);
+ GOOGLE_CHECK(*it != NULL);
- EXPECT_EQ(**it, "n");
- EXPECT_TRUE(it == proto_array_.pointer_begin() + 3);
+ EXPECT_EQ(**it, "n");
+ EXPECT_TRUE(it == const_proto_array_->pointer_begin() + 3);
+ }
}
TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrMutation) {
@@ -931,9 +1342,8 @@ TEST_F(RepeatedPtrFieldPtrsIteratorTest, Sort) {
EXPECT_EQ("foo", proto_array_.Get(0));
EXPECT_EQ("n", proto_array_.Get(5));
EXPECT_EQ("x", proto_array_.Get(9));
- sort(proto_array_.pointer_begin(),
- proto_array_.pointer_end(),
- StringLessThan());
+ std::sort(proto_array_.pointer_begin(), proto_array_.pointer_end(),
+ StringLessThan());
EXPECT_EQ("a", proto_array_.Get(0));
EXPECT_EQ("baz", proto_array_.Get(2));
EXPECT_EQ("y", proto_array_.Get(9));
@@ -1025,13 +1435,24 @@ TEST_F(RepeatedFieldInsertionIteratorsTest, Halves) {
TEST_F(RepeatedFieldInsertionIteratorsTest, Words) {
ASSERT_EQ(words.size(), protobuffer.repeated_string_size());
- EXPECT_EQ(words.at(0), protobuffer.repeated_string(0));
- EXPECT_EQ(words.at(1), protobuffer.repeated_string(1));
- EXPECT_EQ(words.at(2), protobuffer.repeated_string(2));
- EXPECT_EQ(words.at(3), protobuffer.repeated_string(3));
- EXPECT_EQ(words.at(4), protobuffer.repeated_string(4));
- EXPECT_EQ(words.at(5), protobuffer.repeated_string(5));
- EXPECT_EQ(words.at(6), protobuffer.repeated_string(6));
+ for (int i = 0; i < words.size(); ++i)
+ EXPECT_EQ(words.at(i), protobuffer.repeated_string(i));
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest, Words2) {
+ words.clear();
+ words.push_back("sing");
+ words.push_back("a");
+ words.push_back("song");
+ words.push_back("of");
+ words.push_back("six");
+ words.push_back("pence");
+ protobuffer.mutable_repeated_string()->Clear();
+ std::copy(words.begin(), words.end(), RepeatedPtrFieldBackInserter(
+ protobuffer.mutable_repeated_string()));
+ ASSERT_EQ(words.size(), protobuffer.repeated_string_size());
+ for (int i = 0; i < words.size(); ++i)
+ EXPECT_EQ(words.at(i), protobuffer.repeated_string(i));
}
TEST_F(RepeatedFieldInsertionIteratorsTest, Nesteds) {
@@ -1055,9 +1476,9 @@ TEST_F(RepeatedFieldInsertionIteratorsTest,
new_data->set_bb(i);
}
TestAllTypes testproto;
- copy(data.begin(), data.end(),
- AllocatedRepeatedPtrFieldBackInserter(
- testproto.mutable_repeated_nested_message()));
+ std::copy(data.begin(), data.end(),
+ AllocatedRepeatedPtrFieldBackInserter(
+ testproto.mutable_repeated_nested_message()));
EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
}
@@ -1074,9 +1495,8 @@ TEST_F(RepeatedFieldInsertionIteratorsTest,
*new_data = "name-" + SimpleItoa(i);
}
TestAllTypes testproto;
- copy(data.begin(), data.end(),
- AllocatedRepeatedPtrFieldBackInserter(
- testproto.mutable_repeated_string()));
+ std::copy(data.begin(), data.end(), AllocatedRepeatedPtrFieldBackInserter(
+ testproto.mutable_repeated_string()));
EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
}
diff --git a/src/google/protobuf/service.cc b/src/google/protobuf/service.cc
index caf968ca..ffa919da 100644
--- a/src/google/protobuf/service.cc
+++ b/src/google/protobuf/service.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/service.h b/src/google/protobuf/service.h
index a6a7d16d..cc0b45d4 100644
--- a/src/google/protobuf/service.h
+++ b/src/google/protobuf/service.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto
new file mode 100644
index 00000000..9f27eb43
--- /dev/null
+++ b/src/google/protobuf/struct.proto
@@ -0,0 +1,83 @@
+// 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 google.protobuf;
+
+option java_generate_equals_and_hash = true;
+option java_multiple_files = true;
+option java_outer_classname = "StructProto";
+option java_package = "com.google.protobuf";
+
+
+// `Struct` represents a structured data value, consisting of fields
+// which map to dynamically typed values. In some languages, `Struct`
+// might be supported by a native representation. For example, in
+// scripting languages like JS a struct is represented as an
+// object. The details of that representation are described together
+// with the proto support for the language.
+message Struct {
+ // Map of dynamically typed values.
+ map<string, Value> fields = 1;
+}
+
+// `Value` represents a dynamically typed value which can be either
+// null, a number, a string, a boolean, a recursive struct value, or a
+// list of values. A producer of value is expected to set one of that
+// variants, absence of any variant indicates an error.
+message Value {
+ oneof kind {
+ // Represents a null value.
+ NullValue null_value = 1;
+ // Represents a double value.
+ double number_value = 2;
+ // Represents a string value.
+ string string_value = 3;
+ // Represents a boolean value.
+ bool bool_value = 4;
+ // Represents a structured value.
+ Struct struct_value = 5;
+ // Represents a repeated `Value`.
+ ListValue list_value = 6;
+ }
+}
+
+// `NullValue` is a singleton enumeration to represent the null
+// value for the `Value` type union.
+enum NullValue {
+ // Null value.
+ NULL_VALUE = 0;
+}
+
+// `ListValue` is a wrapper around a repeated field of values.
+message ListValue {
+ // Repeated field of dynamically typed values.
+ repeated Value values = 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 <google/protobuf/stubs/atomicops.h>
+
+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/atomicops.h b/src/google/protobuf/stubs/atomicops.h
new file mode 100644
index 00000000..bbe2d845
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops.h
@@ -0,0 +1,241 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 routines exported by this module are subtle. If you use them, even if
+// you get the code right, it will depend on careful reasoning about atomicity
+// and memory ordering; it will be less readable, and harder to maintain. If
+// you plan to use these routines, you should have a good reason, such as solid
+// evidence that performance would otherwise suffer, or there being no
+// alternative. You should assume only properties explicitly guaranteed by the
+// specifications in this file. You are almost certainly _not_ writing code
+// just for the x86; if you assume x86 semantics, x86 hardware bugs and
+// implementations on other archtectures will cause your code to break. If you
+// do not know what you are doing, avoid these routines, and use a Mutex.
+//
+// It is incorrect to make direct assignments to/from an atomic variable.
+// You should use one of the Load or Store routines. The NoBarrier
+// versions are provided when no barriers are needed:
+// NoBarrier_Store()
+// NoBarrier_Load()
+// Although there are currently no compiler enforcement, you are encouraged
+// to use these.
+
+// This header and the implementations for each platform (located in
+// atomicops_internals_*) must be kept in sync with the upstream code (V8).
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_H_
+
+// Don't include this file for people not concerned about thread safety.
+#ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
+
+#include <google/protobuf/stubs/platform_macros.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#if defined(GOOGLE_PROTOBUF_ARCH_POWER)
+#if defined(_LP64) || defined(__LP64__)
+typedef int32 Atomic32;
+typedef intptr_t Atomic64;
+#else
+typedef intptr_t Atomic32;
+typedef int64 Atomic64;
+#endif
+#else
+typedef int32 Atomic32;
+#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
+// We need to be able to go between Atomic64 and AtomicWord implicitly. This
+// means Atomic64 and AtomicWord should be the same type on 64-bit.
+#if defined(__ILP32__) || defined(GOOGLE_PROTOBUF_OS_NACL) || defined(GOOGLE_PROTOBUF_ARCH_SPARC)
+// NaCl's intptr_t is not actually 64-bits on 64-bit!
+// http://code.google.com/p/nativeclient/issues/detail?id=1162
+// sparcv9's pointer type is 32bits
+typedef int64 Atomic64;
+#else
+typedef intptr_t Atomic64;
+#endif
+#endif
+#endif
+
+// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
+// Atomic64 routines below, depending on your architecture.
+typedef intptr_t AtomicWord;
+
+// Atomically execute:
+// result = *ptr;
+// if (*ptr == old_value)
+// *ptr = new_value;
+// return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr. This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
+
+// Atomically increment *ptr by "increment". Returns the new value of
+// *ptr with the increment applied. This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
+
+Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment);
+
+// These following lower-level operations are typically useful only to people
+// implementing higher-level synchronization operations like spinlocks,
+// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or
+// a store with appropriate memory-ordering instructions. "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation. "Barrier" operations have both "Acquire" and "Release"
+// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+
+#if defined(__MINGW32__) && defined(MemoryBarrier)
+#undef MemoryBarrier
+#endif
+void MemoryBarrier();
+void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
+void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
+void Release_Store(volatile Atomic32* ptr, Atomic32 value);
+
+Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
+Atomic32 Acquire_Load(volatile const Atomic32* ptr);
+Atomic32 Release_Load(volatile const Atomic32* ptr);
+
+// 64-bit atomic operations (only available on 64-bit processors).
+#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
+Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
+Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+
+Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
+void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
+void Release_Store(volatile Atomic64* ptr, Atomic64 value);
+Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
+Atomic64 Acquire_Load(volatile const Atomic64* ptr);
+Atomic64 Release_Load(volatile const Atomic64* ptr);
+#endif // GOOGLE_PROTOBUF_ARCH_64_BIT
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+// Include our platform specific implementation.
+#define GOOGLE_PROTOBUF_ATOMICOPS_ERROR \
+#error "Atomic operations are not supported on your platform"
+
+// ThreadSanitizer, http://clang.llvm.org/docs/ThreadSanitizer.html.
+#if defined(THREAD_SANITIZER)
+#include <google/protobuf/stubs/atomicops_internals_tsan.h>
+// MSVC.
+#elif defined(_MSC_VER)
+#if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64)
+#include <google/protobuf/stubs/atomicops_internals_x86_msvc.h>
+#else
+GOOGLE_PROTOBUF_ATOMICOPS_ERROR
+#endif
+
+// Solaris
+#elif defined(GOOGLE_PROTOBUF_OS_SOLARIS)
+#include <google/protobuf/stubs/atomicops_internals_solaris.h>
+
+// AIX
+#elif defined(GOOGLE_PROTOBUF_OS_AIX)
+#include <google/protobuf/stubs/atomicops_internals_aix.h>
+
+// Apple.
+#elif defined(GOOGLE_PROTOBUF_OS_APPLE)
+#include <google/protobuf/stubs/atomicops_internals_macosx.h>
+
+// GCC.
+#elif defined(__GNUC__)
+#if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64)
+#include <google/protobuf/stubs/atomicops_internals_x86_gcc.h>
+#elif defined(GOOGLE_PROTOBUF_ARCH_ARM) && defined(__linux__)
+#include <google/protobuf/stubs/atomicops_internals_arm_gcc.h>
+#elif defined(GOOGLE_PROTOBUF_ARCH_AARCH64)
+#include <google/protobuf/stubs/atomicops_internals_arm64_gcc.h>
+#elif defined(GOOGLE_PROTOBUF_ARCH_ARM_QNX)
+#include <google/protobuf/stubs/atomicops_internals_arm_qnx.h>
+#elif defined(GOOGLE_PROTOBUF_ARCH_MIPS) || defined(GOOGLE_PROTOBUF_ARCH_MIPS64)
+#include <google/protobuf/stubs/atomicops_internals_mips_gcc.h>
+#elif defined(__native_client__)
+#include <google/protobuf/stubs/atomicops_internals_pnacl.h>
+#elif (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
+#include <google/protobuf/stubs/atomicops_internals_generic_gcc.h>
+#elif defined(__clang__)
+#if __has_extension(c_atomic)
+#include <google/protobuf/stubs/atomicops_internals_generic_gcc.h>
+#else
+GOOGLE_PROTOBUF_ATOMICOPS_ERROR
+#endif
+#else
+GOOGLE_PROTOBUF_ATOMICOPS_ERROR
+#endif
+
+// Unknown.
+#else
+GOOGLE_PROTOBUF_ATOMICOPS_ERROR
+#endif
+
+// On some platforms we need additional declarations to make AtomicWord
+// compatible with our other Atomic* types.
+#if defined(GOOGLE_PROTOBUF_OS_APPLE)
+#include <google/protobuf/stubs/atomicops_internals_atomicword_compat.h>
+#endif
+
+#undef GOOGLE_PROTOBUF_ATOMICOPS_ERROR
+
+#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_aix.h b/src/google/protobuf/stubs/atomicops_internals_aix.h
new file mode 100644
index 00000000..b8a42f21
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_aix.h
@@ -0,0 +1,440 @@
+// Copyright 2014 Bloomberg Finance LP. All rights reserved.
+//
+// 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 Bloomberg Finance LP. 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_AIX_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_AIX_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 result;
+
+ asm volatile (
+ "1: lwarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " cmpw %[cmp], %[res] \n\t" // compare values
+ " bne- 2f \n\t"
+ " stwcx. %[val], %[zero], %[obj] \n\t" // store new value
+ " bne- 1b \n\t"
+ "2: \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [cmp] "b" (old_value),
+ [val] "b" (new_value),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 result;
+
+ asm volatile (
+ "1: lwarx %[res], %[zero], %[obj] \n\t"
+ " stwcx. %[val], %[zero], %[obj] \n\t"
+ " bne- 1b \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [val] "b" (new_value),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 result;
+
+ asm volatile (
+ "1: lwarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " add %[res], %[val], %[res] \n\t" // add the operand
+ " stwcx. %[res], %[zero], %[obj] \n\t" // store old value
+ // if still reserved
+ " bne- 1b \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [val] "b" (increment),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline void MemoryBarrier(void) {
+ asm volatile (
+ " lwsync \n\t"
+ " isync \n\t"
+ :
+ :
+ : "memory");
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 result;
+
+ asm volatile (
+ " lwsync \n\t"
+
+ "1: lwarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " add %[res], %[val], %[res] \n\t" // add the operand
+ " stwcx. %[res], %[zero], %[obj] \n\t" // store old value
+ // if still reserved
+ " bne- 1b \n\t"
+ " isync \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [val] "b" (increment),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 result;
+
+ asm volatile (
+ "1: lwarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " cmpw %[cmp], %[res] \n\t" // compare values
+ " bne- 2f \n\t"
+ " stwcx. %[val], %[zero], %[obj] \n\t" // store new value
+ " bne- 1b \n\t"
+
+ " isync \n\t"
+ "2: \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [cmp] "b" (old_value),
+ [val] "b" (new_value),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 result;
+
+ asm volatile (
+ " lwsync \n\t"
+
+ "1: lwarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " cmpw %[cmp], %[res] \n\t" // compare values
+ " bne- 2f \n\t"
+ " stwcx. %[val], %[zero], %[obj] \n\t" // store new value
+ " bne- 1b \n\t"
+
+ "2: \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [cmp] "b" (old_value),
+ [val] "b" (new_value),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ asm volatile (
+ " stw %[val], %[obj] \n\t"
+ " isync \n\t"
+ : [obj] "=m" (*ptr)
+ : [val] "b" (value));
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ asm volatile (
+ " lwsync \n\t"
+ " stw %[val], %[obj] \n\t"
+ : [obj] "=m" (*ptr)
+ : [val] "b" (value));
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 result;
+
+ asm volatile (
+ "1: lwz %[res], %[obj] \n\t"
+ " cmpw %[res], %[res] \n\t" // create data
+ // dependency for
+ // load/load ordering
+ " bne- 1b \n\t" // never taken
+
+ " isync \n\t"
+ : [res] "=b" (result)
+ : [obj] "m" (*ptr),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ Atomic32 result;
+
+ asm volatile (
+ " lwsync \n\t"
+
+ "1: lwz %[res], %[obj] \n\t"
+ " cmpw %[res], %[res] \n\t" // create data
+ // dependency for
+ // load/load ordering
+ " bne- 1b \n\t" // never taken
+ : [res] "=b" (result)
+ : [obj] "m" (*ptr),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 result;
+
+ asm volatile (
+ "1: ldarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " cmpd %[cmp], %[res] \n\t" // compare values
+ " bne- 2f \n\t"
+
+ " stdcx. %[val], %[zero], %[obj] \n\t" // store the new value
+ " bne- 1b \n\t"
+ "2: \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [cmp] "b" (old_value),
+ [val] "b" (new_value),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ Atomic64 result;
+
+ asm volatile (
+ "1: ldarx %[res], %[zero], %[obj] \n\t"
+ " stdcx. %[val], %[zero], %[obj] \n\t"
+ " bne- 1b \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [val] "b" (new_value),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ Atomic64 result;
+
+ asm volatile (
+ "1: ldarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " add %[res], %[res], %[val] \n\t" // add the operand
+ " stdcx. %[res], %[zero], %[obj] \n\t" // store old value if
+ // still reserved
+
+ " bne- 1b \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [val] "b" (increment),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+
+ Atomic64 result;
+
+ asm volatile (
+ " lwsync \n\t"
+
+ "1: ldarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " add %[res], %[res], %[val] \n\t" // add the operand
+ " stdcx. %[res], %[zero], %[obj] \n\t" // store old value if
+ // still reserved
+
+ " bne- 1b \n\t"
+
+ " isync \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [val] "b" (increment),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 result;
+
+ asm volatile (
+ "1: ldarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " cmpd %[cmp], %[res] \n\t" // compare values
+ " bne- 2f \n\t"
+
+ " stdcx. %[val], %[zero], %[obj] \n\t" // store the new value
+ " bne- 1b \n\t"
+ " isync \n\t"
+ "2: \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [cmp] "b" (old_value),
+ [val] "b" (new_value),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 result;
+
+ asm volatile (
+ " lwsync \n\t"
+
+ "1: ldarx %[res], %[zero], %[obj] \n\t" // load and reserve
+ " cmpd %[cmp], %[res] \n\t" // compare values
+ " bne- 2f \n\t"
+
+ " stdcx. %[val], %[zero], %[obj] \n\t" // store the new value
+ " bne- 1b \n\t"
+ "2: \n\t"
+ : [res] "=&b" (result)
+ : [obj] "b" (ptr),
+ [cmp] "b" (old_value),
+ [val] "b" (new_value),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ asm volatile (
+ " std %[val], %[obj] \n\t"
+ " isync \n\t"
+ : [obj] "=m" (*ptr)
+ : [val] "b" (value));
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ asm volatile (
+ " lwsync \n\t"
+ " std %[val], %[obj] \n\t"
+ : [obj] "=m" (*ptr)
+ : [val] "b" (value));
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 result;
+
+ asm volatile (
+ "1: ld %[res], %[obj] \n\t"
+ " cmpd %[res], %[res] \n\t" // create data
+ // dependency for
+ // load/load ordering
+ " bne- 1b \n\t" // never taken
+
+ " isync \n\t"
+ : [res] "=b" (result)
+ : [obj] "m" (*ptr),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ Atomic64 result;
+
+ asm volatile (
+ " lwsync \n\t"
+
+ "1: ld %[res], %[obj] \n\t"
+ " cmpd %[res], %[res] \n\t" // create data
+ // dependency for
+ // load/load ordering
+ " bne- 1b \n\t" // never taken
+ : [res] "=b" (result)
+ : [obj] "m" (*ptr),
+ [zero] "i" (0)
+ : "cr0", "ctr");
+
+ return result;
+}
+#endif
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_SPARC_GCC_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_arm64_gcc.h b/src/google/protobuf/stubs/atomicops_internals_arm64_gcc.h
new file mode 100644
index 00000000..0a2d2b89
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_arm64_gcc.h
@@ -0,0 +1,325 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM64_GCC_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM64_GCC_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline void MemoryBarrier() {
+ __asm__ __volatile__ ("dmb ish" ::: "memory"); // NOLINT
+}
+
+// NoBarrier versions of the operation include "memory" in the clobber list.
+// This is not required for direct usage of the NoBarrier versions of the
+// operations. However this is required for correctness when they are used as
+// part of the Acquire or Release versions, to ensure that nothing from outside
+// the call is reordered between the operation and the memory barrier. This does
+// not change the code generated, so has no or minimal impact on the
+// NoBarrier operations.
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev;
+ int32_t temp;
+
+ __asm__ __volatile__ ( // NOLINT
+ "0: \n\t"
+ "ldxr %w[prev], %[ptr] \n\t" // Load the previous value.
+ "cmp %w[prev], %w[old_value] \n\t"
+ "bne 1f \n\t"
+ "stxr %w[temp], %w[new_value], %[ptr] \n\t" // Try to store the new value.
+ "cbnz %w[temp], 0b \n\t" // Retry if it did not work.
+ "1: \n\t"
+ : [prev]"=&r" (prev),
+ [temp]"=&r" (temp),
+ [ptr]"+Q" (*ptr)
+ : [old_value]"IJr" (old_value),
+ [new_value]"r" (new_value)
+ : "cc", "memory"
+ ); // NOLINT
+
+ return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 result;
+ int32_t temp;
+
+ __asm__ __volatile__ ( // NOLINT
+ "0: \n\t"
+ "ldxr %w[result], %[ptr] \n\t" // Load the previous value.
+ "stxr %w[temp], %w[new_value], %[ptr] \n\t" // Try to store the new value.
+ "cbnz %w[temp], 0b \n\t" // Retry if it did not work.
+ : [result]"=&r" (result),
+ [temp]"=&r" (temp),
+ [ptr]"+Q" (*ptr)
+ : [new_value]"r" (new_value)
+ : "memory"
+ ); // NOLINT
+
+ return result;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 result;
+ int32_t temp;
+
+ __asm__ __volatile__ ( // NOLINT
+ "0: \n\t"
+ "ldxr %w[result], %[ptr] \n\t" // Load the previous value.
+ "add %w[result], %w[result], %w[increment]\n\t"
+ "stxr %w[temp], %w[result], %[ptr] \n\t" // Try to store the result.
+ "cbnz %w[temp], 0b \n\t" // Retry on failure.
+ : [result]"=&r" (result),
+ [temp]"=&r" (temp),
+ [ptr]"+Q" (*ptr)
+ : [increment]"IJr" (increment)
+ : "memory"
+ ); // NOLINT
+
+ return result;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ MemoryBarrier();
+ Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
+ MemoryBarrier();
+
+ return result;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ MemoryBarrier();
+
+ return prev;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ MemoryBarrier();
+ Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+
+ return prev;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ __asm__ __volatile__ ( // NOLINT
+ "stlr %w[value], %[ptr] \n\t"
+ : [ptr]"=Q" (*ptr)
+ : [value]"r" (value)
+ : "memory"
+ ); // NOLINT
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value;
+
+ __asm__ __volatile__ ( // NOLINT
+ "ldar %w[value], %[ptr] \n\t"
+ : [value]"=r" (value)
+ : [ptr]"Q" (*ptr)
+ : "memory"
+ ); // NOLINT
+
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+// 64-bit versions of the operations.
+// See the 32-bit versions for comments.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev;
+ int32_t temp;
+
+ __asm__ __volatile__ ( // NOLINT
+ "0: \n\t"
+ "ldxr %[prev], %[ptr] \n\t"
+ "cmp %[prev], %[old_value] \n\t"
+ "bne 1f \n\t"
+ "stxr %w[temp], %[new_value], %[ptr] \n\t"
+ "cbnz %w[temp], 0b \n\t"
+ "1: \n\t"
+ : [prev]"=&r" (prev),
+ [temp]"=&r" (temp),
+ [ptr]"+Q" (*ptr)
+ : [old_value]"IJr" (old_value),
+ [new_value]"r" (new_value)
+ : "cc", "memory"
+ ); // NOLINT
+
+ return prev;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ Atomic64 result;
+ int32_t temp;
+
+ __asm__ __volatile__ ( // NOLINT
+ "0: \n\t"
+ "ldxr %[result], %[ptr] \n\t"
+ "stxr %w[temp], %[new_value], %[ptr] \n\t"
+ "cbnz %w[temp], 0b \n\t"
+ : [result]"=&r" (result),
+ [temp]"=&r" (temp),
+ [ptr]"+Q" (*ptr)
+ : [new_value]"r" (new_value)
+ : "memory"
+ ); // NOLINT
+
+ return result;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ Atomic64 result;
+ int32_t temp;
+
+ __asm__ __volatile__ ( // NOLINT
+ "0: \n\t"
+ "ldxr %[result], %[ptr] \n\t"
+ "add %[result], %[result], %[increment] \n\t"
+ "stxr %w[temp], %[result], %[ptr] \n\t"
+ "cbnz %w[temp], 0b \n\t"
+ : [result]"=&r" (result),
+ [temp]"=&r" (temp),
+ [ptr]"+Q" (*ptr)
+ : [increment]"IJr" (increment)
+ : "memory"
+ ); // NOLINT
+
+ return result;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ MemoryBarrier();
+ Atomic64 result = NoBarrier_AtomicIncrement(ptr, increment);
+ MemoryBarrier();
+
+ return result;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ MemoryBarrier();
+
+ return prev;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ MemoryBarrier();
+ Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+
+ return prev;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ __asm__ __volatile__ ( // NOLINT
+ "stlr %x[value], %[ptr] \n\t"
+ : [ptr]"=Q" (*ptr)
+ : [value]"r" (value)
+ : "memory"
+ ); // NOLINT
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value;
+
+ __asm__ __volatile__ ( // NOLINT
+ "ldar %x[value], %[ptr] \n\t"
+ : [value]"=r" (value)
+ : [ptr]"Q" (*ptr)
+ : "memory"
+ ); // NOLINT
+
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM64_GCC_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_arm_gcc.h b/src/google/protobuf/stubs/atomicops_internals_arm_gcc.h
new file mode 100644
index 00000000..90e727b0
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_arm_gcc.h
@@ -0,0 +1,151 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 is an internal atomic implementation, use atomicops.h instead.
+//
+// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_GCC_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_GCC_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// 0xffff0fc0 is the hard coded address of a function provided by
+// the kernel which implements an atomic compare-exchange. On older
+// ARM architecture revisions (pre-v6) this may be implemented using
+// a syscall. This address is stable, and in active use (hard coded)
+// by at least glibc-2.7 and the Android C library.
+typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value,
+ Atomic32 new_value,
+ volatile Atomic32* ptr);
+LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) =
+ (LinuxKernelCmpxchgFunc) 0xffff0fc0;
+
+typedef void (*LinuxKernelMemoryBarrierFunc)(void);
+LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
+ (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
+
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev_value = *ptr;
+ do {
+ if (!pLinuxKernelCmpxchg(old_value, new_value,
+ const_cast<Atomic32*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 old_value;
+ do {
+ old_value = *ptr;
+ } while (pLinuxKernelCmpxchg(old_value, new_value,
+ const_cast<Atomic32*>(ptr)));
+ return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ for (;;) {
+ // Atomic exchange the old value with an incremented one.
+ Atomic32 old_value = *ptr;
+ Atomic32 new_value = old_value + increment;
+ if (pLinuxKernelCmpxchg(old_value, new_value,
+ const_cast<Atomic32*>(ptr)) == 0) {
+ // The exchange took place as expected.
+ return new_value;
+ }
+ // Otherwise, *ptr changed mid-loop and we need to retry.
+ }
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void MemoryBarrier() {
+ pLinuxKernelMemoryBarrier();
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_GCC_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_arm_qnx.h b/src/google/protobuf/stubs/atomicops_internals_arm_qnx.h
new file mode 100644
index 00000000..17dfaa51
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_arm_qnx.h
@@ -0,0 +1,146 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_
+
+// For _smp_cmpxchg()
+#include <pthread.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 QNXCmpxchg(Atomic32 old_value,
+ Atomic32 new_value,
+ volatile Atomic32* ptr) {
+ return static_cast<Atomic32>(
+ _smp_cmpxchg((volatile unsigned *)ptr,
+ (unsigned)old_value,
+ (unsigned)new_value));
+}
+
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev_value = *ptr;
+ do {
+ if (!QNXCmpxchg(old_value, new_value,
+ const_cast<Atomic32*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 old_value;
+ do {
+ old_value = *ptr;
+ } while (QNXCmpxchg(old_value, new_value,
+ const_cast<Atomic32*>(ptr)));
+ return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ for (;;) {
+ // Atomic exchange the old value with an incremented one.
+ Atomic32 old_value = *ptr;
+ Atomic32 new_value = old_value + increment;
+ if (QNXCmpxchg(old_value, new_value,
+ const_cast<Atomic32*>(ptr)) == 0) {
+ // The exchange took place as expected.
+ return new_value;
+ }
+ // Otherwise, *ptr changed mid-loop and we need to retry.
+ }
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void MemoryBarrier() {
+ __sync_synchronize();
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h b/src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h
new file mode 100644
index 00000000..eb198ff5
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h
@@ -0,0 +1,122 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+
+// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32,
+// which in turn means int. On some LP32 platforms, intptr_t is an int, but
+// on others, it's a long. When AtomicWord and Atomic32 are based on different
+// fundamental types, their pointers are incompatible.
+//
+// This file defines function overloads to allow both AtomicWord and Atomic32
+// data to be used with this interface.
+//
+// On LP64 platforms, AtomicWord and Atomic64 are both always long,
+// so this problem doesn't occur.
+
+#if !defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
+ AtomicWord old_value,
+ AtomicWord new_value) {
+ return NoBarrier_CompareAndSwap(
+ reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
+ AtomicWord new_value) {
+ return NoBarrier_AtomicExchange(
+ reinterpret_cast<volatile Atomic32*>(ptr), new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
+ AtomicWord increment) {
+ return NoBarrier_AtomicIncrement(
+ reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
+ AtomicWord increment) {
+ return Barrier_AtomicIncrement(
+ reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
+ AtomicWord old_value,
+ AtomicWord new_value) {
+ return Acquire_CompareAndSwap(
+ reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
+ AtomicWord old_value,
+ AtomicWord new_value) {
+ return Release_CompareAndSwap(
+ reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
+ NoBarrier_Store(reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
+ return Acquire_Store(reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
+ return Release_Store(reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
+ return NoBarrier_Load(reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
+ return Acquire_Load(reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
+ return Release_Load(reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // !defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
new file mode 100644
index 00000000..dd7abf6f
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
@@ -0,0 +1,137 @@
+// Copyright 2013 Red Hat Inc. All rights reserved.
+//
+// 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 Red Hat 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_GCC_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_GCC_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ __atomic_compare_exchange_n(ptr, &old_value, new_value, true,
+ __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+ return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return __atomic_add_fetch(ptr, increment, __ATOMIC_RELAXED);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return __atomic_add_fetch(ptr, increment, __ATOMIC_SEQ_CST);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ __atomic_compare_exchange(ptr, &old_value, &new_value, true,
+ __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+ return old_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ __atomic_compare_exchange_n(ptr, &old_value, new_value, true,
+ __ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
+ return old_value;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ __atomic_store_n(ptr, value, __ATOMIC_RELAXED);
+}
+
+inline void MemoryBarrier() {
+ __sync_synchronize();
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ __atomic_store_n(ptr, value, __ATOMIC_SEQ_CST);
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ __atomic_store_n(ptr, value, __ATOMIC_RELEASE);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return __atomic_load_n(ptr, __ATOMIC_RELAXED);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
+}
+
+#ifdef __LP64__
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ __atomic_store_n(ptr, value, __ATOMIC_RELEASE);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ __atomic_compare_exchange_n(ptr, &old_value, new_value, true,
+ __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+ return old_value;
+}
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ __atomic_compare_exchange_n(ptr, &old_value, new_value, true,
+ __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+ return old_value;
+}
+
+#endif // defined(__LP64__)
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_GCC_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_macosx.h b/src/google/protobuf/stubs/atomicops_internals_macosx.h
new file mode 100644
index 00000000..79633241
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_macosx.h
@@ -0,0 +1,225 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MACOSX_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MACOSX_H_
+
+#include <libkern/OSAtomic.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev_value;
+ do {
+ if (OSAtomicCompareAndSwap32(old_value, new_value,
+ const_cast<Atomic32*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 old_value;
+ do {
+ old_value = *ptr;
+ } while (!OSAtomicCompareAndSwap32(old_value, new_value,
+ const_cast<Atomic32*>(ptr)));
+ return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline void MemoryBarrier() {
+ OSMemoryBarrier();
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev_value;
+ do {
+ if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
+ const_cast<Atomic32*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#ifdef __LP64__
+
+// 64-bit implementation on 64-bit platform
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev_value;
+ do {
+ if (OSAtomicCompareAndSwap64(old_value, new_value,
+ reinterpret_cast<volatile int64_t*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ Atomic64 old_value;
+ do {
+ old_value = *ptr;
+ } while (!OSAtomicCompareAndSwap64(old_value, new_value,
+ reinterpret_cast<volatile int64_t*>(ptr)));
+ return old_value;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return OSAtomicAdd64Barrier(increment,
+ reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev_value;
+ do {
+ if (OSAtomicCompareAndSwap64Barrier(
+ old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ // The lib kern interface does not distinguish between
+ // Acquire and Release memory barriers; they are equivalent.
+ return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#endif // defined(__LP64__)
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MACOSX_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h b/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h
new file mode 100644
index 00000000..f5837c9e
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h
@@ -0,0 +1,313 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Atomically execute:
+// result = *ptr;
+// if (*ptr == old_value)
+// *ptr = new_value;
+// return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev, tmp;
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "1:\n"
+ "ll %0, %5\n" // prev = *ptr
+ "bne %0, %3, 2f\n" // if (prev != old_value) goto 2
+ "move %2, %4\n" // tmp = new_value
+ "sc %2, %1\n" // *ptr = tmp (with atomic check)
+ "beqz %2, 1b\n" // start again on atomic error
+ "nop\n" // delay slot nop
+ "2:\n"
+ ".set pop\n"
+ : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
+ : "r" (old_value), "r" (new_value), "m" (*ptr)
+ : "memory");
+ return prev;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr. This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 temp, old;
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "1:\n"
+ "ll %1, %4\n" // old = *ptr
+ "move %0, %3\n" // temp = new_value
+ "sc %0, %2\n" // *ptr = temp (with atomic check)
+ "beqz %0, 1b\n" // start again on atomic error
+ "nop\n" // delay slot nop
+ ".set pop\n"
+ : "=&r" (temp), "=&r" (old), "=m" (*ptr)
+ : "r" (new_value), "m" (*ptr)
+ : "memory");
+
+ return old;
+}
+
+// Atomically increment *ptr by "increment". Returns the new value of
+// *ptr with the increment applied. This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 temp, temp2;
+
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "1:\n"
+ "ll %0, %4\n" // temp = *ptr
+ "addu %1, %0, %3\n" // temp2 = temp + increment
+ "sc %1, %2\n" // *ptr = temp2 (with atomic check)
+ "beqz %1, 1b\n" // start again on atomic error
+ "addu %1, %0, %3\n" // temp2 = temp + increment
+ ".set pop\n"
+ : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
+ : "Ir" (increment), "m" (*ptr)
+ : "memory");
+ // temp2 now holds the final value.
+ return temp2;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ ATOMICOPS_COMPILER_BARRIER();
+ Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
+ ATOMICOPS_COMPILER_BARRIER();
+ return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation. "Barrier" operations have both "Acquire" and "Release"
+// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ ATOMICOPS_COMPILER_BARRIER();
+ Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ ATOMICOPS_COMPILER_BARRIER();
+ return res;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ ATOMICOPS_COMPILER_BARRIER();
+ Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ ATOMICOPS_COMPILER_BARRIER();
+ return res;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void MemoryBarrier() {
+ __asm__ __volatile__("sync" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#if defined(__LP64__)
+// 64-bit versions of the atomic ops.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev, tmp;
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "1:\n"
+ "lld %0, %5\n" // prev = *ptr
+ "bne %0, %3, 2f\n" // if (prev != old_value) goto 2
+ "move %2, %4\n" // tmp = new_value
+ "scd %2, %1\n" // *ptr = tmp (with atomic check)
+ "beqz %2, 1b\n" // start again on atomic error
+ "nop\n" // delay slot nop
+ "2:\n"
+ ".set pop\n"
+ : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
+ : "r" (old_value), "r" (new_value), "m" (*ptr)
+ : "memory");
+ return prev;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr. This routine implies no memory barriers.
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ Atomic64 temp, old;
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "1:\n"
+ "lld %1, %4\n" // old = *ptr
+ "move %0, %3\n" // temp = new_value
+ "scd %0, %2\n" // *ptr = temp (with atomic check)
+ "beqz %0, 1b\n" // start again on atomic error
+ "nop\n" // delay slot nop
+ ".set pop\n"
+ : "=&r" (temp), "=&r" (old), "=m" (*ptr)
+ : "r" (new_value), "m" (*ptr)
+ : "memory");
+
+ return old;
+}
+
+// Atomically increment *ptr by "increment". Returns the new value of
+// *ptr with the increment applied. This routine implies no memory barriers.
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ Atomic64 temp, temp2;
+
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "1:\n"
+ "lld %0, %4\n" // temp = *ptr
+ "daddu %1, %0, %3\n" // temp2 = temp + increment
+ "scd %1, %2\n" // *ptr = temp2 (with atomic check)
+ "beqz %1, 1b\n" // start again on atomic error
+ "daddu %1, %0, %3\n" // temp2 = temp + increment
+ ".set pop\n"
+ : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
+ : "Ir" (increment), "m" (*ptr)
+ : "memory");
+ // temp2 now holds the final value.
+ return temp2;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ MemoryBarrier();
+ Atomic64 res = NoBarrier_AtomicIncrement(ptr, increment);
+ MemoryBarrier();
+ return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation. "Barrier" operations have both "Acquire" and "Release"
+// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ MemoryBarrier();
+ return res;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ MemoryBarrier();
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+#endif
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_pnacl.h b/src/google/protobuf/stubs/atomicops_internals_pnacl.h
new file mode 100644
index 00000000..b10ac02c
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_pnacl.h
@@ -0,0 +1,73 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return __sync_val_compare_and_swap(ptr, old_value, new_value);
+}
+
+inline void MemoryBarrier() {
+ __sync_synchronize();
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ MemoryBarrier();
+ return ret;
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_solaris.h b/src/google/protobuf/stubs/atomicops_internals_solaris.h
new file mode 100644
index 00000000..d8057ecd
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_solaris.h
@@ -0,0 +1,188 @@
+// 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.
+
+// This file is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_SPARC_GCC_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_SPARC_GCC_H_
+
+#include <atomic.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return (Atomic32)atomic_cas_32((volatile uint32_t*)ptr, (uint32_t)old_value, (uint32_t)new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ return (Atomic32)atomic_swap_32((volatile uint32_t*)ptr, (uint32_t)new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return (Atomic32)atomic_add_32_nv((volatile uint32_t*)ptr, (uint32_t)increment);
+}
+
+inline void MemoryBarrier(void) {
+ membar_producer();
+ membar_consumer();
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ MemoryBarrier();
+ Atomic32 ret = NoBarrier_AtomicIncrement(ptr, increment);
+ MemoryBarrier();
+
+ return ret;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ MemoryBarrier();
+
+ return ret;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ MemoryBarrier();
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ membar_producer();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ membar_consumer();
+ *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 val = *ptr;
+ membar_consumer();
+ return val;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ membar_producer();
+ return *ptr;
+}
+
+#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return atomic_cas_64((volatile uint64_t*)ptr, (uint64_t)old_value, (uint64_t)new_value);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value) {
+ return atomic_swap_64((volatile uint64_t*)ptr, (uint64_t)new_value);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) {
+ return atomic_add_64_nv((volatile uint64_t*)ptr, increment);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) {
+ MemoryBarrier();
+ Atomic64 ret = atomic_add_64_nv((volatile uint64_t*)ptr, increment);
+ MemoryBarrier();
+ return ret;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ MemoryBarrier();
+ return ret;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ MemoryBarrier();
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+ membar_producer();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ membar_consumer();
+ *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 ret = *ptr;
+ membar_consumer();
+ return ret;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ membar_producer();
+ return *ptr;
+}
+#endif
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_SPARC_GCC_H_
+
diff --git a/src/google/protobuf/stubs/atomicops_internals_tsan.h b/src/google/protobuf/stubs/atomicops_internals_tsan.h
new file mode 100644
index 00000000..0c903545
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_tsan.h
@@ -0,0 +1,219 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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 is an internal atomic implementation for compiler-based
+// ThreadSanitizer (http://clang.llvm.org/docs/ThreadSanitizer.html).
+// Use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TSAN_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TSAN_H_
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+#include <sanitizer/tsan_interface_atomic.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 cmp = old_value;
+ __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
+ Atomic32 new_value) {
+ return __tsan_atomic32_exchange(ptr, new_value,
+ __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
+ Atomic32 new_value) {
+ return __tsan_atomic32_exchange(ptr, new_value,
+ __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
+ Atomic32 new_value) {
+ return __tsan_atomic32_exchange(ptr, new_value,
+ __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
+ Atomic32 increment) {
+ return increment + __tsan_atomic32_fetch_add(ptr, increment,
+ __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
+ Atomic32 increment) {
+ return increment + __tsan_atomic32_fetch_add(ptr, increment,
+ __tsan_memory_order_acq_rel);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 cmp = old_value;
+ __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_acquire, __tsan_memory_order_acquire);
+ return cmp;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 cmp = old_value;
+ __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_release, __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ __tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
+ return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
+ return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+ return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 cmp = old_value;
+ __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
+ Atomic64 new_value) {
+ return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
+ Atomic64 new_value) {
+ return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
+ Atomic64 new_value) {
+ return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
+ Atomic64 increment) {
+ return increment + __tsan_atomic64_fetch_add(ptr, increment,
+ __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
+ Atomic64 increment) {
+ return increment + __tsan_atomic64_fetch_add(ptr, increment,
+ __tsan_memory_order_acq_rel);
+}
+
+inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ __tsan_atomic64_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
+ return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
+ return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+ return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 cmp = old_value;
+ __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_acquire, __tsan_memory_order_acquire);
+ return cmp;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 cmp = old_value;
+ __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_release, __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline void MemoryBarrier() {
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TSAN_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc b/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc
new file mode 100644
index 00000000..53c9eae0
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc
@@ -0,0 +1,137 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 module gets enough CPU information to optimize the
+// atomicops module on x86.
+
+#include <cstring>
+
+#include <google/protobuf/stubs/atomicops.h>
+
+// This file only makes sense with atomicops_internals_x86_gcc.h -- it
+// depends on structs that are defined in that file. If atomicops.h
+// doesn't sub-include that file, then we aren't needed, and shouldn't
+// try to do anything.
+#ifdef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_
+
+// Inline cpuid instruction. In PIC compilations, %ebx contains the address
+// of the global offset table. To avoid breaking such executables, this code
+// must preserve that register's value across cpuid instructions.
+#if defined(__i386__)
+#define cpuid(a, b, c, d, inp) \
+ asm("mov %%ebx, %%edi\n" \
+ "cpuid\n" \
+ "xchg %%edi, %%ebx\n" \
+ : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#elif defined(__x86_64__)
+#define cpuid(a, b, c, d, inp) \
+ asm("mov %%rbx, %%rdi\n" \
+ "cpuid\n" \
+ "xchg %%rdi, %%rbx\n" \
+ : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#endif
+
+#if defined(cpuid) // initialize the struct only on x86
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Set the flags so that code will run correctly and conservatively, so even
+// if we haven't been initialized yet, we're probably single threaded, and our
+// default values should hopefully be pretty safe.
+struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = {
+ false, // bug can't exist before process spawns multiple threads
+ false, // no SSE2
+};
+
+namespace {
+
+// Initialize the AtomicOps_Internalx86CPUFeatures struct.
+void AtomicOps_Internalx86CPUFeaturesInit() {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+
+ // Get vendor string (issue CPUID with eax = 0)
+ cpuid(eax, ebx, ecx, edx, 0);
+ char vendor[13];
+ memcpy(vendor, &ebx, 4);
+ memcpy(vendor + 4, &edx, 4);
+ memcpy(vendor + 8, &ecx, 4);
+ vendor[12] = 0;
+
+ // get feature flags in ecx/edx, and family/model in eax
+ cpuid(eax, ebx, ecx, edx, 1);
+
+ int family = (eax >> 8) & 0xf; // family and model fields
+ int model = (eax >> 4) & 0xf;
+ if (family == 0xf) { // use extended family and model fields
+ family += (eax >> 20) & 0xff;
+ model += ((eax >> 16) & 0xf) << 4;
+ }
+
+ // Opteron Rev E has a bug in which on very rare occasions a locked
+ // instruction doesn't act as a read-acquire barrier if followed by a
+ // non-locked read-modify-write instruction. Rev F has this bug in
+ // pre-release versions, but not in versions released to customers,
+ // so we test only for Rev E, which is family 15, model 32..63 inclusive.
+ if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD
+ family == 15 &&
+ 32 <= model && model <= 63) {
+ AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
+ } else {
+ AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
+ }
+
+ // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
+ AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);
+}
+
+class AtomicOpsx86Initializer {
+ public:
+ AtomicOpsx86Initializer() {
+ AtomicOps_Internalx86CPUFeaturesInit();
+ }
+};
+
+// A global to get use initialized on startup via static initialization :/
+AtomicOpsx86Initializer g_initer;
+
+} // namespace
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // __i386__
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h b/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h
new file mode 100644
index 00000000..edccc59d
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h
@@ -0,0 +1,293 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This struct is not part of the public API of this module; clients may not
+// use it.
+// Features of this x86. Values may not be correct before main() is run,
+// but are set conservatively.
+struct AtomicOps_x86CPUFeatureStruct {
+ bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
+ // after acquire compare-and-swap.
+ bool has_sse2; // Processor has SSE2.
+};
+extern struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures;
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+// 32-bit low-level operations on any platform.
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev;
+ __asm__ __volatile__("lock; cmpxchgl %1,%2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ __asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg.
+ : "=r" (new_value)
+ : "m" (*ptr), "0" (new_value)
+ : "memory");
+ return new_value; // Now it's the previous value.
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 temp = increment;
+ __asm__ __volatile__("lock; xaddl %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now holds the old value of *ptr
+ return temp + increment;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 temp = increment;
+ __asm__ __volatile__("lock; xaddl %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now holds the old value of *ptr
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return temp + increment;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return x;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit implementations of memory barrier can be simpler, because it
+// "mfence" is guaranteed to exist.
+inline void MemoryBarrier() {
+ __asm__ __volatile__("mfence" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+#else
+
+inline void MemoryBarrier() {
+ if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
+ __asm__ __volatile__("mfence" : : : "memory");
+ } else { // mfence is faster but not present on PIII
+ Atomic32 x = 0;
+ NoBarrier_AtomicExchange(&x, 0); // acts as a barrier on PIII
+ }
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
+ *ptr = value;
+ __asm__ __volatile__("mfence" : : : "memory");
+ } else {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier on PIII
+ }
+}
+#endif
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ ATOMICOPS_COMPILER_BARRIER();
+ *ptr = value; // An x86 store acts as a release barrier.
+ // See comments in Atomic64 version of Release_Store(), below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
+ // See comments in Atomic64 version of Release_Store(), below.
+ ATOMICOPS_COMPILER_BARRIER();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit low-level operations on 64-bit platform.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev;
+ __asm__ __volatile__("lock; cmpxchgq %1,%2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ __asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg.
+ : "=r" (new_value)
+ : "m" (*ptr), "0" (new_value)
+ : "memory");
+ return new_value; // Now it's the previous value.
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ Atomic64 temp = increment;
+ __asm__ __volatile__("lock; xaddq %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now contains the previous value of *ptr
+ return temp + increment;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ Atomic64 temp = increment;
+ __asm__ __volatile__("lock; xaddq %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now contains the previous value of *ptr
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return temp + increment;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ ATOMICOPS_COMPILER_BARRIER();
+
+ *ptr = value; // An x86 store acts as a release barrier
+ // for current AMD/Intel chips as of Jan 2008.
+ // See also Acquire_Load(), below.
+
+ // When new chips come out, check:
+ // IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+ // System Programming Guide, Chatper 7: Multiple-processor management,
+ // Section 7.2, Memory Ordering.
+ // Last seen at:
+ // http://developer.intel.com/design/pentium4/manuals/index_new.htm
+ //
+ // x86 stores/loads fail to act as barriers for a few instructions (clflush
+ // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
+ // not generated by the compiler, and are rare. Users of these instructions
+ // need to know about cache behaviour in any case since all of these involve
+ // either flushing cache lines or non-temporal cache hints.
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
+ // for current AMD/Intel chips as of Jan 2008.
+ // See also Release_Store(), above.
+ ATOMICOPS_COMPILER_BARRIER();
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return x;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+#endif // defined(__x86_64__)
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc b/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc
new file mode 100644
index 00000000..741b164f
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc
@@ -0,0 +1,112 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 compilation of extension_set.cc fails when windows.h is included.
+// Therefore we move the code depending on windows.h to this separate cc file.
+
+// Don't compile this file for people not concerned about thread safety.
+#ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
+
+#include <google/protobuf/stubs/atomicops.h>
+
+#ifdef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_MSVC_H_
+
+#include <windows.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline void MemoryBarrier() {
+ // We use MemoryBarrier from WinNT.h
+ ::MemoryBarrier();
+}
+
+Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ LONG result = InterlockedCompareExchange(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(new_value),
+ static_cast<LONG>(old_value));
+ return static_cast<Atomic32>(result);
+}
+
+Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ LONG result = InterlockedExchange(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(new_value));
+ return static_cast<Atomic32>(result);
+}
+
+Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return InterlockedExchangeAdd(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(increment)) + increment;
+}
+
+#if defined(_WIN64)
+
+// 64-bit low-level operations on 64-bit platform.
+
+Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ PVOID result = InterlockedCompareExchangePointer(
+ reinterpret_cast<volatile PVOID*>(ptr),
+ reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
+ return reinterpret_cast<Atomic64>(result);
+}
+
+Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ PVOID result = InterlockedExchangePointer(
+ reinterpret_cast<volatile PVOID*>(ptr),
+ reinterpret_cast<PVOID>(new_value));
+ return reinterpret_cast<Atomic64>(result);
+}
+
+Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return InterlockedExchangeAdd64(
+ reinterpret_cast<volatile LONGLONG*>(ptr),
+ static_cast<LONGLONG>(increment)) + increment;
+}
+
+#endif // defined(_WIN64)
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_MSVC_H_
+#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
diff --git a/src/google/protobuf/stubs/atomicops_internals_x86_msvc.h b/src/google/protobuf/stubs/atomicops_internals_x86_msvc.h
new file mode 100644
index 00000000..e53a641f
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_x86_msvc.h
@@ -0,0 +1,150 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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 is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_MSVC_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_MSVC_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
+#error "We require at least vs2005 for MemoryBarrier"
+#endif
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+ // See comments in Atomic64 version of Release_Store() below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#if defined(_WIN64)
+
+// 64-bit low-level operations on 64-bit platform.
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+
+ // When new chips come out, check:
+ // IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+ // System Programming Guide, Chatper 7: Multiple-processor management,
+ // Section 7.2, Memory Ordering.
+ // Last seen at:
+ // http://developer.intel.com/design/pentium4/manuals/index_new.htm
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value = *ptr;
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+#endif // defined(_WIN64)
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_MSVC_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 <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/type_traits.h>
+
+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<ToType>(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<typename To, typename From>
+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<Subclass1>(foo)) HandleASubclass1Object(foo);
+// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+
+template<typename To, typename From> // use like this: down_cast<T*>(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<From*, To>(0);
+ }
+
+#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
+ assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only!
+#endif
+ return static_cast<To>(f);
+}
+
+template<typename To, typename From> // use like this: down_cast<T&>(foo);
+inline To down_cast(From& f) {
+ typedef typename remove_reference<To>::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<From*, ToAsPointer>(0);
+ }
+
+#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
+ // RTTI: debug mode only!
+ assert(dynamic_cast<ToAsPointer>(&f) != NULL);
+#endif
+ return *static_cast<ToAsPointer>(&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 7b15be44..54e00ccb 100644
--- a/src/google/protobuf/stubs/common.cc
+++ b/src/google/protobuf/stubs/common.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -110,13 +110,13 @@ void DefaultLogHandler(LogLevel level, const char* filename, int line,
// We use fprintf() instead of cerr because we want this to work at static
// initialization time.
- fprintf(stderr, "libprotobuf %s %s:%d] %s\n",
+ fprintf(stderr, "[libprotobuf %s %s:%d] %s\n",
level_names[level], filename, line, message.c_str());
fflush(stderr); // Needed on MSVC.
}
-void NullLogHandler(LogLevel level, const char* filename, int line,
- const string& message) {
+void NullLogHandler(LogLevel /* level */, const char* /* filename */,
+ int /* line */, const string& /* message */) {
// Nothing.
}
@@ -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)
@@ -183,15 +184,15 @@ void LogMessage::Finish() {
if (level_ != LOGLEVEL_FATAL) {
InitLogSilencerCountOnce();
MutexLock lock(log_silencer_count_mutex_);
- suppress = internal::log_silencer_count_ > 0;
+ suppress = log_silencer_count_ > 0;
}
if (!suppress) {
- internal::log_handler_(level_, filename_, line_, message_);
+ log_handler_(level_, filename_, line_, message_);
}
if (level_ == LOGLEVEL_FATAL) {
-#ifdef PROTOBUF_USE_EXCEPTIONS
+#if PROTOBUF_USE_EXCEPTIONS
throw FatalException(filename_, line_, message_);
#else
abort();
@@ -320,6 +321,24 @@ void Mutex::AssertHeld() {
#endif
// ===================================================================
+// emulates google3/util/endian/endian.h
+//
+// TODO(xiaofeng): PROTOBUF_LITTLE_ENDIAN is unfortunately defined in
+// google/protobuf/io/coded_stream.h and therefore can not be used here.
+// Maybe move that macro definition here in the furture.
+uint32 ghtonl(uint32 x) {
+ union {
+ uint32 result;
+ uint8 result_array[4];
+ };
+ result_array[0] = static_cast<uint8>(x >> 24);
+ result_array[1] = static_cast<uint8>((x >> 16) & 0xFF);
+ result_array[2] = static_cast<uint8>((x >> 8) & 0xFF);
+ result_array[3] = static_cast<uint8>(x & 0xFF);
+ return result;
+}
+
+// ===================================================================
// Shutdown support.
namespace internal {
@@ -365,7 +384,7 @@ void ShutdownProtobufLibrary() {
internal::shutdown_functions_mutex = NULL;
}
-#ifdef PROTOBUF_USE_EXCEPTIONS
+#if PROTOBUF_USE_EXCEPTIONS
FatalException::~FatalException() throw() {}
const char* FatalException::what() const throw() {
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
index 7173a84d..c3f735a2 100644
--- a/src/google/protobuf/stubs/common.h
+++ b/src/google/protobuf/stubs/common.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -48,12 +48,17 @@
#include <stdint.h>
#endif
+#ifndef PROTOBUF_USE_EXCEPTIONS
#if defined(_MSC_VER) && defined(_CPPUNWIND)
- #define PROTOBUF_USE_EXCEPTIONS
+ #define PROTOBUF_USE_EXCEPTIONS 1
#elif defined(__EXCEPTIONS)
- #define PROTOBUF_USE_EXCEPTIONS
+ #define PROTOBUF_USE_EXCEPTIONS 1
+#else
+ #define PROTOBUF_USE_EXCEPTIONS 0
+#endif
#endif
-#ifdef PROTOBUF_USE_EXCEPTIONS
+
+#if PROTOBUF_USE_EXCEPTIONS
#include <exception>
#endif
@@ -108,24 +113,24 @@ namespace internal {
// The current version, represented as a single integer to make comparison
// easier: major * 10^6 + minor * 10^3 + micro
-#define GOOGLE_PROTOBUF_VERSION 2004001
+#define GOOGLE_PROTOBUF_VERSION 3000000
// The minimum library version which works with the current version of the
// headers.
-#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2004000
+#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 3000000
// The minimum header version which works with the current version of
// the library. This constant should only be used by protoc's C++ code
// generator.
-static const int kMinHeaderVersionForLibrary = 2004000;
+static const int kMinHeaderVersionForLibrary = 3000000;
// The minimum protoc version which works with the current version of the
// headers.
-#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2004000
+#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 3000000
// The minimum header version which works with the current version of
// protoc. This constant should only be used in VerifyVersion().
-static const int kMinHeaderVersionForProtoc = 2004000;
+static const int kMinHeaderVersionForProtoc = 3000000;
// Verifies that the headers and libraries are compatible. Use the macro
// below to call this.
@@ -213,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.
@@ -231,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).
@@ -241,6 +266,60 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF);
#define GOOGLE_SAFE_CONCURRENT_WRITES_END()
#endif
+#define GOOGLE_GUARDED_BY(x)
+#define GOOGLE_FALLTHROUGH_INTENDED
+#define GOOGLE_ATTRIBUTE_COLD
+
+// 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<const uint16 *>(_p))
+#define GOOGLE_UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
+#define GOOGLE_UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p))
+
+#define GOOGLE_UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val))
+#define GOOGLE_UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val))
+#define GOOGLE_UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_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
+
+#if defined(_MSC_VER)
+#define GOOGLE_THREAD_LOCAL __declspec(thread)
+#else
+#define GOOGLE_THREAD_LOCAL __thread
+#endif
+
// ===================================================================
// from google3/base/basictypes.h
@@ -283,71 +362,6 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF);
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(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<ToType>(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<typename To, typename From>
-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<Subclass1>(foo)) HandleASubclass1Object(foo);
-// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
-// You should design the code some other way not to need this.
-
-template<typename To, typename From> // use like this: down_cast<T*>(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<From*, To>(0);
- }
-
-#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
- assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only!
-#endif
- return static_cast<To>(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:
@@ -373,8 +387,9 @@ struct CompileAssert {
#undef GOOGLE_COMPILE_ASSERT
#define GOOGLE_COMPILE_ASSERT(expr, msg) \
- typedef ::google::protobuf::internal::CompileAssert<(bool(expr))> \
- msg[bool(expr) ? 1 : -1]
+ ::google::protobuf::internal::CompileAssert<(bool(expr))> \
+ msg[bool(expr) ? 1 : -1]; \
+ (void)msg
// Implementation details of COMPILE_ASSERT:
@@ -444,7 +459,7 @@ class scoped_ptr {
// The element type
typedef C element_type;
- // Constructor. Defaults to intializing with NULL.
+ // Constructor. Defaults to initializing with NULL.
// There is no way to create an uninitialized scoped_ptr.
// The input parameter must be allocated with new.
explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
@@ -531,7 +546,7 @@ class scoped_array {
// The element type
typedef C element_type;
- // Constructor. Defaults to intializing with NULL.
+ // Constructor. Defaults to initializing with NULL.
// There is no way to create an uninitialized scoped_array.
// The input parameter must be allocated with new [].
explicit scoped_array(C* p = NULL) : array_(p) { }
@@ -652,6 +667,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;
@@ -680,12 +696,14 @@ class LIBPROTOBUF_EXPORT LogFinisher {
#undef GOOGLE_LOG_IF
#undef GOOGLE_CHECK
+#undef GOOGLE_CHECK_OK
#undef GOOGLE_CHECK_EQ
#undef GOOGLE_CHECK_NE
#undef GOOGLE_CHECK_LT
#undef GOOGLE_CHECK_LE
#undef GOOGLE_CHECK_GT
#undef GOOGLE_CHECK_GE
+#undef GOOGLE_CHECK_NOTNULL
#undef GOOGLE_DLOG
#undef GOOGLE_DCHECK
@@ -705,6 +723,7 @@ class LIBPROTOBUF_EXPORT LogFinisher {
#define GOOGLE_CHECK(EXPRESSION) \
GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
+#define GOOGLE_CHECK_OK(A) GOOGLE_CHECK(A)
#define GOOGLE_CHECK_EQ(A, B) GOOGLE_CHECK((A) == (B))
#define GOOGLE_CHECK_NE(A, B) GOOGLE_CHECK((A) != (B))
#define GOOGLE_CHECK_LT(A, B) GOOGLE_CHECK((A) < (B))
@@ -712,6 +731,20 @@ class LIBPROTOBUF_EXPORT LogFinisher {
#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) > (B))
#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B))
+namespace internal {
+template<typename T>
+T* CheckNotNull(const char* /* file */, int /* line */,
+ const char* name, T* val) {
+ if (val == NULL) {
+ GOOGLE_LOG(FATAL) << name;
+ }
+ return val;
+}
+} // namespace internal
+#define GOOGLE_CHECK_NOTNULL(A) \
+ ::google::protobuf::internal::CheckNotNull(\
+ __FILE__, __LINE__, "'" #A "' must not be NULL", (A))
+
#ifdef NDEBUG
#define GOOGLE_DLOG GOOGLE_LOG_IF(INFO, false)
@@ -1136,20 +1169,10 @@ using internal::WriterMutexLock;
using internal::MutexLockMaybe;
// ===================================================================
-// from google3/base/type_traits.h
+// from google3/util/utf8/public/unilib.h
namespace internal {
-// Specified by TR1 [4.7.4] Pointer modifications.
-template<typename T> struct remove_pointer { typedef T type; };
-template<typename T> struct remove_pointer<T*> { typedef T type; };
-template<typename T> struct remove_pointer<T* const> { typedef T type; };
-template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
-template<typename T> struct remove_pointer<T* const volatile> {
- typedef T type; };
-
-// ===================================================================
-
// Checks if the buffer contains structurally-valid UTF-8. Implemented in
// structurally_valid.cc.
LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
@@ -1157,6 +1180,10 @@ LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
} // namespace internal
// ===================================================================
+// from google3/util/endian/endian.h
+LIBPROTOBUF_EXPORT uint32 ghtonl(uint32 x);
+
+// ===================================================================
// Shutdown support.
// Shut down the entire protocol buffers library, deleting all static-duration
@@ -1181,7 +1208,7 @@ LIBPROTOBUF_EXPORT void OnShutdown(void (*func)());
} // namespace internal
-#ifdef PROTOBUF_USE_EXCEPTIONS
+#if PROTOBUF_USE_EXCEPTIONS
class FatalException : public std::exception {
public:
FatalException(const char* filename, int line, const std::string& message)
diff --git a/src/google/protobuf/stubs/common_unittest.cc b/src/google/protobuf/stubs/common_unittest.cc
index 4109a52c..5f458e98 100644
--- a/src/google/protobuf/stubs/common_unittest.cc
+++ b/src/google/protobuf/stubs/common_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -31,6 +31,7 @@
// Author: kenton@google.com (Kenton Varda)
#include <vector>
+#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
@@ -94,9 +95,9 @@ TEST(LoggingTest, DefaultLogging) {
string text = GetCapturedTestStderr();
EXPECT_EQ(
- "libprotobuf INFO "__FILE__":" + SimpleItoa(line + 1) + "] A message.\n"
- "libprotobuf WARNING "__FILE__":" + SimpleItoa(line + 2) + "] A warning.\n"
- "libprotobuf ERROR "__FILE__":" + SimpleItoa(line + 3) + "] An error.\n",
+ "[libprotobuf INFO " __FILE__ ":" + SimpleItoa(line + 1) + "] A message.\n"
+ "[libprotobuf WARNING " __FILE__ ":" + SimpleItoa(line + 2) + "] A warning.\n"
+ "[libprotobuf ERROR " __FILE__ ":" + SimpleItoa(line + 3) + "] An error.\n",
text);
}
@@ -127,10 +128,10 @@ TEST(LoggingTest, CaptureLogging) {
ASSERT_EQ(2, captured_messages_.size());
EXPECT_EQ(
- "2 "__FILE__":" + SimpleItoa(start_line + 1) + ": An error.",
+ "2 " __FILE__ ":" + SimpleItoa(start_line + 1) + ": An error.",
captured_messages_[0]);
EXPECT_EQ(
- "1 "__FILE__":" + SimpleItoa(start_line + 2) + ": A warning.",
+ "1 " __FILE__ ":" + SimpleItoa(start_line + 2) + ": A warning.",
captured_messages_[1]);
}
@@ -153,10 +154,10 @@ TEST(LoggingTest, SilenceLogging) {
ASSERT_EQ(2, captured_messages_.size());
EXPECT_EQ(
- "0 "__FILE__":" + SimpleItoa(line1) + ": Visible1",
+ "0 " __FILE__ ":" + SimpleItoa(line1) + ": Visible1",
captured_messages_[0]);
EXPECT_EQ(
- "0 "__FILE__":" + SimpleItoa(line2) + ": Visible2",
+ "0 " __FILE__ ":" + SimpleItoa(line2) + ": Visible2",
captured_messages_[1]);
}
diff --git a/src/google/protobuf/stubs/fastmem.h b/src/google/protobuf/stubs/fastmem.h
new file mode 100644
index 00000000..763a6e60
--- /dev/null
+++ b/src/google/protobuf/stubs/fastmem.h
@@ -0,0 +1,152 @@
+// 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 <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <google/protobuf/stubs/common.h>
+
+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<size_t>(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<uint32>(*a++) - static_cast<uint32>(*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/hash.h b/src/google/protobuf/stubs/hash.h
index 822d6050..82d5052e 100644..100755
--- a/src/google/protobuf/stubs/hash.h
+++ b/src/google/protobuf/stubs/hash.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -37,13 +37,14 @@
#include <string.h>
#include <google/protobuf/stubs/common.h>
-#include "config.h"
+#include <google/protobuf/stubs/pbconfig.h>
-#if defined(HAVE_HASH_MAP) && defined(HAVE_HASH_SET)
-#include HASH_MAP_H
-#include HASH_SET_H
+#if defined(GOOGLE_PROTOBUF_HAVE_HASH_MAP) && \
+ defined(GOOGLE_PROTOBUF_HAVE_HASH_SET)
+#include GOOGLE_PROTOBUF_HASH_MAP_H
+#include GOOGLE_PROTOBUF_HASH_SET_H
#else
-#define MISSING_HASH
+#define GOOGLE_PROTOBUF_MISSING_HASH
#include <map>
#include <set>
#endif
@@ -51,7 +52,7 @@
namespace google {
namespace protobuf {
-#ifdef MISSING_HASH
+#ifdef GOOGLE_PROTOBUF_MISSING_HASH
// This system doesn't have hash_map or hash_set. Emulate them using map and
// set.
@@ -88,20 +89,26 @@ struct hash<const char*> {
template <typename Key, typename Data,
typename HashFcn = hash<Key>,
- typename EqualKey = int >
-class hash_map : public std::map<Key, Data, HashFcn> {
+ typename EqualKey = std::equal_to<Key>,
+ typename Alloc = std::allocator< std::pair<const Key, Data> > >
+class hash_map : public std::map<Key, Data, HashFcn, EqualKey, Alloc> {
+ public:
+ hash_map(int = 0, const HashFcn& = HashFcn(), const EqualKey& = EqualKey(),
+ const Alloc& = Alloc()) {}
};
template <typename Key,
typename HashFcn = hash<Key>,
- typename EqualKey = int >
+ typename EqualKey = std::equal_to<Key> >
class hash_set : public std::set<Key, HashFcn> {
+ public:
+ hash_set(int = 0) {}
};
#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
template <typename Key>
-struct hash : public HASH_NAMESPACE::hash_compare<Key> {
+struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash_compare<Key> {
};
// MSVC's hash_compare<const char*> hashes based on the string contents but
@@ -115,27 +122,34 @@ class CstringLess {
template <>
struct hash<const char*>
- : public HASH_NAMESPACE::hash_compare<const char*, CstringLess> {
-};
+ : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash_compare<
+ const char*, CstringLess> {};
template <typename Key, typename Data,
typename HashFcn = hash<Key>,
- typename EqualKey = int >
-class hash_map : public HASH_NAMESPACE::hash_map<
- Key, Data, HashFcn> {
+ typename EqualKey = std::equal_to<Key>,
+ typename Alloc = std::allocator< std::pair<const Key, Data> > >
+class hash_map
+ : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+ Key, Data, HashFcn, EqualKey, Alloc> {
+ public:
+ hash_map(int = 0, const HashFcn& = HashFcn(), const EqualKey& = EqualKey(),
+ const Alloc& = Alloc()) {}
};
-template <typename Key,
- typename HashFcn = hash<Key>,
- typename EqualKey = int >
-class hash_set : public HASH_NAMESPACE::hash_set<
- Key, HashFcn> {
+template <typename Key, typename HashFcn = hash<Key>,
+ typename EqualKey = std::equal_to<Key> >
+class hash_set
+ : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
+ Key, HashFcn, EqualKey> {
+ public:
+ hash_set(int = 0) {}
};
#else
template <typename Key>
-struct hash : public HASH_NAMESPACE::hash<Key> {
+struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash<Key> {
};
template <typename Key>
@@ -160,19 +174,27 @@ struct hash<const char*> {
template <typename Key, typename Data,
typename HashFcn = hash<Key>,
- typename EqualKey = std::equal_to<Key> >
-class hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS<
- Key, Data, HashFcn, EqualKey> {
+ typename EqualKey = std::equal_to<Key>,
+ typename Alloc = std::allocator< std::pair<const Key, Data> > >
+class hash_map
+ : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+ Key, Data, HashFcn, EqualKey, Alloc> {
+ public:
+ hash_map(int = 0, const HashFcn& = HashFcn(), const EqualKey& = EqualKey(),
+ const Alloc& = Alloc()) {}
};
-template <typename Key,
- typename HashFcn = hash<Key>,
+template <typename Key, typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key> >
-class hash_set : public HASH_NAMESPACE::HASH_SET_CLASS<
- Key, HashFcn, EqualKey> {
+class hash_set
+ : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
+ Key, HashFcn, EqualKey> {
+ public:
+ hash_set(int = 0) {}
};
-#endif
+#undef GOOGLE_PROTOBUF_MISSING_HASH
+#endif // !GOOGLE_PROTOBUF_MISSING_HASH
template <>
struct hash<string> {
diff --git a/src/google/protobuf/stubs/map-util.h b/src/google/protobuf/stubs/map-util.h
deleted file mode 100644
index f5c9d6b6..00000000
--- a/src/google/protobuf/stubs/map-util.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// from google3/util/gtl/map-util.h
-// Author: Anton Carver
-
-#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
-#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
-
-#include <google/protobuf/stubs/common.h>
-
-namespace google {
-namespace protobuf {
-
-// Perform a lookup in a map or hash_map.
-// If the key is present in the map then the value associated with that
-// key is returned, otherwise the value passed as a default is returned.
-template <class Collection>
-const typename Collection::value_type::second_type&
-FindWithDefault(const Collection& collection,
- const typename Collection::value_type::first_type& key,
- const typename Collection::value_type::second_type& value) {
- typename Collection::const_iterator it = collection.find(key);
- if (it == collection.end()) {
- return value;
- }
- return it->second;
-}
-
-// Perform a lookup in a map or hash_map.
-// If the key is present a const pointer to the associated value is returned,
-// otherwise a NULL pointer is returned.
-template <class Collection>
-const typename Collection::value_type::second_type*
-FindOrNull(const Collection& collection,
- const typename Collection::value_type::first_type& key) {
- typename Collection::const_iterator it = collection.find(key);
- if (it == collection.end()) {
- return 0;
- }
- return &it->second;
-}
-
-// Perform a lookup in a map or hash_map whose values are pointers.
-// If the key is present a const pointer to the associated value is returned,
-// otherwise a NULL pointer is returned.
-// This function does not distinguish between a missing key and a key mapped
-// to a NULL value.
-template <class Collection>
-const typename Collection::value_type::second_type
-FindPtrOrNull(const Collection& collection,
- const typename Collection::value_type::first_type& key) {
- typename Collection::const_iterator it = collection.find(key);
- if (it == collection.end()) {
- return 0;
- }
- return it->second;
-}
-
-// Change the value associated with a particular key in a map or hash_map.
-// If the key is not present in the map the key and value are inserted,
-// otherwise the value is updated to be a copy of the value provided.
-// True indicates that an insert took place, false indicates an update.
-template <class Collection, class Key, class Value>
-bool InsertOrUpdate(Collection * const collection,
- const Key& key, const Value& value) {
- pair<typename Collection::iterator, bool> ret =
- collection->insert(typename Collection::value_type(key, value));
- if (!ret.second) {
- // update
- ret.first->second = value;
- return false;
- }
- return true;
-}
-
-// Insert a new key and value into a map or hash_map.
-// If the key is not present in the map the key and value are
-// inserted, otherwise nothing happens. True indicates that an insert
-// took place, false indicates the key was already present.
-template <class Collection, class Key, class Value>
-bool InsertIfNotPresent(Collection * const collection,
- const Key& key, const Value& value) {
- pair<typename Collection::iterator, bool> ret =
- collection->insert(typename Collection::value_type(key, value));
- return ret.second;
-}
-
-} // namespace protobuf
-} // namespace google
-
-#endif // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
diff --git a/src/google/protobuf/stubs/map_util.h b/src/google/protobuf/stubs/map_util.h
new file mode 100644
index 00000000..4cccbbed
--- /dev/null
+++ b/src/google/protobuf/stubs/map_util.h
@@ -0,0 +1,769 @@
+// 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.
+
+// from google3/util/gtl/map_util.h
+// Author: Anton Carver
+
+#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
+
+#include <stddef.h>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// Local implementation of RemoveConst to avoid including base/type_traits.h.
+template <class T> struct RemoveConst { typedef T type; };
+template <class T> struct RemoveConst<const T> : RemoveConst<T> {};
+} // namespace internal
+
+//
+// Find*()
+//
+
+// Returns a const reference to the value associated with the given key if it
+// exists. Crashes otherwise.
+//
+// This is intended as a replacement for operator[] as an rvalue (for reading)
+// when the key is guaranteed to exist.
+//
+// operator[] for lookup is discouraged for several reasons:
+// * It has a side-effect of inserting missing keys
+// * It is not thread-safe (even when it is not inserting, it can still
+// choose to resize the underlying storage)
+// * It invalidates iterators (when it chooses to resize)
+// * It default constructs a value object even if it doesn't need to
+//
+// This version assumes the key is printable, and includes it in the fatal log
+// message.
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindOrDie(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
+ return it->second;
+}
+
+// Same as above, but returns a non-const reference.
+template <class Collection>
+typename Collection::value_type::second_type&
+FindOrDie(Collection& collection, // NOLINT
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::iterator it = collection.find(key);
+ GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
+ return it->second;
+}
+
+// Same as FindOrDie above, but doesn't log the key on failure.
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindOrDieNoPrint(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ GOOGLE_CHECK(it != collection.end()) << "Map key not found";
+ return it->second;
+}
+
+// Same as above, but returns a non-const reference.
+template <class Collection>
+typename Collection::value_type::second_type&
+FindOrDieNoPrint(Collection& collection, // NOLINT
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::iterator it = collection.find(key);
+ GOOGLE_CHECK(it != collection.end()) << "Map key not found";
+ return it->second;
+}
+
+// Returns a const reference to the value associated with the given key if it
+// exists, otherwise returns a const reference to the provided default value.
+//
+// WARNING: If a temporary object is passed as the default "value,"
+// this function will return a reference to that temporary object,
+// which will be destroyed at the end of the statement. A common
+// example: if you have a map with string values, and you pass a char*
+// as the default "value," either use the returned value immediately
+// or store it in a string (not string&).
+// Details: http://go/findwithdefault
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindWithDefault(const Collection& collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& value) {
+ typename Collection::const_iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return value;
+ }
+ return it->second;
+}
+
+// Returns a pointer to the const value associated with the given key if it
+// exists, or NULL otherwise.
+template <class Collection>
+const typename Collection::value_type::second_type*
+FindOrNull(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return 0;
+ }
+ return &it->second;
+}
+
+// Same as above but returns a pointer to the non-const value.
+template <class Collection>
+typename Collection::value_type::second_type*
+FindOrNull(Collection& collection, // NOLINT
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return 0;
+ }
+ return &it->second;
+}
+
+// Returns the pointer value associated with the given key. If none is found,
+// NULL is returned. The function is designed to be used with a map of keys to
+// pointers.
+//
+// This function does not distinguish between a missing key and a key mapped
+// to a NULL value.
+template <class Collection>
+typename Collection::value_type::second_type
+FindPtrOrNull(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return typename Collection::value_type::second_type();
+ }
+ return it->second;
+}
+
+// Same as above, except takes non-const reference to collection.
+//
+// This function is needed for containers that propagate constness to the
+// pointee, such as boost::ptr_map.
+template <class Collection>
+typename Collection::value_type::second_type
+FindPtrOrNull(Collection& collection, // NOLINT
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return typename Collection::value_type::second_type();
+ }
+ return it->second;
+}
+
+// Finds the pointer value associated with the given key in a map whose values
+// are linked_ptrs. Returns NULL if key is not found.
+template <class Collection>
+typename Collection::value_type::second_type::element_type*
+FindLinkedPtrOrNull(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return 0;
+ }
+ // Since linked_ptr::get() is a const member returning a non const,
+ // we do not need a version of this function taking a non const collection.
+ return it->second.get();
+}
+
+// Same as above, but dies if the key is not found.
+template <class Collection>
+typename Collection::value_type::second_type::element_type&
+FindLinkedPtrOrDie(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ CHECK(it != collection.end()) << "key not found: " << key;
+ // Since linked_ptr::operator*() is a const member returning a non const,
+ // we do not need a version of this function taking a non const collection.
+ return *it->second;
+}
+
+// Finds the value associated with the given key and copies it to *value (if not
+// NULL). Returns false if the key was not found, true otherwise.
+template <class Collection, class Key, class Value>
+bool FindCopy(const Collection& collection,
+ const Key& key,
+ Value* const value) {
+ typename Collection::const_iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return false;
+ }
+ if (value) {
+ *value = it->second;
+ }
+ return true;
+}
+
+//
+// Contains*()
+//
+
+// Returns true if and only if the given collection contains the given key.
+template <class Collection, class Key>
+bool ContainsKey(const Collection& collection, const Key& key) {
+ return collection.find(key) != collection.end();
+}
+
+// Returns true if and only if the given collection contains the given key-value
+// pair.
+template <class Collection, class Key, class Value>
+bool ContainsKeyValuePair(const Collection& collection,
+ const Key& key,
+ const Value& value) {
+ typedef typename Collection::const_iterator const_iterator;
+ std::pair<const_iterator, const_iterator> range = collection.equal_range(key);
+ for (const_iterator it = range.first; it != range.second; ++it) {
+ if (it->second == value) {
+ return true;
+ }
+ }
+ return false;
+}
+
+//
+// Insert*()
+//
+
+// Inserts the given key-value pair into the collection. Returns true if and
+// only if the key from the given pair didn't previously exist. Otherwise, the
+// value in the map is replaced with the value from the given pair.
+template <class Collection>
+bool InsertOrUpdate(Collection* const collection,
+ const typename Collection::value_type& vt) {
+ std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
+ if (!ret.second) {
+ // update
+ ret.first->second = vt.second;
+ return false;
+ }
+ return true;
+}
+
+// Same as above, except that the key and value are passed separately.
+template <class Collection>
+bool InsertOrUpdate(Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& value) {
+ return InsertOrUpdate(
+ collection, typename Collection::value_type(key, value));
+}
+
+// Inserts/updates all the key-value pairs from the range defined by the
+// iterators "first" and "last" into the given collection.
+template <class Collection, class InputIterator>
+void InsertOrUpdateMany(Collection* const collection,
+ InputIterator first, InputIterator last) {
+ for (; first != last; ++first) {
+ InsertOrUpdate(collection, *first);
+ }
+}
+
+// Change the value associated with a particular key in a map or hash_map
+// of the form map<Key, Value*> which owns the objects pointed to by the
+// value pointers. If there was an existing value for the key, it is deleted.
+// True indicates an insert took place, false indicates an update + delete.
+template <class Collection>
+bool InsertAndDeleteExisting(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& value) {
+ std::pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(key, value));
+ if (!ret.second) {
+ delete ret.first->second;
+ ret.first->second = value;
+ return false;
+ }
+ return true;
+}
+
+// Inserts the given key and value into the given collection if and only if the
+// given key did NOT already exist in the collection. If the key previously
+// existed in the collection, the value is not changed. Returns true if the
+// key-value pair was inserted; returns false if the key was already present.
+template <class Collection>
+bool InsertIfNotPresent(Collection* const collection,
+ const typename Collection::value_type& vt) {
+ return collection->insert(vt).second;
+}
+
+// Same as above except the key and value are passed separately.
+template <class Collection>
+bool InsertIfNotPresent(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& value) {
+ return InsertIfNotPresent(
+ collection, typename Collection::value_type(key, value));
+}
+
+// Same as above except dies if the key already exists in the collection.
+template <class Collection>
+void InsertOrDie(Collection* const collection,
+ const typename Collection::value_type& value) {
+ CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value;
+}
+
+// Same as above except doesn't log the value on error.
+template <class Collection>
+void InsertOrDieNoPrint(Collection* const collection,
+ const typename Collection::value_type& value) {
+ CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
+}
+
+// Inserts the key-value pair into the collection. Dies if key was already
+// present.
+template <class Collection>
+void InsertOrDie(Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& data) {
+ GOOGLE_CHECK(InsertIfNotPresent(collection, key, data))
+ << "duplicate key: " << key;
+}
+
+// Same as above except doesn't log the key on error.
+template <class Collection>
+void InsertOrDieNoPrint(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& data) {
+ GOOGLE_CHECK(InsertIfNotPresent(collection, key, data)) << "duplicate key.";
+}
+
+// Inserts a new key and default-initialized value. Dies if the key was already
+// present. Returns a reference to the value. Example usage:
+//
+// map<int, SomeProto> m;
+// SomeProto& proto = InsertKeyOrDie(&m, 3);
+// proto.set_field("foo");
+template <class Collection>
+typename Collection::value_type::second_type& InsertKeyOrDie(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key) {
+ typedef typename Collection::value_type value_type;
+ std::pair<typename Collection::iterator, bool> res =
+ collection->insert(value_type(key, typename value_type::second_type()));
+ GOOGLE_CHECK(res.second) << "duplicate key: " << key;
+ return res.first->second;
+}
+
+//
+// Lookup*()
+//
+
+// Looks up a given key and value pair in a collection and inserts the key-value
+// pair if it's not already present. Returns a reference to the value associated
+// with the key.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsert(Collection* const collection,
+ const typename Collection::value_type& vt) {
+ return collection->insert(vt).first->second;
+}
+
+// Same as above except the key-value are passed separately.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsert(Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& value) {
+ return LookupOrInsert(
+ collection, typename Collection::value_type(key, value));
+}
+
+// Counts the number of equivalent elements in the given "sequence", and stores
+// the results in "count_map" with element as the key and count as the value.
+//
+// Example:
+// vector<string> v = {"a", "b", "c", "a", "b"};
+// map<string, int> m;
+// AddTokenCounts(v, 1, &m);
+// assert(m["a"] == 2);
+// assert(m["b"] == 2);
+// assert(m["c"] == 1);
+template <typename Sequence, typename Collection>
+void AddTokenCounts(
+ const Sequence& sequence,
+ const typename Collection::value_type::second_type& increment,
+ Collection* const count_map) {
+ for (typename Sequence::const_iterator it = sequence.begin();
+ it != sequence.end(); ++it) {
+ typename Collection::value_type::second_type& value =
+ LookupOrInsert(count_map, *it,
+ typename Collection::value_type::second_type());
+ value += increment;
+ }
+}
+
+// Returns a reference to the value associated with key. If not found, a value
+// is default constructed on the heap and added to the map.
+//
+// This function is useful for containers of the form map<Key, Value*>, where
+// inserting a new key, value pair involves constructing a new heap-allocated
+// Value, and storing a pointer to that in the collection.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsertNew(Collection* const collection,
+ const typename Collection::value_type::first_type& key) {
+ typedef typename std::iterator_traits<
+ typename Collection::value_type::second_type>::value_type Element;
+ std::pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(
+ key,
+ static_cast<typename Collection::value_type::second_type>(NULL)));
+ if (ret.second) {
+ ret.first->second = new Element();
+ }
+ return ret.first->second;
+}
+
+// Same as above but constructs the value using the single-argument constructor
+// and the given "arg".
+template <class Collection, class Arg>
+typename Collection::value_type::second_type&
+LookupOrInsertNew(Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const Arg& arg) {
+ typedef typename std::iterator_traits<
+ typename Collection::value_type::second_type>::value_type Element;
+ std::pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(
+ key,
+ static_cast<typename Collection::value_type::second_type>(NULL)));
+ if (ret.second) {
+ ret.first->second = new Element(arg);
+ }
+ return ret.first->second;
+}
+
+// Lookup of linked/shared pointers is used in two scenarios:
+//
+// Use LookupOrInsertNewLinkedPtr if the container owns the elements.
+// In this case it is fine working with the raw pointer as long as it is
+// guaranteed that no other thread can delete/update an accessed element.
+// A mutex will need to lock the container operation as well as the use
+// of the returned elements. Finding an element may be performed using
+// FindLinkedPtr*().
+//
+// Use LookupOrInsertNewSharedPtr if the container does not own the elements
+// for their whole lifetime. This is typically the case when a reader allows
+// parallel updates to the container. In this case a Mutex only needs to lock
+// container operations, but all element operations must be performed on the
+// shared pointer. Finding an element must be performed using FindPtr*() and
+// cannot be done with FindLinkedPtr*() even though it compiles.
+
+// Lookup a key in a map or hash_map whose values are linked_ptrs. If it is
+// missing, set collection[key].reset(new Value::element_type) and return that.
+// Value::element_type must be default constructable.
+template <class Collection>
+typename Collection::value_type::second_type::element_type*
+LookupOrInsertNewLinkedPtr(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key) {
+ typedef typename Collection::value_type::second_type Value;
+ std::pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(key, Value()));
+ if (ret.second) {
+ ret.first->second.reset(new typename Value::element_type);
+ }
+ return ret.first->second.get();
+}
+
+// A variant of LookupOrInsertNewLinkedPtr where the value is constructed using
+// a single-parameter constructor. Note: the constructor argument is computed
+// even if it will not be used, so only values cheap to compute should be passed
+// here. On the other hand it does not matter how expensive the construction of
+// the actual stored value is, as that only occurs if necessary.
+template <class Collection, class Arg>
+typename Collection::value_type::second_type::element_type*
+LookupOrInsertNewLinkedPtr(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const Arg& arg) {
+ typedef typename Collection::value_type::second_type Value;
+ std::pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(key, Value()));
+ if (ret.second) {
+ ret.first->second.reset(new typename Value::element_type(arg));
+ }
+ return ret.first->second.get();
+}
+
+// Lookup a key in a map or hash_map whose values are shared_ptrs. If it is
+// missing, set collection[key].reset(new Value::element_type). Unlike
+// LookupOrInsertNewLinkedPtr, this function returns the shared_ptr instead of
+// the raw pointer. Value::element_type must be default constructable.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsertNewSharedPtr(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key) {
+ typedef typename Collection::value_type::second_type SharedPtr;
+ typedef typename Collection::value_type::second_type::element_type Element;
+ std::pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(key, SharedPtr()));
+ if (ret.second) {
+ ret.first->second.reset(new Element());
+ }
+ return ret.first->second;
+}
+
+// A variant of LookupOrInsertNewSharedPtr where the value is constructed using
+// a single-parameter constructor. Note: the constructor argument is computed
+// even if it will not be used, so only values cheap to compute should be passed
+// here. On the other hand it does not matter how expensive the construction of
+// the actual stored value is, as that only occurs if necessary.
+template <class Collection, class Arg>
+typename Collection::value_type::second_type&
+LookupOrInsertNewSharedPtr(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const Arg& arg) {
+ typedef typename Collection::value_type::second_type SharedPtr;
+ typedef typename Collection::value_type::second_type::element_type Element;
+ std::pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(key, SharedPtr()));
+ if (ret.second) {
+ ret.first->second.reset(new Element(arg));
+ }
+ return ret.first->second;
+}
+
+//
+// Misc Utility Functions
+//
+
+// Updates the value associated with the given key. If the key was not already
+// present, then the key-value pair are inserted and "previous" is unchanged. If
+// the key was already present, the value is updated and "*previous" will
+// contain a copy of the old value.
+//
+// InsertOrReturnExisting has complementary behavior that returns the
+// address of an already existing value, rather than updating it.
+template <class Collection>
+bool UpdateReturnCopy(Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& value,
+ typename Collection::value_type::second_type* previous) {
+ std::pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(key, value));
+ if (!ret.second) {
+ // update
+ if (previous) {
+ *previous = ret.first->second;
+ }
+ ret.first->second = value;
+ return true;
+ }
+ return false;
+}
+
+// Same as above except that the key and value are passed as a pair.
+template <class Collection>
+bool UpdateReturnCopy(Collection* const collection,
+ const typename Collection::value_type& vt,
+ typename Collection::value_type::second_type* previous) {
+ std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
+ if (!ret.second) {
+ // update
+ if (previous) {
+ *previous = ret.first->second;
+ }
+ ret.first->second = vt.second;
+ return true;
+ }
+ return false;
+}
+
+// Tries to insert the given key-value pair into the collection. Returns NULL if
+// the insert succeeds. Otherwise, returns a pointer to the existing value.
+//
+// This complements UpdateReturnCopy in that it allows to update only after
+// verifying the old value and still insert quickly without having to look up
+// twice. Unlike UpdateReturnCopy this also does not come with the issue of an
+// undefined previous* in case new data was inserted.
+template <class Collection>
+typename Collection::value_type::second_type* const
+InsertOrReturnExisting(Collection* const collection,
+ const typename Collection::value_type& vt) {
+ std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
+ if (ret.second) {
+ return NULL; // Inserted, no existing previous value.
+ } else {
+ return &ret.first->second; // Return address of already existing value.
+ }
+}
+
+// Same as above, except for explicit key and data.
+template <class Collection>
+typename Collection::value_type::second_type* const
+InsertOrReturnExisting(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& data) {
+ return InsertOrReturnExisting(collection,
+ typename Collection::value_type(key, data));
+}
+
+// Erases the collection item identified by the given key, and returns the value
+// associated with that key. It is assumed that the value (i.e., the
+// mapped_type) is a pointer. Returns NULL if the key was not found in the
+// collection.
+//
+// Examples:
+// map<string, MyType*> my_map;
+//
+// One line cleanup:
+// delete EraseKeyReturnValuePtr(&my_map, "abc");
+//
+// Use returned value:
+// scoped_ptr<MyType> value_ptr(EraseKeyReturnValuePtr(&my_map, "abc"));
+// if (value_ptr.get())
+// value_ptr->DoSomething();
+//
+template <class Collection>
+typename Collection::value_type::second_type EraseKeyReturnValuePtr(
+ Collection* const collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::iterator it = collection->find(key);
+ if (it == collection->end()) {
+ return NULL;
+ }
+ typename Collection::value_type::second_type v = it->second;
+ collection->erase(it);
+ return v;
+}
+
+// Inserts all the keys from map_container into key_container, which must
+// support insert(MapContainer::key_type).
+//
+// Note: any initial contents of the key_container are not cleared.
+template <class MapContainer, class KeyContainer>
+void InsertKeysFromMap(const MapContainer& map_container,
+ KeyContainer* key_container) {
+ GOOGLE_CHECK(key_container != NULL);
+ for (typename MapContainer::const_iterator it = map_container.begin();
+ it != map_container.end(); ++it) {
+ key_container->insert(it->first);
+ }
+}
+
+// Appends all the keys from map_container into key_container, which must
+// support push_back(MapContainer::key_type).
+//
+// Note: any initial contents of the key_container are not cleared.
+template <class MapContainer, class KeyContainer>
+void AppendKeysFromMap(const MapContainer& map_container,
+ KeyContainer* key_container) {
+ GOOGLE_CHECK(key_container != NULL);
+ for (typename MapContainer::const_iterator it = map_container.begin();
+ it != map_container.end(); ++it) {
+ key_container->push_back(it->first);
+ }
+}
+
+// A more specialized overload of AppendKeysFromMap to optimize reallocations
+// for the common case in which we're appending keys to a vector and hence can
+// (and sometimes should) call reserve() first.
+//
+// (It would be possible to play SFINAE games to call reserve() for any
+// container that supports it, but this seems to get us 99% of what we need
+// without the complexity of a SFINAE-based solution.)
+template <class MapContainer, class KeyType>
+void AppendKeysFromMap(const MapContainer& map_container,
+ vector<KeyType>* key_container) {
+ GOOGLE_CHECK(key_container != NULL);
+ // We now have the opportunity to call reserve(). Calling reserve() every
+ // time is a bad idea for some use cases: libstdc++'s implementation of
+ // vector<>::reserve() resizes the vector's backing store to exactly the
+ // given size (unless it's already at least that big). Because of this,
+ // the use case that involves appending a lot of small maps (total size
+ // N) one by one to a vector would be O(N^2). But never calling reserve()
+ // loses the opportunity to improve the use case of adding from a large
+ // map to an empty vector (this improves performance by up to 33%). A
+ // number of heuristics are possible; see the discussion in
+ // cl/34081696. Here we use the simplest one.
+ if (key_container->empty()) {
+ key_container->reserve(map_container.size());
+ }
+ for (typename MapContainer::const_iterator it = map_container.begin();
+ it != map_container.end(); ++it) {
+ key_container->push_back(it->first);
+ }
+}
+
+// Inserts all the values from map_container into value_container, which must
+// support push_back(MapContainer::mapped_type).
+//
+// Note: any initial contents of the value_container are not cleared.
+template <class MapContainer, class ValueContainer>
+void AppendValuesFromMap(const MapContainer& map_container,
+ ValueContainer* value_container) {
+ GOOGLE_CHECK(value_container != NULL);
+ for (typename MapContainer::const_iterator it = map_container.begin();
+ it != map_container.end(); ++it) {
+ value_container->push_back(it->second);
+ }
+}
+
+// A more specialized overload of AppendValuesFromMap to optimize reallocations
+// for the common case in which we're appending values to a vector and hence
+// can (and sometimes should) call reserve() first.
+//
+// (It would be possible to play SFINAE games to call reserve() for any
+// container that supports it, but this seems to get us 99% of what we need
+// without the complexity of a SFINAE-based solution.)
+template <class MapContainer, class ValueType>
+void AppendValuesFromMap(const MapContainer& map_container,
+ vector<ValueType>* value_container) {
+ GOOGLE_CHECK(value_container != NULL);
+ // See AppendKeysFromMap for why this is done.
+ if (value_container->empty()) {
+ value_container->reserve(map_container.size());
+ }
+ for (typename MapContainer::const_iterator it = map_container.begin();
+ it != map_container.end(); ++it) {
+ value_container->push_back(it->second);
+ }
+}
+
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
diff --git a/src/google/protobuf/stubs/once.cc b/src/google/protobuf/stubs/once.cc
index 5b7af9ce..889c6476 100644
--- a/src/google/protobuf/stubs/once.cc
+++ b/src/google/protobuf/stubs/once.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -35,54 +35,65 @@
// This header is intended to be included only by internal .cc files and
// generated .pb.cc files. Users should not use this directly.
+#include <google/protobuf/stubs/once.h>
+
+#ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
+
#ifdef _WIN32
#include <windows.h>
+#else
+#include <sched.h>
#endif
-#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/atomicops.h>
namespace google {
namespace protobuf {
-#ifdef _WIN32
-
-struct ProtobufOnceInternal {
- ProtobufOnceInternal() {
- InitializeCriticalSection(&critical_section);
- }
- ~ProtobufOnceInternal() {
- DeleteCriticalSection(&critical_section);
- }
- CRITICAL_SECTION critical_section;
-};
-
-ProtobufOnceType::~ProtobufOnceType()
-{
- delete internal_;
- internal_ = NULL;
-}
+namespace {
-ProtobufOnceType::ProtobufOnceType() {
- // internal_ may be non-NULL if Init() was already called.
- if (internal_ == NULL) internal_ = new ProtobufOnceInternal;
+void SchedYield() {
+#ifdef _WIN32
+ Sleep(0);
+#else // POSIX
+ sched_yield();
+#endif
}
-void ProtobufOnceType::Init(void (*init_func)()) {
- // internal_ may be NULL if we're still in dynamic initialization and the
- // constructor has not been called yet. As mentioned in once.h, we assume
- // that the program is still single-threaded at this time, and therefore it
- // should be safe to initialize internal_ like so.
- if (internal_ == NULL) internal_ = new ProtobufOnceInternal;
+} // namespace
- EnterCriticalSection(&internal_->critical_section);
- if (!initialized_) {
- init_func();
- initialized_ = true;
+void GoogleOnceInitImpl(ProtobufOnceType* once, Closure* closure) {
+ internal::AtomicWord state = internal::Acquire_Load(once);
+ // Fast path. The provided closure was already executed.
+ if (state == ONCE_STATE_DONE) {
+ return;
+ }
+ // The closure execution did not complete yet. The once object can be in one
+ // of the two following states:
+ // - UNINITIALIZED: We are the first thread calling this function.
+ // - EXECUTING_CLOSURE: Another thread is already executing the closure.
+ //
+ // First, try to change the state from UNINITIALIZED to EXECUTING_CLOSURE
+ // atomically.
+ state = internal::Acquire_CompareAndSwap(
+ once, ONCE_STATE_UNINITIALIZED, ONCE_STATE_EXECUTING_CLOSURE);
+ if (state == ONCE_STATE_UNINITIALIZED) {
+ // We are the first thread to call this function, so we have to call the
+ // closure.
+ closure->Run();
+ internal::Release_Store(once, ONCE_STATE_DONE);
+ } else {
+ // Another thread has already started executing the closure. We need to
+ // wait until it completes the initialization.
+ while (state == ONCE_STATE_EXECUTING_CLOSURE) {
+ // Note that futex() could be used here on Linux as an improvement.
+ SchedYield();
+ state = internal::Acquire_Load(once);
+ }
}
- LeaveCriticalSection(&internal_->critical_section);
}
-#endif
-
} // namespace protobuf
} // namespace google
+
+#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
diff --git a/src/google/protobuf/stubs/once.h b/src/google/protobuf/stubs/once.h
index 0dee4076..cc62bbaa 100644
--- a/src/google/protobuf/stubs/once.h
+++ b/src/google/protobuf/stubs/once.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -37,16 +37,22 @@
//
// This is basically a portable version of pthread_once().
//
-// This header declares three things:
+// This header declares:
// * A type called ProtobufOnceType.
// * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type
// ProtobufOnceType. This is the only legal way to declare such a variable.
-// The macro may only be used at the global scope (you cannot create local
-// or class member variables of this type).
-// * A function GogoleOnceInit(ProtobufOnceType* once, void (*init_func)()).
+// The macro may only be used at the global scope (you cannot create local or
+// class member variables of this type).
+// * A function GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()).
// This function, when invoked multiple times given the same ProtobufOnceType
// object, will invoke init_func on the first call only, and will make sure
// none of the calls return before that first call to init_func has finished.
+// * The user can provide a parameter which GoogleOnceInit() forwards to the
+// user-provided function when it is called. Usage example:
+// int a = 10;
+// GoogleOnceInit(&my_once, &MyFunctionExpectingIntArgument, &a);
+// * This implementation guarantees that ProtobufOnceType is a POD (i.e. no
+// static initializer generated).
//
// This implements a way to perform lazy initialization. It's more efficient
// than using mutexes as no lock is needed if initialization has already
@@ -72,50 +78,87 @@
#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
#define GOOGLE_PROTOBUF_STUBS_ONCE_H__
+#include <google/protobuf/stubs/atomicops.h>
#include <google/protobuf/stubs/common.h>
-#ifndef _WIN32
-#include <pthread.h>
-#endif
-
namespace google {
namespace protobuf {
-#ifdef _WIN32
-
-struct ProtobufOnceInternal;
+#ifdef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
-struct LIBPROTOBUF_EXPORT ProtobufOnceType {
- ProtobufOnceType();
- ~ProtobufOnceType();
- void Init(void (*init_func)());
+typedef bool ProtobufOnceType;
- volatile bool initialized_;
- ProtobufOnceInternal* internal_;
-};
-
-#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
- ::google::protobuf::ProtobufOnceType NAME
+#define GOOGLE_PROTOBUF_ONCE_INIT false
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
- // Note: Double-checked locking is safe on x86.
- if (!once->initialized_) {
- once->Init(init_func);
+ if (!*once) {
+ *once = true;
+ init_func();
+ }
+}
+
+template <typename Arg>
+inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)(Arg),
+ Arg arg) {
+ if (!*once) {
+ *once = true;
+ init_func(arg);
}
}
#else
-typedef pthread_once_t ProtobufOnceType;
+enum {
+ ONCE_STATE_UNINITIALIZED = 0,
+ ONCE_STATE_EXECUTING_CLOSURE = 1,
+ ONCE_STATE_DONE = 2
+};
+
+typedef internal::AtomicWord ProtobufOnceType;
-#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
- pthread_once_t NAME = PTHREAD_ONCE_INIT
+#define GOOGLE_PROTOBUF_ONCE_INIT ::google::protobuf::ONCE_STATE_UNINITIALIZED
+
+LIBPROTOBUF_EXPORT
+void GoogleOnceInitImpl(ProtobufOnceType* once, Closure* closure);
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
- pthread_once(once, init_func);
+ if (internal::Acquire_Load(once) != ONCE_STATE_DONE) {
+ internal::FunctionClosure0 func(init_func, false);
+ GoogleOnceInitImpl(once, &func);
+ }
+}
+
+template <typename Arg>
+inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)(Arg*),
+ Arg* arg) {
+ if (internal::Acquire_Load(once) != ONCE_STATE_DONE) {
+ internal::FunctionClosure1<Arg*> func(init_func, false, arg);
+ GoogleOnceInitImpl(once, &func);
+ }
}
-#endif
+#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
+
+class GoogleOnceDynamic {
+ public:
+ GoogleOnceDynamic() : state_(GOOGLE_PROTOBUF_ONCE_INIT) { }
+
+ // If this->Init() has not been called before by any thread,
+ // execute (*func_with_arg)(arg) then return.
+ // Otherwise, wait until that prior invocation has finished
+ // executing its function, then return.
+ template<typename T>
+ void Init(void (*func_with_arg)(T*), T* arg) {
+ GoogleOnceInit<T>(&this->state_,
+ func_with_arg,
+ arg);
+ }
+ private:
+ ProtobufOnceType state_;
+};
+
+#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
+ ::google::protobuf::ProtobufOnceType NAME = GOOGLE_PROTOBUF_ONCE_INIT
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/stubs/once_unittest.cc b/src/google/protobuf/stubs/once_unittest.cc
index b8f86a0f..cb5a20dd 100644
--- a/src/google/protobuf/stubs/once_unittest.cc
+++ b/src/google/protobuf/stubs/once_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/stubs/platform_macros.h b/src/google/protobuf/stubs/platform_macros.h
new file mode 100644
index 00000000..1ff09b83
--- /dev/null
+++ b/src/google/protobuf/stubs/platform_macros.h
@@ -0,0 +1,108 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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_PLATFORM_MACROS_H_
+#define GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
+
+#include <google/protobuf/stubs/common.h>
+
+#define GOOGLE_PROTOBUF_PLATFORM_ERROR \
+#error "Host platform was not detected as supported by protobuf"
+
+// Processor architecture detection. For more info on what's defined, see:
+// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+// http://www.agner.org/optimize/calling_conventions.pdf
+// or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define GOOGLE_PROTOBUF_ARCH_X64 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(_M_IX86) || defined(__i386__)
+#define GOOGLE_PROTOBUF_ARCH_IA32 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(__QNX__)
+#define GOOGLE_PROTOBUF_ARCH_ARM_QNX 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(__ARMEL__)
+#define GOOGLE_PROTOBUF_ARCH_ARM 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(__aarch64__)
+#define GOOGLE_PROTOBUF_ARCH_AARCH64 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(__MIPSEL__)
+#if defined(__LP64__)
+#define GOOGLE_PROTOBUF_ARCH_MIPS64 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#else
+#define GOOGLE_PROTOBUF_ARCH_MIPS 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#endif
+#elif defined(__pnacl__)
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(sparc)
+#define GOOGLE_PROTOBUF_ARCH_SPARC 1
+#ifdef SOLARIS_64BIT_ENABLED
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#else
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#endif
+#elif defined(_POWER)
+#define GOOGLE_PROTOBUF_ARCH_POWER 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(__GNUC__)
+# if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
+// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
+# elif defined(__clang__)
+# if !__has_extension(c_atomic)
+GOOGLE_PROTOBUF_PLATFORM_ERROR
+# endif
+// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
+# endif
+# if __LP64__
+# define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+# else
+# define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+# endif
+#else
+GOOGLE_PROTOBUF_PLATFORM_ERROR
+#endif
+
+#if defined(__APPLE__)
+#define GOOGLE_PROTOBUF_OS_APPLE
+#elif defined(__native_client__)
+#define GOOGLE_PROTOBUF_OS_NACL
+#elif defined(sun)
+#define GOOGLE_PROTOBUF_OS_SOLARIS
+#elif defined(_AIX)
+#define GOOGLE_PROTOBUF_OS_AIX
+#endif
+
+#undef GOOGLE_PROTOBUF_PLATFORM_ERROR
+
+#endif // GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
diff --git a/src/google/protobuf/stubs/shared_ptr.h b/src/google/protobuf/stubs/shared_ptr.h
new file mode 100644
index 00000000..d250bf4d
--- /dev/null
+++ b/src/google/protobuf/stubs/shared_ptr.h
@@ -0,0 +1,470 @@
+// 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.
+
+// from google3/util/gtl/shared_ptr.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_SHARED_PTR_H__
+#define GOOGLE_PROTOBUF_STUBS_SHARED_PTR_H__
+
+#include <google/protobuf/stubs/atomicops.h>
+
+#include <algorithm> // for swap
+#include <stddef.h>
+#include <memory>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Alias to std::shared_ptr for any C++11 platform,
+// and for any supported MSVC compiler.
+#if !defined(UTIL_GTL_USE_STD_SHARED_PTR) && \
+ (defined(COMPILER_MSVC) || defined(LANG_CXX11))
+#define UTIL_GTL_USE_STD_SHARED_PTR 1
+#endif
+
+#if defined(UTIL_GTL_USE_STD_SHARED_PTR) && UTIL_GTL_USE_STD_SHARED_PTR
+
+// These are transitional. They will be going away soon.
+// Please just #include <memory> and just type std::shared_ptr yourself, instead
+// of relying on this file.
+//
+// Migration doc: http://go/std-shared-ptr-lsc
+using std::enable_shared_from_this;
+using std::shared_ptr;
+using std::static_pointer_cast;
+using std::weak_ptr;
+
+#else // below, UTIL_GTL_USE_STD_SHARED_PTR not set or set to 0.
+
+// For everything else there is the google3 implementation.
+inline bool RefCountDec(volatile Atomic32 *ptr) {
+ return Barrier_AtomicIncrement(ptr, -1) != 0;
+}
+
+inline void RefCountInc(volatile Atomic32 *ptr) {
+ NoBarrier_AtomicIncrement(ptr, 1);
+}
+
+template <typename T> class shared_ptr;
+template <typename T> class weak_ptr;
+
+// This class is an internal implementation detail for shared_ptr. If two
+// shared_ptrs point to the same object, they also share a control block.
+// An "empty" shared_pointer refers to NULL and also has a NULL control block.
+// It contains all of the state that's needed for reference counting or any
+// other kind of resource management. In this implementation the control block
+// happens to consist of two atomic words, the reference count (the number
+// of shared_ptrs that share ownership of the object) and the weak count
+// (the number of weak_ptrs that observe the object, plus 1 if the
+// refcount is nonzero).
+//
+// The "plus 1" is to prevent a race condition in the shared_ptr and
+// weak_ptr destructors. We need to make sure the control block is
+// only deleted once, so we need to make sure that at most one
+// object sees the weak count decremented from 1 to 0.
+class SharedPtrControlBlock {
+ template <typename T> friend class shared_ptr;
+ template <typename T> friend class weak_ptr;
+ private:
+ SharedPtrControlBlock() : refcount_(1), weak_count_(1) { }
+ Atomic32 refcount_;
+ Atomic32 weak_count_;
+};
+
+// Forward declaration. The class is defined below.
+template <typename T> class enable_shared_from_this;
+
+template <typename T>
+class shared_ptr {
+ template <typename U> friend class weak_ptr;
+ public:
+ typedef T element_type;
+
+ shared_ptr() : ptr_(NULL), control_block_(NULL) {}
+
+ explicit shared_ptr(T* ptr)
+ : ptr_(ptr),
+ control_block_(ptr != NULL ? new SharedPtrControlBlock : NULL) {
+ // If p is non-null and T inherits from enable_shared_from_this, we
+ // set up the data that shared_from_this needs.
+ MaybeSetupWeakThis(ptr);
+ }
+
+ // Copy constructor: makes this object a copy of ptr, and increments
+ // the reference count.
+ template <typename U>
+ shared_ptr(const shared_ptr<U>& ptr)
+ : ptr_(NULL),
+ control_block_(NULL) {
+ Initialize(ptr);
+ }
+ // Need non-templated version to prevent the compiler-generated default
+ shared_ptr(const shared_ptr<T>& ptr)
+ : ptr_(NULL),
+ control_block_(NULL) {
+ Initialize(ptr);
+ }
+
+ // Assignment operator. Replaces the existing shared_ptr with ptr.
+ // Increment ptr's reference count and decrement the one being replaced.
+ template <typename U>
+ shared_ptr<T>& operator=(const shared_ptr<U>& ptr) {
+ if (ptr_ != ptr.ptr_) {
+ shared_ptr<T> me(ptr); // will hold our previous state to be destroyed.
+ swap(me);
+ }
+ return *this;
+ }
+
+ // Need non-templated version to prevent the compiler-generated default
+ shared_ptr<T>& operator=(const shared_ptr<T>& ptr) {
+ if (ptr_ != ptr.ptr_) {
+ shared_ptr<T> me(ptr); // will hold our previous state to be destroyed.
+ swap(me);
+ }
+ return *this;
+ }
+
+ // TODO(austern): Consider providing this constructor. The draft C++ standard
+ // (20.8.10.2.1) includes it. However, it says that this constructor throws
+ // a bad_weak_ptr exception when ptr is expired. Is it better to provide this
+ // constructor and make it do something else, like fail with a CHECK, or to
+ // leave this constructor out entirely?
+ //
+ // template <typename U>
+ // shared_ptr(const weak_ptr<U>& ptr);
+
+ ~shared_ptr() {
+ if (ptr_ != NULL) {
+ if (!RefCountDec(&control_block_->refcount_)) {
+ delete ptr_;
+
+ // weak_count_ is defined as the number of weak_ptrs that observe
+ // ptr_, plus 1 if refcount_ is nonzero.
+ if (!RefCountDec(&control_block_->weak_count_)) {
+ delete control_block_;
+ }
+ }
+ }
+ }
+
+ // Replaces underlying raw pointer with the one passed in. The reference
+ // count is set to one (or zero if the pointer is NULL) for the pointer
+ // being passed in and decremented for the one being replaced.
+ //
+ // If you have a compilation error with this code, make sure you aren't
+ // passing NULL, nullptr, or 0 to this function. Call reset without an
+ // argument to reset to a null ptr.
+ template <typename Y>
+ void reset(Y* p) {
+ if (p != ptr_) {
+ shared_ptr<T> tmp(p);
+ tmp.swap(*this);
+ }
+ }
+
+ void reset() {
+ reset(static_cast<T*>(NULL));
+ }
+
+ // Exchanges the contents of this with the contents of r. This function
+ // supports more efficient swapping since it eliminates the need for a
+ // temporary shared_ptr object.
+ void swap(shared_ptr<T>& r) {
+ using std::swap; // http://go/using-std-swap
+ swap(ptr_, r.ptr_);
+ swap(control_block_, r.control_block_);
+ }
+
+ // The following function is useful for gaining access to the underlying
+ // pointer when a shared_ptr remains in scope so the reference-count is
+ // known to be > 0 (e.g. for parameter passing).
+ T* get() const {
+ return ptr_;
+ }
+
+ T& operator*() const {
+ return *ptr_;
+ }
+
+ T* operator->() const {
+ return ptr_;
+ }
+
+ long use_count() const {
+ return control_block_ ? control_block_->refcount_ : 1;
+ }
+
+ bool unique() const {
+ return use_count() == 1;
+ }
+
+ private:
+ // If r is non-empty, initialize *this to share ownership with r,
+ // increasing the underlying reference count.
+ // If r is empty, *this remains empty.
+ // Requires: this is empty, namely this->ptr_ == NULL.
+ template <typename U>
+ void Initialize(const shared_ptr<U>& r) {
+ // This performs a static_cast on r.ptr_ to U*, which is a no-op since it
+ // is already a U*. So initialization here requires that r.ptr_ is
+ // implicitly convertible to T*.
+ InitializeWithStaticCast<U>(r);
+ }
+
+ // Initializes *this as described in Initialize, but additionally performs a
+ // static_cast from r.ptr_ (V*) to U*.
+ // NOTE(gfc): We'd need a more general form to support const_pointer_cast and
+ // dynamic_pointer_cast, but those operations are sufficiently discouraged
+ // that supporting static_pointer_cast is sufficient.
+ template <typename U, typename V>
+ void InitializeWithStaticCast(const shared_ptr<V>& r) {
+ if (r.control_block_ != NULL) {
+ RefCountInc(&r.control_block_->refcount_);
+
+ ptr_ = static_cast<U*>(r.ptr_);
+ control_block_ = r.control_block_;
+ }
+ }
+
+ // Helper function for the constructor that takes a raw pointer. If T
+ // doesn't inherit from enable_shared_from_this<T> then we have nothing to
+ // do, so this function is trivial and inline. The other version is declared
+ // out of line, after the class definition of enable_shared_from_this.
+ void MaybeSetupWeakThis(enable_shared_from_this<T>* ptr);
+ void MaybeSetupWeakThis(...) { }
+
+ T* ptr_;
+ SharedPtrControlBlock* control_block_;
+
+#ifndef SWIG
+ template <typename U>
+ friend class shared_ptr;
+
+ template <typename U, typename V>
+ friend shared_ptr<U> static_pointer_cast(const shared_ptr<V>& rhs);
+#endif
+};
+
+// Matches the interface of std::swap as an aid to generic programming.
+template <typename T> void swap(shared_ptr<T>& r, shared_ptr<T>& s) {
+ r.swap(s);
+}
+
+template <typename T, typename U>
+shared_ptr<T> static_pointer_cast(const shared_ptr<U>& rhs) {
+ shared_ptr<T> lhs;
+ lhs.template InitializeWithStaticCast<T>(rhs);
+ return lhs;
+}
+
+// See comments at the top of the file for a description of why this
+// class exists, and the draft C++ standard (as of July 2009 the
+// latest draft is N2914) for the detailed specification.
+template <typename T>
+class weak_ptr {
+ template <typename U> friend class weak_ptr;
+ public:
+ typedef T element_type;
+
+ // Create an empty (i.e. already expired) weak_ptr.
+ weak_ptr() : ptr_(NULL), control_block_(NULL) { }
+
+ // Create a weak_ptr that observes the same object that ptr points
+ // to. Note that there is no race condition here: we know that the
+ // control block can't disappear while we're looking at it because
+ // it is owned by at least one shared_ptr, ptr.
+ template <typename U> weak_ptr(const shared_ptr<U>& ptr) {
+ CopyFrom(ptr.ptr_, ptr.control_block_);
+ }
+
+ // Copy a weak_ptr. The object it points to might disappear, but we
+ // don't care: we're only working with the control block, and it can't
+ // disappear while we're looking at because it's owned by at least one
+ // weak_ptr, ptr.
+ template <typename U> weak_ptr(const weak_ptr<U>& ptr) {
+ CopyFrom(ptr.ptr_, ptr.control_block_);
+ }
+
+ // Need non-templated version to prevent default copy constructor
+ weak_ptr(const weak_ptr& ptr) {
+ CopyFrom(ptr.ptr_, ptr.control_block_);
+ }
+
+ // Destroy the weak_ptr. If no shared_ptr owns the control block, and if
+ // we are the last weak_ptr to own it, then it can be deleted. Note that
+ // weak_count_ is defined as the number of weak_ptrs sharing this control
+ // block, plus 1 if there are any shared_ptrs. We therefore know that it's
+ // safe to delete the control block when weak_count_ reaches 0, without
+ // having to perform any additional tests.
+ ~weak_ptr() {
+ if (control_block_ != NULL &&
+ !RefCountDec(&control_block_->weak_count_)) {
+ delete control_block_;
+ }
+ }
+
+ weak_ptr& operator=(const weak_ptr& ptr) {
+ if (&ptr != this) {
+ weak_ptr tmp(ptr);
+ tmp.swap(*this);
+ }
+ return *this;
+ }
+ template <typename U> weak_ptr& operator=(const weak_ptr<U>& ptr) {
+ weak_ptr tmp(ptr);
+ tmp.swap(*this);
+ return *this;
+ }
+ template <typename U> weak_ptr& operator=(const shared_ptr<U>& ptr) {
+ weak_ptr tmp(ptr);
+ tmp.swap(*this);
+ return *this;
+ }
+
+ void swap(weak_ptr& ptr) {
+ using std::swap; // http://go/using-std-swap
+ swap(ptr_, ptr.ptr_);
+ swap(control_block_, ptr.control_block_);
+ }
+
+ void reset() {
+ weak_ptr tmp;
+ tmp.swap(*this);
+ }
+
+ // Return the number of shared_ptrs that own the object we are observing.
+ // Note that this number can be 0 (if this pointer has expired).
+ long use_count() const {
+ return control_block_ != NULL ? control_block_->refcount_ : 0;
+ }
+
+ bool expired() const { return use_count() == 0; }
+
+ // Return a shared_ptr that owns the object we are observing. If we
+ // have expired, the shared_ptr will be empty. We have to be careful
+ // about concurrency, though, since some other thread might be
+ // destroying the last owning shared_ptr while we're in this
+ // function. We want to increment the refcount only if it's nonzero
+ // and get the new value, and we want that whole operation to be
+ // atomic.
+ shared_ptr<T> lock() const {
+ shared_ptr<T> result;
+ if (control_block_ != NULL) {
+ Atomic32 old_refcount;
+ do {
+ old_refcount = control_block_->refcount_;
+ if (old_refcount == 0)
+ break;
+ } while (old_refcount !=
+ NoBarrier_CompareAndSwap(
+ &control_block_->refcount_, old_refcount,
+ old_refcount + 1));
+ if (old_refcount > 0) {
+ result.ptr_ = ptr_;
+ result.control_block_ = control_block_;
+ }
+ }
+
+ return result;
+ }
+
+ private:
+ void CopyFrom(T* ptr, SharedPtrControlBlock* control_block) {
+ ptr_ = ptr;
+ control_block_ = control_block;
+ if (control_block_ != NULL)
+ RefCountInc(&control_block_->weak_count_);
+ }
+
+ private:
+ element_type* ptr_;
+ SharedPtrControlBlock* control_block_;
+};
+
+template <typename T> void swap(weak_ptr<T>& r, weak_ptr<T>& s) {
+ r.swap(s);
+}
+
+// See comments at the top of the file for a description of why this class
+// exists, and section 20.8.10.5 of the draft C++ standard (as of July 2009
+// the latest draft is N2914) for the detailed specification.
+template <typename T>
+class enable_shared_from_this {
+ friend class shared_ptr<T>;
+ public:
+ // Precondition: there must be a shared_ptr that owns *this and that was
+ // created, directly or indirectly, from a raw pointer of type T*. (The
+ // latter part of the condition is technical but not quite redundant; it
+ // rules out some complicated uses involving inheritance hierarchies.)
+ shared_ptr<T> shared_from_this() {
+ // Behavior is undefined if the precondition isn't satisfied; we choose
+ // to die with a CHECK failure.
+ CHECK(!weak_this_.expired()) << "No shared_ptr owns this object";
+ return weak_this_.lock();
+ }
+ shared_ptr<const T> shared_from_this() const {
+ CHECK(!weak_this_.expired()) << "No shared_ptr owns this object";
+ return weak_this_.lock();
+ }
+
+ protected:
+ enable_shared_from_this() { }
+ enable_shared_from_this(const enable_shared_from_this& other) { }
+ enable_shared_from_this& operator=(const enable_shared_from_this& other) {
+ return *this;
+ }
+ ~enable_shared_from_this() { }
+
+ private:
+ weak_ptr<T> weak_this_;
+};
+
+// This is a helper function called by shared_ptr's constructor from a raw
+// pointer. If T inherits from enable_shared_from_this<T>, it sets up
+// weak_this_ so that shared_from_this works correctly. If T does not inherit
+// from weak_this we get a different overload, defined inline, which does
+// nothing.
+template<typename T>
+void shared_ptr<T>::MaybeSetupWeakThis(enable_shared_from_this<T>* ptr) {
+ if (ptr) {
+ CHECK(ptr->weak_this_.expired()) << "Object already owned by a shared_ptr";
+ ptr->weak_this_ = *this;
+ }
+}
+
+#endif // UTIL_GTL_USE_STD_SHARED_PTR
+
+} // internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_STUBS_SHARED_PTR_H__
diff --git a/src/google/protobuf/stubs/singleton.h b/src/google/protobuf/stubs/singleton.h
new file mode 100644
index 00000000..9301f549
--- /dev/null
+++ b/src/google/protobuf/stubs/singleton.h
@@ -0,0 +1,68 @@
+// 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 <google/protobuf/stubs/atomicops.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<typename T>
+class Singleton {
+ public:
+ static T* get() {
+ GoogleOnceInit(&once_, &Singleton<T>::Init);
+ return instance_;
+ }
+ static void ShutDown() {
+ delete instance_;
+ instance_ = NULL;
+ }
+ private:
+ static void Init() {
+ instance_ = new T();
+ }
+ static ProtobufOnceType once_;
+ static T* instance_;
+};
+
+template<typename T>
+ProtobufOnceType Singleton<T>::once_;
+
+template<typename T>
+T* Singleton<T>::instance_ = NULL;
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_STUBS_SINGLETON_H__
diff --git a/src/google/protobuf/stubs/stl_util-inl.h b/src/google/protobuf/stubs/stl_util.h
index a2e671bb..9e4c82a4 100644
--- a/src/google/protobuf/stubs/stl_util-inl.h
+++ b/src/google/protobuf/stubs/stl_util.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -28,10 +28,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// from google3/util/gtl/stl_util-inl.h
+// from google3/util/gtl/stl_util.h
-#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
-#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
+#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
#include <google/protobuf/stubs/common.h>
@@ -118,4 +118,4 @@ void STLDeleteValues(T *v) {
} // namespace protobuf
} // namespace google
-#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
+#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
diff --git a/src/google/protobuf/stubs/stringprintf.cc b/src/google/protobuf/stubs/stringprintf.cc
new file mode 100644
index 00000000..3272d8e3
--- /dev/null
+++ b/src/google/protobuf/stubs/stringprintf.cc
@@ -0,0 +1,175 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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.
+
+// from google3/base/stringprintf.cc
+
+#include <google/protobuf/stubs/stringprintf.h>
+
+#include <errno.h>
+#include <stdarg.h> // For va_list and related operations
+#include <stdio.h> // MSVC requires this for _vsnprintf
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+
+namespace google {
+namespace protobuf {
+
+#ifdef _MSC_VER
+enum { IS_COMPILER_MSVC = 1 };
+#ifndef va_copy
+// Define va_copy for MSVC. This is a hack, assuming va_list is simply a
+// pointer into the stack and is safe to copy.
+#define va_copy(dest, src) ((dest) = (src))
+#endif
+#else
+enum { IS_COMPILER_MSVC = 0 };
+#endif
+
+void StringAppendV(string* dst, const char* format, va_list ap) {
+ // First try with a small fixed size buffer
+ static const int kSpaceLength = 1024;
+ char space[kSpaceLength];
+
+ // It's possible for methods that use a va_list to invalidate
+ // the data in it upon use. The fix is to make a copy
+ // of the structure before using it and use that copy instead.
+ va_list backup_ap;
+ va_copy(backup_ap, ap);
+ int result = vsnprintf(space, kSpaceLength, format, backup_ap);
+ va_end(backup_ap);
+
+ if (result < kSpaceLength) {
+ if (result >= 0) {
+ // Normal case -- everything fit.
+ dst->append(space, result);
+ return;
+ }
+
+ if (IS_COMPILER_MSVC) {
+ // Error or MSVC running out of space. MSVC 8.0 and higher
+ // can be asked about space needed with the special idiom below:
+ va_copy(backup_ap, ap);
+ result = vsnprintf(NULL, 0, format, backup_ap);
+ va_end(backup_ap);
+ }
+
+ if (result < 0) {
+ // Just an error.
+ return;
+ }
+ }
+
+ // Increase the buffer size to the size requested by vsnprintf,
+ // plus one for the closing \0.
+ int length = result+1;
+ char* buf = new char[length];
+
+ // Restore the va_list before we use it again
+ va_copy(backup_ap, ap);
+ result = vsnprintf(buf, length, format, backup_ap);
+ va_end(backup_ap);
+
+ if (result >= 0 && result < length) {
+ // It fit
+ dst->append(buf, result);
+ }
+ delete[] buf;
+}
+
+
+string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ string result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+const string& SStringPrintf(string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+
+void StringAppendF(string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+// Max arguments supported by StringPrintVector
+const int kStringPrintfVectorMaxArgs = 32;
+
+// An empty block of zero for filler arguments. This is const so that if
+// printf tries to write to it (via %n) then the program gets a SIGSEGV
+// and we can fix the problem or protect against an attack.
+static const char string_printf_empty_block[256] = { '\0' };
+
+string StringPrintfVector(const char* format, const vector<string>& v) {
+ GOOGLE_CHECK_LE(v.size(), kStringPrintfVectorMaxArgs)
+ << "StringPrintfVector currently only supports up to "
+ << kStringPrintfVectorMaxArgs << " arguments. "
+ << "Feel free to add support for more if you need it.";
+
+ // Add filler arguments so that bogus format+args have a harder time
+ // crashing the program, corrupting the program (%n),
+ // or displaying random chunks of memory to users.
+
+ const char* cstr[kStringPrintfVectorMaxArgs];
+ for (int i = 0; i < v.size(); ++i) {
+ cstr[i] = v[i].c_str();
+ }
+ for (int i = v.size(); i < GOOGLE_ARRAYSIZE(cstr); ++i) {
+ cstr[i] = &string_printf_empty_block[0];
+ }
+
+ // I do not know any way to pass kStringPrintfVectorMaxArgs arguments,
+ // or any way to build a va_list by hand, or any API for printf
+ // that accepts an array of arguments. The best I can do is stick
+ // this COMPILE_ASSERT right next to the actual statement.
+
+ GOOGLE_COMPILE_ASSERT(kStringPrintfVectorMaxArgs == 32, arg_count_mismatch);
+ return StringPrintf(format,
+ cstr[0], cstr[1], cstr[2], cstr[3], cstr[4],
+ cstr[5], cstr[6], cstr[7], cstr[8], cstr[9],
+ cstr[10], cstr[11], cstr[12], cstr[13], cstr[14],
+ cstr[15], cstr[16], cstr[17], cstr[18], cstr[19],
+ cstr[20], cstr[21], cstr[22], cstr[23], cstr[24],
+ cstr[25], cstr[26], cstr[27], cstr[28], cstr[29],
+ cstr[30], cstr[31]);
+}
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/stringprintf.h b/src/google/protobuf/stubs/stringprintf.h
new file mode 100644
index 00000000..ab1ab558
--- /dev/null
+++ b/src/google/protobuf/stubs/stringprintf.h
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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.
+
+// from google3/base/stringprintf.h
+//
+// Printf variants that place their output in a C++ string.
+//
+// Usage:
+// string result = StringPrintf("%d %s\n", 10, "hello");
+// SStringPrintf(&result, "%d %s\n", 10, "hello");
+// StringAppendF(&result, "%d %s\n", 20, "there");
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
+#define GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
+
+#include <stdarg.h>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+// Return a C++ string
+LIBPROTOBUF_EXPORT extern string StringPrintf(const char* format, ...);
+
+// Store result into a supplied string and return it
+LIBPROTOBUF_EXPORT extern const string& SStringPrintf(string* dst, const char* format, ...);
+
+// Append result to a supplied string
+LIBPROTOBUF_EXPORT extern void StringAppendF(string* dst, const char* format, ...);
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string. All other routines are just convenience wrappers around it.
+LIBPROTOBUF_EXPORT extern void StringAppendV(string* dst, const char* format, va_list ap);
+
+// The max arguments supported by StringPrintfVector
+LIBPROTOBUF_EXPORT extern const int kStringPrintfVectorMaxArgs;
+
+// You can use this version when all your arguments are strings, but
+// you don't know how many arguments you'll have at compile time.
+// StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs
+LIBPROTOBUF_EXPORT extern string StringPrintfVector(const char* format, const vector<string>& v);
+
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
diff --git a/src/google/protobuf/stubs/stringprintf_unittest.cc b/src/google/protobuf/stubs/stringprintf_unittest.cc
new file mode 100644
index 00000000..15895e59
--- /dev/null
+++ b/src/google/protobuf/stubs/stringprintf_unittest.cc
@@ -0,0 +1,152 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 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.
+
+// from google3/base/stringprintf_unittest.cc
+
+#include <google/protobuf/stubs/stringprintf.h>
+
+#include <cerrno>
+#include <string>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+TEST(StringPrintfTest, Empty) {
+#if 0
+ // gcc 2.95.3, gcc 4.1.0, and gcc 4.2.2 all warn about this:
+ // warning: zero-length printf format string.
+ // so we do not allow them in google3.
+ EXPECT_EQ("", StringPrintf(""));
+#endif
+ EXPECT_EQ("", StringPrintf("%s", string().c_str()));
+ EXPECT_EQ("", StringPrintf("%s", ""));
+}
+
+TEST(StringPrintfTest, Misc) {
+// MSVC and mingw does not support $ format specifier.
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+ EXPECT_EQ("123hello w", StringPrintf("%3$d%2$s %1$c", 'w', "hello", 123));
+#endif // !_MSC_VER
+}
+
+TEST(StringAppendFTest, Empty) {
+ string value("Hello");
+ const char* empty = "";
+ StringAppendF(&value, "%s", empty);
+ EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, EmptyString) {
+ string value("Hello");
+ StringAppendF(&value, "%s", "");
+ EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, String) {
+ string value("Hello");
+ StringAppendF(&value, " %s", "World");
+ EXPECT_EQ("Hello World", value);
+}
+
+TEST(StringAppendFTest, Int) {
+ string value("Hello");
+ StringAppendF(&value, " %d", 123);
+ EXPECT_EQ("Hello 123", value);
+}
+
+TEST(StringPrintfTest, Multibyte) {
+ // If we are in multibyte mode and feed invalid multibyte sequence,
+ // StringPrintf should return an empty string instead of running
+ // out of memory while trying to determine destination buffer size.
+ // see b/4194543.
+
+ char* old_locale = setlocale(LC_CTYPE, NULL);
+ // Push locale with multibyte mode
+ setlocale(LC_CTYPE, "en_US.utf8");
+
+ const char kInvalidCodePoint[] = "\375\067s";
+ string value = StringPrintf("%.*s", 3, kInvalidCodePoint);
+
+ // In some versions of glibc (e.g. eglibc-2.11.1, aka GRTEv2), snprintf
+ // returns error given an invalid codepoint. Other versions
+ // (e.g. eglibc-2.15, aka pre-GRTEv3) emit the codepoint verbatim.
+ // We test that the output is one of the above.
+ EXPECT_TRUE(value.empty() || value == kInvalidCodePoint);
+
+ // Repeat with longer string, to make sure that the dynamically
+ // allocated path in StringAppendV is handled correctly.
+ int n = 2048;
+ char* buf = new char[n+1];
+ memset(buf, ' ', n-3);
+ memcpy(buf + n - 3, kInvalidCodePoint, 4);
+ value = StringPrintf("%.*s", n, buf);
+ // See GRTEv2 vs. GRTEv3 comment above.
+ EXPECT_TRUE(value.empty() || value == buf);
+ delete[] buf;
+
+ setlocale(LC_CTYPE, old_locale);
+}
+
+TEST(StringPrintfTest, NoMultibyte) {
+ // No multibyte handling, but the string contains funny chars.
+ char* old_locale = setlocale(LC_CTYPE, NULL);
+ setlocale(LC_CTYPE, "POSIX");
+ string value = StringPrintf("%.*s", 3, "\375\067s");
+ setlocale(LC_CTYPE, old_locale);
+ EXPECT_EQ("\375\067s", value);
+}
+
+TEST(StringPrintfTest, DontOverwriteErrno) {
+ // Check that errno isn't overwritten unless we're printing
+ // something significantly larger than what people are normally
+ // printing in their badly written PLOG() statements.
+ errno = ECHILD;
+ string value = StringPrintf("Hello, %s!", "World");
+ EXPECT_EQ(ECHILD, errno);
+}
+
+TEST(StringPrintfTest, LargeBuf) {
+ // Check that the large buffer is handled correctly.
+ int n = 2048;
+ char* buf = new char[n+1];
+ memset(buf, ' ', n);
+ buf[n] = 0;
+ string value = StringPrintf("%s", buf);
+ EXPECT_EQ(buf, value);
+ delete[] buf;
+}
+
+} // anonymous namespace
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
index bb658ba8..7955d261 100644
--- a/src/google/protobuf/stubs/strutil.cc
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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,
@@ -189,6 +217,44 @@ void SplitStringUsing(const string& full,
SplitStringToIteratorUsing(full, delim, it);
}
+// Split a string using a character delimiter. Append the components
+// to 'result'. If there are consecutive delimiters, this function
+// will return corresponding empty strings. The string is split into
+// at most the specified number of pieces greedily. This means that the
+// last piece may possibly be split further. To split into as many pieces
+// as possible, specify 0 as the number of pieces.
+//
+// If "full" is the empty string, yields an empty string as the only value.
+//
+// If "pieces" is negative for some reason, it returns the whole string
+// ----------------------------------------------------------------------
+template <typename StringType, typename ITR>
+static inline
+void SplitStringToIteratorAllowEmpty(const StringType& full,
+ const char* delim,
+ int pieces,
+ ITR& result) {
+ string::size_type begin_index, end_index;
+ begin_index = 0;
+
+ for (int i = 0; (i < pieces-1) || (pieces == 0); i++) {
+ end_index = full.find_first_of(delim, begin_index);
+ if (end_index == string::npos) {
+ *result++ = full.substr(begin_index);
+ return;
+ }
+ *result++ = full.substr(begin_index, (end_index - begin_index));
+ begin_index = end_index + 1;
+ }
+ *result++ = full.substr(begin_index);
+}
+
+void SplitStringAllowEmpty(const string& full, const char* delim,
+ vector<string>* result) {
+ back_insert_iterator<vector<string> > it(*result);
+ SplitStringToIteratorAllowEmpty(full, delim, 0, it);
+}
+
// ----------------------------------------------------------------------
// JoinStrings()
// This merges a vector of string components with delim inserted
@@ -558,6 +624,120 @@ uint32 strtou32_adaptor(const char *nptr, char **endptr, int base) {
return static_cast<uint32>(result);
}
+inline bool safe_parse_sign(string* text /*inout*/,
+ bool* negative_ptr /*output*/) {
+ const char* start = text->data();
+ const char* end = start + text->size();
+
+ // Consume whitespace.
+ while (start < end && (start[0] == ' ')) {
+ ++start;
+ }
+ while (start < end && (end[-1] == ' ')) {
+ --end;
+ }
+ if (start >= end) {
+ return false;
+ }
+
+ // Consume sign.
+ *negative_ptr = (start[0] == '-');
+ if (*negative_ptr || start[0] == '+') {
+ ++start;
+ if (start >= end) {
+ return false;
+ }
+ }
+ *text = text->substr(start - text->data(), end - start);
+ return true;
+}
+
+inline bool safe_parse_positive_int(
+ string text, int32* value_p) {
+ int base = 10;
+ int32 value = 0;
+ const int32 vmax = std::numeric_limits<int32>::max();
+ assert(vmax > 0);
+ assert(vmax >= base);
+ const int32 vmax_over_base = vmax / base;
+ const char* start = text.data();
+ const char* end = start + text.size();
+ // loop over digits
+ for (; start < end; ++start) {
+ unsigned char c = static_cast<unsigned char>(start[0]);
+ int digit = c - '0';
+ if (digit >= base || digit < 0) {
+ *value_p = value;
+ return false;
+ }
+ if (value > vmax_over_base) {
+ *value_p = vmax;
+ return false;
+ }
+ value *= base;
+ if (value > vmax - digit) {
+ *value_p = vmax;
+ return false;
+ }
+ value += digit;
+ }
+ *value_p = value;
+ return true;
+}
+
+inline bool safe_parse_negative_int(
+ string text, int32* value_p) {
+ int base = 10;
+ int32 value = 0;
+ const int32 vmin = std::numeric_limits<int32>::min();
+ assert(vmin < 0);
+ assert(vmin <= 0 - base);
+ int32 vmin_over_base = vmin / base;
+ // 2003 c++ standard [expr.mul]
+ // "... the sign of the remainder is implementation-defined."
+ // Although (vmin/base)*base + vmin%base is always vmin.
+ // 2011 c++ standard tightens the spec but we cannot rely on it.
+ if (vmin % base > 0) {
+ vmin_over_base += 1;
+ }
+ const char* start = text.data();
+ const char* end = start + text.size();
+ // loop over digits
+ for (; start < end; ++start) {
+ unsigned char c = static_cast<unsigned char>(start[0]);
+ int digit = c - '0';
+ if (digit >= base || digit < 0) {
+ *value_p = value;
+ return false;
+ }
+ if (value < vmin_over_base) {
+ *value_p = vmin;
+ return false;
+ }
+ value *= base;
+ if (value < vmin + digit) {
+ *value_p = vmin;
+ return false;
+ }
+ value -= digit;
+ }
+ *value_p = value;
+ return true;
+}
+
+bool safe_int(string text, int32* value_p) {
+ *value_p = 0;
+ bool negative;
+ if (!safe_parse_sign(&text, &negative)) {
+ return false;
+ }
+ if (!negative) {
+ return safe_parse_positive_int(text, value_p);
+ } else {
+ return safe_parse_negative_int(text, value_p);
+ }
+}
+
// ----------------------------------------------------------------------
// FastIntToBuffer()
// FastInt64ToBuffer()
@@ -670,7 +850,14 @@ char *InternalFastHexToBuffer(uint64 value, char* buffer, int num_byte) {
static const char *hexdigits = "0123456789abcdef";
buffer[num_byte] = '\0';
for (int i = num_byte - 1; i >= 0; i--) {
+#ifdef _M_X64
+ // MSVC x64 platform has a bug optimizing the uint32(value) in the #else
+ // block. Given that the uint32 cast was to improve performance on 32-bit
+ // platforms, we use 64-bit '&' directly.
+ buffer[i] = hexdigits[value & 0xf];
+#else
buffer[i] = hexdigits[uint32(value) & 0xf];
+#endif
value >>= 4;
}
return buffer;
@@ -1098,69 +1285,256 @@ char* FloatToBuffer(float value, char* buffer) {
return buffer;
}
+string ToHex(uint64 num) {
+ if (num == 0) {
+ return string("0");
+ }
+
+ // Compute hex bytes in reverse order, writing to the back of the
+ // buffer.
+ char buf[16]; // No more than 16 hex digits needed.
+ char* bufptr = buf + 16;
+ static const char kHexChars[] = "0123456789abcdef";
+ while (num != 0) {
+ *--bufptr = kHexChars[num & 0xf];
+ num >>= 4;
+ }
+
+ return string(bufptr, buf + 16 - bufptr);
+}
+
+namespace strings {
+
+AlphaNum::AlphaNum(strings::Hex hex) {
+ char *const end = &digits[kFastToBufferSize];
+ char *writer = end;
+ uint64 value = hex.value;
+ uint64 width = hex.spec;
+ // We accomplish minimum width by OR'ing in 0x10000 to the user's value,
+ // where 0x10000 is the smallest hex number that is as wide as the user
+ // asked for.
+ uint64 mask = ((static_cast<uint64>(1) << (width - 1) * 4)) | value;
+ static const char hexdigits[] = "0123456789abcdef";
+ do {
+ *--writer = hexdigits[value & 0xF];
+ value >>= 4;
+ mask >>= 4;
+ } while (mask != 0);
+ piece_data_ = writer;
+ piece_size_ = end - writer;
+}
+
+} // namespace strings
+
// ----------------------------------------------------------------------
-// NoLocaleStrtod()
-// This code will make you cry.
+// StrCat()
+// This merges the given strings or integers, with no delimiter. This
+// is designed to be the fastest possible way to construct a string out
+// of a mix of raw C strings, C++ strings, and integer values.
// ----------------------------------------------------------------------
-// Returns a string identical to *input except that the character pointed to
-// by radix_pos (which should be '.') is replaced with the locale-specific
-// radix character.
-string LocalizeRadix(const char* input, const char* radix_pos) {
- // Determine the locale-specific radix character by calling sprintf() to
- // print the number 1.5, then stripping off the digits. As far as I can
- // tell, this is the only portable, thread-safe way to get the C library
- // to divuldge the locale's radix character. No, localeconv() is NOT
- // thread-safe.
- char temp[16];
- int size = sprintf(temp, "%.1f", 1.5);
- GOOGLE_CHECK_EQ(temp[0], '1');
- GOOGLE_CHECK_EQ(temp[size-1], '5');
- GOOGLE_CHECK_LE(size, 6);
-
- // Now replace the '.' in the input with it.
+// Append is merely a version of memcpy that returns the address of the byte
+// after the area just overwritten. It comes in multiple flavors to minimize
+// call overhead.
+static char *Append1(char *out, const AlphaNum &x) {
+ memcpy(out, x.data(), x.size());
+ return out + x.size();
+}
+
+static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) {
+ memcpy(out, x1.data(), x1.size());
+ out += x1.size();
+
+ memcpy(out, x2.data(), x2.size());
+ return out + x2.size();
+}
+
+static char *Append4(char *out,
+ const AlphaNum &x1, const AlphaNum &x2,
+ const AlphaNum &x3, const AlphaNum &x4) {
+ memcpy(out, x1.data(), x1.size());
+ out += x1.size();
+
+ memcpy(out, x2.data(), x2.size());
+ out += x2.size();
+
+ memcpy(out, x3.data(), x3.size());
+ out += x3.size();
+
+ memcpy(out, x4.data(), x4.size());
+ return out + x4.size();
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b) {
string result;
- result.reserve(strlen(input) + size - 3);
- result.append(input, radix_pos);
- result.append(temp + 1, size - 2);
- result.append(radix_pos + 1);
+ result.resize(a.size() + b.size());
+ char *const begin = &*result.begin();
+ char *out = Append2(begin, a, b);
+ GOOGLE_DCHECK_EQ(out, begin + result.size());
return result;
}
-double NoLocaleStrtod(const char* text, char** original_endptr) {
- // We cannot simply set the locale to "C" temporarily with setlocale()
- // as this is not thread-safe. Instead, we try to parse in the current
- // locale first. If parsing stops at a '.' character, then this is a
- // pretty good hint that we're actually in some other locale in which
- // '.' is not the radix character.
-
- char* temp_endptr;
- double result = strtod(text, &temp_endptr);
- if (original_endptr != NULL) *original_endptr = temp_endptr;
- if (*temp_endptr != '.') return result;
-
- // Parsing halted on a '.'. Perhaps we're in a different locale? Let's
- // try to replace the '.' with a locale-specific radix character and
- // try again.
- string localized = LocalizeRadix(text, temp_endptr);
- const char* localized_cstr = localized.c_str();
- char* localized_endptr;
- result = strtod(localized_cstr, &localized_endptr);
- if ((localized_endptr - localized_cstr) >
- (temp_endptr - text)) {
- // This attempt got further, so replacing the decimal must have helped.
- // Update original_endptr to point at the right location.
- if (original_endptr != NULL) {
- // size_diff is non-zero if the localized radix has multiple bytes.
- int size_diff = localized.size() - strlen(text);
- // const_cast is necessary to match the strtod() interface.
- *original_endptr = const_cast<char*>(
- text + (localized_endptr - localized_cstr - size_diff));
- }
- }
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
+ string result;
+ result.resize(a.size() + b.size() + c.size());
+ char *const begin = &*result.begin();
+ char *out = Append2(begin, a, b);
+ out = Append1(out, c);
+ GOOGLE_DCHECK_EQ(out, begin + result.size());
+ return result;
+}
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d) {
+ string result;
+ result.resize(a.size() + b.size() + c.size() + d.size());
+ char *const begin = &*result.begin();
+ char *out = Append4(begin, a, b, c, d);
+ GOOGLE_DCHECK_EQ(out, begin + result.size());
return result;
}
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e) {
+ string result;
+ result.resize(a.size() + b.size() + c.size() + d.size() + e.size());
+ char *const begin = &*result.begin();
+ char *out = Append4(begin, a, b, c, d);
+ out = Append1(out, e);
+ GOOGLE_DCHECK_EQ(out, begin + result.size());
+ return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e, const AlphaNum &f) {
+ string result;
+ result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+ f.size());
+ char *const begin = &*result.begin();
+ char *out = Append4(begin, a, b, c, d);
+ out = Append2(out, e, f);
+ GOOGLE_DCHECK_EQ(out, begin + result.size());
+ return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+ const AlphaNum &g) {
+ string result;
+ result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+ f.size() + g.size());
+ char *const begin = &*result.begin();
+ char *out = Append4(begin, a, b, c, d);
+ out = Append2(out, e, f);
+ out = Append1(out, g);
+ GOOGLE_DCHECK_EQ(out, begin + result.size());
+ return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+ const AlphaNum &g, const AlphaNum &h) {
+ string result;
+ result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+ f.size() + g.size() + h.size());
+ char *const begin = &*result.begin();
+ char *out = Append4(begin, a, b, c, d);
+ out = Append4(out, e, f, g, h);
+ GOOGLE_DCHECK_EQ(out, begin + result.size());
+ return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+ const AlphaNum &g, const AlphaNum &h, const AlphaNum &i) {
+ string result;
+ result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+ f.size() + g.size() + h.size() + i.size());
+ char *const begin = &*result.begin();
+ char *out = Append4(begin, a, b, c, d);
+ out = Append4(out, e, f, g, h);
+ out = Append1(out, i);
+ GOOGLE_DCHECK_EQ(out, begin + result.size());
+ return result;
+}
+
+// It's possible to call StrAppend with a char * pointer that is partway into
+// the string we're appending to. However the results of this are random.
+// Therefore, check for this in debug mode. Use unsigned math so we only have
+// to do one comparison.
+#define GOOGLE_DCHECK_NO_OVERLAP(dest, src) \
+ GOOGLE_DCHECK_GT(uintptr_t((src).data() - (dest).data()), \
+ uintptr_t((dest).size()))
+
+void StrAppend(string *result, const AlphaNum &a) {
+ GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+ result->append(a.data(), a.size());
+}
+
+void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b) {
+ GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+ GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+ string::size_type old_size = result->size();
+ result->resize(old_size + a.size() + b.size());
+ char *const begin = &*result->begin();
+ char *out = Append2(begin + old_size, a, b);
+ GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+void StrAppend(string *result,
+ const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
+ GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+ GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+ GOOGLE_DCHECK_NO_OVERLAP(*result, c);
+ string::size_type old_size = result->size();
+ result->resize(old_size + a.size() + b.size() + c.size());
+ char *const begin = &*result->begin();
+ char *out = Append2(begin + old_size, a, b);
+ out = Append1(out, c);
+ GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+void StrAppend(string *result,
+ const AlphaNum &a, const AlphaNum &b,
+ const AlphaNum &c, const AlphaNum &d) {
+ GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+ GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+ GOOGLE_DCHECK_NO_OVERLAP(*result, c);
+ GOOGLE_DCHECK_NO_OVERLAP(*result, d);
+ string::size_type old_size = result->size();
+ result->resize(old_size + a.size() + b.size() + c.size() + d.size());
+ char *const begin = &*result->begin();
+ char *out = Append4(begin + old_size, a, b, c, d);
+ GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+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 4a79c224..920701eb 100644
--- a/src/google/protobuf/stubs/strutil.h
+++ b/src/google/protobuf/stubs/strutil.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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,13 +125,19 @@ 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()
+// ToUpper()
// Convert the characters in "s" to lowercase or uppercase. ASCII-only:
// these functions intentionally ignore locale because they are applied to
// identifiers used in the Protocol Buffer language, not to natural-language
@@ -148,6 +160,12 @@ inline void UpperString(string * s) {
}
}
+inline string ToUpper(const string& s) {
+ string out = s;
+ UpperString(&out);
+ return out;
+}
+
// ----------------------------------------------------------------------
// StringReplace()
// Give me a string and two patterns "old" and "new", and I replace
@@ -168,6 +186,33 @@ LIBPROTOBUF_EXPORT string StringReplace(const string& s, const string& oldsub,
LIBPROTOBUF_EXPORT void SplitStringUsing(const string& full, const char* delim,
vector<string>* res);
+// Split a string using one or more byte delimiters, presented
+// as a nul-terminated c string. Append the components to 'result'.
+// If there are consecutive delimiters, this function will return
+// corresponding empty strings. If you want to drop the empty
+// strings, try SplitStringUsing().
+//
+// If "full" is the empty string, yields an empty string as the only value.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT void SplitStringAllowEmpty(const string& full,
+ const char* delim,
+ vector<string>* result);
+
+// ----------------------------------------------------------------------
+// Split()
+// Split a string using a character delimiter.
+// ----------------------------------------------------------------------
+inline vector<string> Split(
+ const string& full, const char* delim, bool skip_empty = true) {
+ vector<string> result;
+ if (skip_empty) {
+ SplitStringUsing(full, delim, &result);
+ } else {
+ SplitStringAllowEmpty(full, delim, &result);
+ }
+ return result;
+}
+
// ----------------------------------------------------------------------
// JoinStrings()
// These methods concatenate a vector of strings into a C++ string, using
@@ -315,6 +360,15 @@ inline uint64 strtou64(const char *nptr, char **endptr, int base) {
}
// ----------------------------------------------------------------------
+// safe_strto32()
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT bool safe_int(string text, int32* value_p);
+
+inline bool safe_strto32(string text, int32* value) {
+ return safe_int(text, value);
+}
+
+// ----------------------------------------------------------------------
// FastIntToBuffer()
// FastHexToBuffer()
// FastHex64ToBuffer()
@@ -441,17 +495,211 @@ LIBPROTOBUF_EXPORT char* FloatToBuffer(float i, char* buffer);
static const int kDoubleToBufferSize = 32;
static const int kFloatToBufferSize = 24;
+namespace strings {
+
+struct Hex {
+ uint64 value;
+ enum PadSpec {
+ NONE = 1,
+ ZERO_PAD_2,
+ ZERO_PAD_3,
+ ZERO_PAD_4,
+ ZERO_PAD_5,
+ ZERO_PAD_6,
+ ZERO_PAD_7,
+ ZERO_PAD_8,
+ ZERO_PAD_9,
+ ZERO_PAD_10,
+ ZERO_PAD_11,
+ ZERO_PAD_12,
+ ZERO_PAD_13,
+ ZERO_PAD_14,
+ ZERO_PAD_15,
+ ZERO_PAD_16,
+ } spec;
+ template <class Int>
+ explicit Hex(Int v, PadSpec s = NONE)
+ : spec(s) {
+ // Prevent sign-extension by casting integers to
+ // their unsigned counterparts.
+#ifdef LANG_CXX11
+ static_assert(
+ sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
+ "Unknown integer type");
+#endif
+ value = sizeof(v) == 1 ? static_cast<uint8>(v)
+ : sizeof(v) == 2 ? static_cast<uint16>(v)
+ : sizeof(v) == 4 ? static_cast<uint32>(v)
+ : static_cast<uint64>(v);
+ }
+};
+
+struct AlphaNum {
+ const char *piece_data_; // move these to string_ref eventually
+ size_t piece_size_; // move these to string_ref eventually
+
+ char digits[kFastToBufferSize];
+
+ // No bool ctor -- bools convert to an integral type.
+ // A bool ctor would also convert incoming pointers (bletch).
+
+ AlphaNum(int32 i32)
+ : piece_data_(digits),
+ piece_size_(FastInt32ToBufferLeft(i32, digits) - &digits[0]) {}
+ AlphaNum(uint32 u32)
+ : piece_data_(digits),
+ piece_size_(FastUInt32ToBufferLeft(u32, digits) - &digits[0]) {}
+ AlphaNum(int64 i64)
+ : piece_data_(digits),
+ piece_size_(FastInt64ToBufferLeft(i64, digits) - &digits[0]) {}
+ AlphaNum(uint64 u64)
+ : piece_data_(digits),
+ piece_size_(FastUInt64ToBufferLeft(u64, digits) - &digits[0]) {}
+
+ AlphaNum(float f)
+ : piece_data_(digits), piece_size_(strlen(FloatToBuffer(f, digits))) {}
+ AlphaNum(double f)
+ : piece_data_(digits), piece_size_(strlen(DoubleToBuffer(f, digits))) {}
+
+ AlphaNum(Hex hex);
+
+ AlphaNum(const char* c_str)
+ : piece_data_(c_str), piece_size_(strlen(c_str)) {}
+ // TODO: Add a string_ref constructor, eventually
+ // AlphaNum(const StringPiece &pc) : piece(pc) {}
+
+ AlphaNum(const string& str)
+ : piece_data_(str.data()), piece_size_(str.size()) {}
+
+ size_t size() const { return piece_size_; }
+ const char *data() const { return piece_data_; }
+
+ private:
+ // Use ":" not ':'
+ AlphaNum(char c); // NOLINT(runtime/explicit)
+
+ // Disallow copy and assign.
+ AlphaNum(const AlphaNum&);
+ void operator=(const AlphaNum&);
+};
+
+} // namespace strings
+
+using strings::AlphaNum;
+
// ----------------------------------------------------------------------
-// NoLocaleStrtod()
-// Exactly like strtod(), except it always behaves as if in the "C"
-// locale (i.e. decimal points must be '.'s).
+// StrCat()
+// This merges the given strings or numbers, with no delimiter. This
+// is designed to be the fastest possible way to construct a string out
+// of a mix of raw C strings, strings, bool values,
+// and numeric values.
+//
+// Don't use this for user-visible strings. The localization process
+// works poorly on strings built up out of fragments.
+//
+// For clarity and performance, don't use StrCat when appending to a
+// string. In particular, avoid using any of these (anti-)patterns:
+// str.append(StrCat(...)
+// str += StrCat(...)
+// str = StrCat(str, ...)
+// where the last is the worse, with the potential to change a loop
+// from a linear time operation with O(1) dynamic allocations into a
+// quadratic time operation with O(n) dynamic allocations. StrAppend
+// is a better choice than any of the above, subject to the restriction
+// of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may
+// be a reference into str.
+// ----------------------------------------------------------------------
+
+string StrCat(const AlphaNum &a, const AlphaNum &b);
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c);
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d);
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e);
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e, const AlphaNum &f);
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+ const AlphaNum &g);
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+ const AlphaNum &g, const AlphaNum &h);
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+ const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+ const AlphaNum &g, const AlphaNum &h, const AlphaNum &i);
+
+inline string StrCat(const AlphaNum& a) { return string(a.data(), a.size()); }
+
+// ----------------------------------------------------------------------
+// StrAppend()
+// Same as above, but adds the output to the given string.
+// WARNING: For speed, StrAppend does not try to check each of its input
+// arguments to be sure that they are not a subset of the string being
+// appended to. That is, while this will work:
+//
+// string s = "foo";
+// s += s;
+//
+// This will not (necessarily) work:
+//
+// string s = "foo";
+// StrAppend(&s, s);
+//
+// Note: while StrCat supports appending up to 9 arguments, StrAppend
+// is currently limited to 4. That's rarely an issue except when
+// automatically transforming StrCat to StrAppend, and can easily be
+// worked around as consecutive calls to StrAppend are quite efficient.
+// ----------------------------------------------------------------------
+
+void StrAppend(string* dest, const AlphaNum& a);
+void StrAppend(string* dest, const AlphaNum& a, const AlphaNum& b);
+void StrAppend(string* dest, const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c);
+void StrAppend(string* dest, const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c, const AlphaNum& d);
+
+// ----------------------------------------------------------------------
+// Join()
+// These methods concatenate a range of components into a C++ string, using
+// the C-string "delim" as a separator between components.
+// ----------------------------------------------------------------------
+template <typename Iterator>
+void Join(Iterator start, Iterator end,
+ const char* delim, string* result) {
+ for (Iterator it = start; it != end; ++it) {
+ if (it != start) {
+ result->append(delim);
+ }
+ StrAppend(result, *it);
+ }
+}
+
+template <typename Range>
+string Join(const Range& components,
+ const char* delim) {
+ string result;
+ Join(components.begin(), components.end(), delim, &result);
+ return result;
+}
+
+// ----------------------------------------------------------------------
+// ToHex()
+// Return a lower-case hex string representation of the given integer.
// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT string ToHex(uint64 num);
-LIBPROTOBUF_EXPORT double NoLocaleStrtod(const char* text, char** endptr);
+// ----------------------------------------------------------------------
+// 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
#endif // GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
-
-
diff --git a/src/google/protobuf/stubs/strutil_unittest.cc b/src/google/protobuf/stubs/strutil_unittest.cc
index b9c9253b..7f27dca0 100644
--- a/src/google/protobuf/stubs/strutil_unittest.cc
+++ b/src/google/protobuf/stubs/strutil_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -51,27 +51,17 @@ TEST(StringUtilityTest, ImmuneToLocales) {
// Set the locale to "C".
ASSERT_TRUE(setlocale(LC_NUMERIC, "C") != NULL);
- EXPECT_EQ(1.5, NoLocaleStrtod("1.5", NULL));
EXPECT_EQ("1.5", SimpleDtoa(1.5));
EXPECT_EQ("1.5", SimpleFtoa(1.5));
- // Verify that the endptr is set correctly even if not all text was parsed.
- const char* text = "1.5f";
- char* endptr;
- EXPECT_EQ(1.5, NoLocaleStrtod(text, &endptr));
- EXPECT_EQ(3, endptr - text);
-
if (setlocale(LC_NUMERIC, "es_ES") == NULL &&
setlocale(LC_NUMERIC, "es_ES.utf8") == NULL) {
// Some systems may not have the desired locale available.
GOOGLE_LOG(WARNING)
<< "Couldn't set locale to es_ES. Skipping this test.";
} else {
- EXPECT_EQ(1.5, NoLocaleStrtod("1.5", NULL));
EXPECT_EQ("1.5", SimpleDtoa(1.5));
EXPECT_EQ("1.5", SimpleFtoa(1.5));
- EXPECT_EQ(1.5, NoLocaleStrtod(text, &endptr));
- EXPECT_EQ(3, endptr - text);
}
// Return to original locale.
diff --git a/src/google/protobuf/stubs/substitute.cc b/src/google/protobuf/stubs/substitute.cc
index b542aaa4..c9d95899 100644
--- a/src/google/protobuf/stubs/substitute.cc
+++ b/src/google/protobuf/stubs/substitute.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,7 +32,7 @@
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/stubs/substitute.h b/src/google/protobuf/stubs/substitute.h
index 2581793b..7ee442af 100644
--- a/src/google/protobuf/stubs/substitute.h
+++ b/src/google/protobuf/stubs/substitute.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/stubs/template_util.h b/src/google/protobuf/stubs/template_util.h
new file mode 100644
index 00000000..feef904b
--- /dev/null
+++ b/src/google/protobuf/stubs/template_util.h
@@ -0,0 +1,138 @@
+// Copyright 2005 Google Inc.
+// All rights reserved.
+//
+// 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: lar@google.com (Laramie Leavitt)
+//
+// Template metaprogramming utility functions.
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems. Before making
+// any changes here, make sure that you're not breaking any platforms.
+//
+//
+// The names chosen here reflect those used in tr1 and the boost::mpl
+// library, there are similar operations used in the Loki library as
+// well. I prefer the boost names for 2 reasons:
+// 1. I think that portions of the Boost libraries are more likely to
+// be included in the c++ standard.
+// 2. It is not impossible that some of the boost libraries will be
+// included in our own build in the future.
+// Both of these outcomes means that we may be able to directly replace
+// some of these with boost equivalents.
+//
+#ifndef GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
+#define GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Types small_ and big_ are guaranteed such that sizeof(small_) <
+// sizeof(big_)
+typedef char small_;
+
+struct big_ {
+ char dummy[2];
+};
+
+// Identity metafunction.
+template <class T>
+struct identity_ {
+ typedef T type;
+};
+
+// integral_constant, defined in tr1, is a wrapper for an integer
+// value. We don't really need this generality; we could get away
+// with hardcoding the integer type to bool. We use the fully
+// general integer_constant for compatibility with tr1.
+
+template<class T, T v>
+struct integral_constant {
+ static const T value = v;
+ typedef T value_type;
+ typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+
+// Abbreviations: true_type and false_type are structs that represent boolean
+// true and false values. Also define the boost::mpl versions of those names,
+// true_ and false_.
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+typedef true_type true_;
+typedef false_type false_;
+
+// if_ is a templatized conditional statement.
+// if_<cond, A, B> is a compile time evaluation of cond.
+// if_<>::type contains A if cond is true, B otherwise.
+template<bool cond, typename A, typename B>
+struct if_{
+ typedef A type;
+};
+
+template<typename A, typename B>
+struct if_<false, A, B> {
+ typedef B type;
+};
+
+
+// type_equals_ is a template type comparator, similar to Loki IsSameType.
+// type_equals_<A, B>::value is true iff "A" is the same type as "B".
+//
+// New code should prefer base::is_same, defined in base/type_traits.h.
+// It is functionally identical, but is_same is the standard spelling.
+template<typename A, typename B>
+struct type_equals_ : public false_ {
+};
+
+template<typename A>
+struct type_equals_<A, A> : public true_ {
+};
+
+// and_ is a template && operator.
+// and_<A, B>::value evaluates "A::value && B::value".
+template<typename A, typename B>
+struct and_ : public integral_constant<bool, (A::value && B::value)> {
+};
+
+// or_ is a template || operator.
+// or_<A, B>::value evaluates "A::value || B::value".
+template<typename A, typename B>
+struct or_ : public integral_constant<bool, (A::value || B::value)> {
+};
+
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
diff --git a/src/google/protobuf/stubs/template_util_unittest.cc b/src/google/protobuf/stubs/template_util_unittest.cc
new file mode 100644
index 00000000..b1745e2b
--- /dev/null
+++ b/src/google/protobuf/stubs/template_util_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2005 Google Inc.
+// All rights reserved.
+//
+// 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: lar@google.com (Laramie Leavitt)
+//
+// These tests are really compile time tests.
+// If you try to step through this in a debugger
+// you will not see any evaluations, merely that
+// value is assigned true or false sequentially.
+
+#include <google/protobuf/stubs/template_util.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace GOOGLE_NAMESPACE = google::protobuf::internal;
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST(TemplateUtilTest, TestSize) {
+ EXPECT_GT(sizeof(GOOGLE_NAMESPACE::big_), sizeof(GOOGLE_NAMESPACE::small_));
+}
+
+TEST(TemplateUtilTest, TestIntegralConstants) {
+ // test the built-in types.
+ EXPECT_TRUE(true_type::value);
+ EXPECT_FALSE(false_type::value);
+
+ typedef integral_constant<int, 1> one_type;
+ EXPECT_EQ(1, one_type::value);
+}
+
+TEST(TemplateUtilTest, TestTemplateIf) {
+ typedef if_<true, true_type, false_type>::type if_true;
+ EXPECT_TRUE(if_true::value);
+
+ typedef if_<false, true_type, false_type>::type if_false;
+ EXPECT_FALSE(if_false::value);
+}
+
+TEST(TemplateUtilTest, TestTemplateTypeEquals) {
+ // Check that the TemplateTypeEquals works correctly.
+ bool value = false;
+
+ // Test the same type is true.
+ value = type_equals_<int, int>::value;
+ EXPECT_TRUE(value);
+
+ // Test different types are false.
+ value = type_equals_<float, int>::value;
+ EXPECT_FALSE(value);
+
+ // Test type aliasing.
+ typedef const int foo;
+ value = type_equals_<const foo, const int>::value;
+ EXPECT_TRUE(value);
+}
+
+TEST(TemplateUtilTest, TestTemplateAndOr) {
+ // Check that the TemplateTypeEquals works correctly.
+ bool value = false;
+
+ // Yes && Yes == true.
+ value = and_<true_, true_>::value;
+ EXPECT_TRUE(value);
+ // Yes && No == false.
+ value = and_<true_, false_>::value;
+ EXPECT_FALSE(value);
+ // No && Yes == false.
+ value = and_<false_, true_>::value;
+ EXPECT_FALSE(value);
+ // No && No == false.
+ value = and_<false_, false_>::value;
+ EXPECT_FALSE(value);
+
+ // Yes || Yes == true.
+ value = or_<true_, true_>::value;
+ EXPECT_TRUE(value);
+ // Yes || No == true.
+ value = or_<true_, false_>::value;
+ EXPECT_TRUE(value);
+ // No || Yes == true.
+ value = or_<false_, true_>::value;
+ EXPECT_TRUE(value);
+ // No || No == false.
+ value = or_<false_, false_>::value;
+ EXPECT_FALSE(value);
+}
+
+TEST(TemplateUtilTest, TestIdentity) {
+ EXPECT_TRUE(
+ (type_equals_<GOOGLE_NAMESPACE::identity_<int>::type, int>::value));
+ EXPECT_TRUE(
+ (type_equals_<GOOGLE_NAMESPACE::identity_<void>::type, void>::value));
+}
+
+} // anonymous namespace
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/type_traits.h b/src/google/protobuf/stubs/type_traits.h
new file mode 100644
index 00000000..b58cae3f
--- /dev/null
+++ b/src/google/protobuf/stubs/type_traits.h
@@ -0,0 +1,360 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// 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: Matt Austern
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems. Before making
+// 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
+// is_enum
+// is_reference
+// is_pod
+// has_trivial_constructor
+// has_trivial_copy
+// has_trivial_assign
+// has_trivial_destructor
+// remove_const
+// remove_volatile
+// remove_cv
+// remove_reference
+// add_reference
+// remove_pointer
+// is_same
+// is_convertible
+// We can add more type traits as required.
+
+#ifndef GOOGLE_PROTOBUF_TYPE_TRAITS_H_
+#define GOOGLE_PROTOBUF_TYPE_TRAITS_H_
+
+#include <utility> // For pair
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/template_util.h> // For true_type and false_type
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+template<typename B, typename D>
+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<const D*>(NULL))) == sizeof(yes),
+ };
+};
+
+template <bool cond, class T = void> struct enable_if;
+template <class T> struct is_integral;
+template <class T> struct is_floating_point;
+template <class T> struct is_pointer;
+// MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least)
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+// is_enum uses is_convertible, which is not available on MSVC.
+template <class T> struct is_enum;
+#endif
+template <class T> struct is_reference;
+template <class T> struct is_pod;
+template <class T> struct has_trivial_constructor;
+template <class T> struct has_trivial_copy;
+template <class T> struct has_trivial_assign;
+template <class T> struct has_trivial_destructor;
+template <class T> struct remove_const;
+template <class T> struct remove_volatile;
+template <class T> struct remove_cv;
+template <class T> struct remove_reference;
+template <class T> struct add_reference;
+template <class T> struct remove_pointer;
+template <class T, class U> struct is_same;
+#if !(defined(__GNUC__) && __GNUC__ <= 3)
+template <class From, class To> 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<bool cond, class T> struct enable_if { typedef T type; };
+template<class T> struct enable_if<false, T> {};
+// 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 <class T> struct is_integral : false_type { };
+template<> struct is_integral<bool> : true_type { };
+template<> struct is_integral<char> : true_type { };
+template<> struct is_integral<unsigned char> : true_type { };
+template<> struct is_integral<signed char> : true_type { };
+#if defined(_MSC_VER)
+// wchar_t is not by default a distinct type from unsigned short in
+// Microsoft C.
+// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx
+template<> struct is_integral<__wchar_t> : true_type { };
+#else
+template<> struct is_integral<wchar_t> : true_type { };
+#endif
+template<> struct is_integral<short> : true_type { };
+template<> struct is_integral<unsigned short> : true_type { };
+template<> struct is_integral<int> : true_type { };
+template<> struct is_integral<unsigned int> : true_type { };
+template<> struct is_integral<long> : true_type { };
+template<> struct is_integral<unsigned long> : true_type { };
+#ifdef HAVE_LONG_LONG
+template<> struct is_integral<long long> : true_type { };
+template<> struct is_integral<unsigned long long> : true_type { };
+#endif
+template <class T> struct is_integral<const T> : is_integral<T> { };
+template <class T> struct is_integral<volatile T> : is_integral<T> { };
+template <class T> struct is_integral<const volatile T> : is_integral<T> { };
+
+// is_floating_point is false except for the built-in floating-point types.
+// A cv-qualified type is integral if and only if the underlying type is.
+template <class T> struct is_floating_point : false_type { };
+template<> struct is_floating_point<float> : true_type { };
+template<> struct is_floating_point<double> : true_type { };
+template<> struct is_floating_point<long double> : true_type { };
+template <class T> struct is_floating_point<const T>
+ : is_floating_point<T> { };
+template <class T> struct is_floating_point<volatile T>
+ : is_floating_point<T> { };
+template <class T> struct is_floating_point<const volatile T>
+ : is_floating_point<T> { };
+
+// is_pointer is false except for pointer types. A cv-qualified type (e.g.
+// "int* const", as opposed to "int const*") is cv-qualified if and only if
+// the underlying type is.
+template <class T> struct is_pointer : false_type { };
+template <class T> struct is_pointer<T*> : true_type { };
+template <class T> struct is_pointer<const T> : is_pointer<T> { };
+template <class T> struct is_pointer<volatile T> : is_pointer<T> { };
+template <class T> struct is_pointer<const volatile T> : is_pointer<T> { };
+
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+
+namespace type_traits_internal {
+
+template <class T> struct is_class_or_union {
+ template <class U> static small_ tester(void (U::*)());
+ template <class U> static big_ tester(...);
+ static const bool value = sizeof(tester<T>(0)) == sizeof(small_);
+};
+
+// is_convertible chokes if the first argument is an array. That's why
+// we use add_reference here.
+template <bool NotUnum, class T> struct is_enum_impl
+ : is_convertible<typename add_reference<T>::type, int> { };
+
+template <class T> struct is_enum_impl<true, T> : false_type { };
+
+} // namespace type_traits_internal
+
+// Specified by TR1 [4.5.1] primary type categories.
+
+// Implementation note:
+//
+// Each type is either void, integral, floating point, array, pointer,
+// reference, member object pointer, member function pointer, enum,
+// union or class. Out of these, only integral, floating point, reference,
+// class and enum types are potentially convertible to int. Therefore,
+// if a type is not a reference, integral, floating point or class and
+// is convertible to int, it's a enum. Adding cv-qualification to a type
+// does not change whether it's an enum.
+//
+// Is-convertible-to-int check is done only if all other checks pass,
+// because it can't be used with some types (e.g. void or classes with
+// inaccessible conversion operators).
+template <class T> struct is_enum
+ : type_traits_internal::is_enum_impl<
+ is_same<T, void>::value ||
+ is_integral<T>::value ||
+ is_floating_point<T>::value ||
+ is_reference<T>::value ||
+ type_traits_internal::is_class_or_union<T>::value,
+ T> { };
+
+template <class T> struct is_enum<const T> : is_enum<T> { };
+template <class T> struct is_enum<volatile T> : is_enum<T> { };
+template <class T> struct is_enum<const volatile T> : is_enum<T> { };
+
+#endif
+
+// is_reference is false except for reference types.
+template<typename T> struct is_reference : false_type {};
+template<typename T> struct is_reference<T&> : true_type {};
+
+
+// We can't get is_pod right without compiler help, so fail conservatively.
+// We will assume it's false except for arithmetic types, enumerations,
+// pointers and cv-qualified versions thereof. Note that std::pair<T,U>
+// is not a POD even if T and U are PODs.
+template <class T> struct is_pod
+ : integral_constant<bool, (is_integral<T>::value ||
+ is_floating_point<T>::value ||
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+ // is_enum is not available on MSVC.
+ is_enum<T>::value ||
+#endif
+ is_pointer<T>::value)> { };
+template <class T> struct is_pod<const T> : is_pod<T> { };
+template <class T> struct is_pod<volatile T> : is_pod<T> { };
+template <class T> struct is_pod<const volatile T> : is_pod<T> { };
+
+
+// We can't get has_trivial_constructor right without compiler help, so
+// fail conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial
+// constructors. (3) array of a type with a trivial constructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_constructor : is_pod<T> { };
+template <class T, class U> struct has_trivial_constructor<std::pair<T, U> >
+ : integral_constant<bool,
+ (has_trivial_constructor<T>::value &&
+ has_trivial_constructor<U>::value)> { };
+template <class A, int N> struct has_trivial_constructor<A[N]>
+ : has_trivial_constructor<A> { };
+template <class T> struct has_trivial_constructor<const T>
+ : has_trivial_constructor<T> { };
+
+// We can't get has_trivial_copy right without compiler help, so fail
+// conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial copy
+// constructors. (3) array of a type with a trivial copy constructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_copy : is_pod<T> { };
+template <class T, class U> struct has_trivial_copy<std::pair<T, U> >
+ : integral_constant<bool,
+ (has_trivial_copy<T>::value &&
+ has_trivial_copy<U>::value)> { };
+template <class A, int N> struct has_trivial_copy<A[N]>
+ : has_trivial_copy<A> { };
+template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { };
+
+// We can't get has_trivial_assign right without compiler help, so fail
+// conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial copy
+// constructors. (3) array of a type with a trivial assign constructor.
+template <class T> struct has_trivial_assign : is_pod<T> { };
+template <class T, class U> struct has_trivial_assign<std::pair<T, U> >
+ : integral_constant<bool,
+ (has_trivial_assign<T>::value &&
+ has_trivial_assign<U>::value)> { };
+template <class A, int N> struct has_trivial_assign<A[N]>
+ : has_trivial_assign<A> { };
+
+// We can't get has_trivial_destructor right without compiler help, so
+// fail conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial
+// destructors. (3) array of a type with a trivial destructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_destructor : is_pod<T> { };
+template <class T, class U> struct has_trivial_destructor<std::pair<T, U> >
+ : integral_constant<bool,
+ (has_trivial_destructor<T>::value &&
+ has_trivial_destructor<U>::value)> { };
+template <class A, int N> struct has_trivial_destructor<A[N]>
+ : has_trivial_destructor<A> { };
+template <class T> struct has_trivial_destructor<const T>
+ : has_trivial_destructor<T> { };
+
+// Specified by TR1 [4.7.1]
+template<typename T> struct remove_const { typedef T type; };
+template<typename T> struct remove_const<T const> { typedef T type; };
+template<typename T> struct remove_volatile { typedef T type; };
+template<typename T> struct remove_volatile<T volatile> { typedef T type; };
+template<typename T> struct remove_cv {
+ typedef typename remove_const<typename remove_volatile<T>::type>::type type;
+};
+
+
+// Specified by TR1 [4.7.2] Reference modifications.
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+
+template <typename T> struct add_reference { typedef T& type; };
+template <typename T> struct add_reference<T&> { typedef T& type; };
+
+// Specified by TR1 [4.7.4] Pointer modifications.
+template<typename T> struct remove_pointer { typedef T type; };
+template<typename T> struct remove_pointer<T*> { typedef T type; };
+template<typename T> struct remove_pointer<T* const> { typedef T type; };
+template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
+template<typename T> struct remove_pointer<T* const volatile> {
+ typedef T type; };
+
+// Specified by TR1 [4.6] Relationships between types
+template<typename T, typename U> struct is_same : public false_type { };
+template<typename T> struct is_same<T, T> : public true_type { };
+
+// Specified by TR1 [4.6] Relationships between types
+#if !(defined(__GNUC__) && __GNUC__ <= 3)
+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
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From. See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+template <typename From, typename To>
+struct ConvertHelper {
+ static small_ Test(To);
+ static big_ Test(...);
+ static From Create();
+ enum {
+ value = sizeof(Test(Create())) == sizeof(small_)
+ };
+};
+} // namespace type_traits_internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+template <typename From, typename To>
+struct is_convertible
+ : integral_constant<bool,
+ type_traits_internal::ConvertHelper<From, To>::value> {
+};
+#endif
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_TYPE_TRAITS_H_
diff --git a/src/google/protobuf/stubs/type_traits_unittest.cc b/src/google/protobuf/stubs/type_traits_unittest.cc
new file mode 100644
index 00000000..49c10ace
--- /dev/null
+++ b/src/google/protobuf/stubs/type_traits_unittest.cc
@@ -0,0 +1,631 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// 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: Matt Austern
+
+#include <google/protobuf/stubs/type_traits.h>
+
+#include <stdlib.h> // for exit()
+#include <stdio.h>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+typedef int int32;
+// IBM AIX typedefs `int64` in `sys/inttypes.h`, included transitively above.
+#ifndef _AIX
+typedef long int64;
+#endif
+
+using std::string;
+using std::vector;
+using std::pair;
+
+
+// This assertion produces errors like "error: invalid use of
+// incomplete type 'struct <unnamed>::AssertTypesEq<const int, int>'"
+// when it fails.
+template<typename T, typename U> struct AssertTypesEq;
+template<typename T> struct AssertTypesEq<T, T> {};
+#define COMPILE_ASSERT_TYPES_EQ(T, U) static_cast<void>(AssertTypesEq<T, U>())
+
+// A user-defined POD type.
+struct A {
+ int n_;
+};
+
+// A user-defined non-POD type with a trivial copy constructor.
+class B {
+ public:
+ explicit B(int n) : n_(n) { }
+ private:
+ int n_;
+};
+
+// Another user-defined non-POD type with a trivial copy constructor.
+// We will explicitly declare C to have a trivial copy constructor
+// by specializing has_trivial_copy.
+class C {
+ public:
+ explicit C(int n) : n_(n) { }
+ private:
+ int n_;
+};
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<> struct has_trivial_copy<C> : true_type { };
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+// Another user-defined non-POD type with a trivial assignment operator.
+// We will explicitly declare C to have a trivial assignment operator
+// by specializing has_trivial_assign.
+class D {
+ public:
+ explicit D(int n) : n_(n) { }
+ private:
+ int n_;
+};
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<> struct has_trivial_assign<D> : true_type { };
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+// Another user-defined non-POD type with a trivial constructor.
+// We will explicitly declare E to have a trivial constructor
+// by specializing has_trivial_constructor.
+class E {
+ public:
+ int n_;
+};
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<> struct has_trivial_constructor<E> : true_type { };
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+// Another user-defined non-POD type with a trivial destructor.
+// We will explicitly declare E to have a trivial destructor
+// by specializing has_trivial_destructor.
+class F {
+ public:
+ explicit F(int n) : n_(n) { }
+ private:
+ int n_;
+};
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<> struct has_trivial_destructor<F> : true_type { };
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+enum G {};
+
+union H {};
+
+class I {
+ public:
+ operator int() const;
+};
+
+class J {
+ private:
+ operator int() const;
+};
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+// A base class and a derived class that inherits from it, used for
+// testing conversion type traits.
+class Base {
+ public:
+ virtual ~Base() { }
+};
+
+class Derived : public Base {
+};
+
+TEST(TypeTraitsTest, TestIsInteger) {
+ // Verify that is_integral is true for all integer types.
+ EXPECT_TRUE(is_integral<bool>::value);
+ EXPECT_TRUE(is_integral<char>::value);
+ EXPECT_TRUE(is_integral<unsigned char>::value);
+ EXPECT_TRUE(is_integral<signed char>::value);
+ EXPECT_TRUE(is_integral<wchar_t>::value);
+ EXPECT_TRUE(is_integral<int>::value);
+ EXPECT_TRUE(is_integral<unsigned int>::value);
+ EXPECT_TRUE(is_integral<short>::value);
+ EXPECT_TRUE(is_integral<unsigned short>::value);
+ EXPECT_TRUE(is_integral<long>::value);
+ EXPECT_TRUE(is_integral<unsigned long>::value);
+
+ // Verify that is_integral is false for a few non-integer types.
+ EXPECT_FALSE(is_integral<void>::value);
+ EXPECT_FALSE(is_integral<float>::value);
+ EXPECT_FALSE(is_integral<string>::value);
+ EXPECT_FALSE(is_integral<int*>::value);
+ EXPECT_FALSE(is_integral<A>::value);
+ EXPECT_FALSE((is_integral<pair<int, int> >::value));
+
+ // Verify that cv-qualified integral types are still integral, and
+ // cv-qualified non-integral types are still non-integral.
+ EXPECT_TRUE(is_integral<const char>::value);
+ EXPECT_TRUE(is_integral<volatile bool>::value);
+ EXPECT_TRUE(is_integral<const volatile unsigned int>::value);
+ EXPECT_FALSE(is_integral<const float>::value);
+ EXPECT_FALSE(is_integral<int* volatile>::value);
+ EXPECT_FALSE(is_integral<const volatile string>::value);
+}
+
+TEST(TypeTraitsTest, TestIsFloating) {
+ // Verify that is_floating_point is true for all floating-point types.
+ EXPECT_TRUE(is_floating_point<float>::value);
+ EXPECT_TRUE(is_floating_point<double>::value);
+ EXPECT_TRUE(is_floating_point<long double>::value);
+
+ // Verify that is_floating_point is false for a few non-float types.
+ EXPECT_FALSE(is_floating_point<void>::value);
+ EXPECT_FALSE(is_floating_point<long>::value);
+ EXPECT_FALSE(is_floating_point<string>::value);
+ EXPECT_FALSE(is_floating_point<float*>::value);
+ EXPECT_FALSE(is_floating_point<A>::value);
+ EXPECT_FALSE((is_floating_point<pair<int, int> >::value));
+
+ // Verify that cv-qualified floating point types are still floating, and
+ // cv-qualified non-floating types are still non-floating.
+ EXPECT_TRUE(is_floating_point<const float>::value);
+ EXPECT_TRUE(is_floating_point<volatile double>::value);
+ EXPECT_TRUE(is_floating_point<const volatile long double>::value);
+ EXPECT_FALSE(is_floating_point<const int>::value);
+ EXPECT_FALSE(is_floating_point<volatile string>::value);
+ EXPECT_FALSE(is_floating_point<const volatile char>::value);
+}
+
+TEST(TypeTraitsTest, TestIsPointer) {
+ // Verify that is_pointer is true for some pointer types.
+ EXPECT_TRUE(is_pointer<int*>::value);
+ EXPECT_TRUE(is_pointer<void*>::value);
+ EXPECT_TRUE(is_pointer<string*>::value);
+ EXPECT_TRUE(is_pointer<const void*>::value);
+ EXPECT_TRUE(is_pointer<volatile float* const*>::value);
+
+ // Verify that is_pointer is false for some non-pointer types.
+ EXPECT_FALSE(is_pointer<void>::value);
+ EXPECT_FALSE(is_pointer<float&>::value);
+ EXPECT_FALSE(is_pointer<long>::value);
+ EXPECT_FALSE(is_pointer<vector<int*> >::value);
+ EXPECT_FALSE(is_pointer<int[5]>::value);
+
+ // A function pointer is a pointer, but a function type, or a function
+ // reference type, is not.
+ EXPECT_TRUE(is_pointer<int (*)(int x)>::value);
+ EXPECT_FALSE(is_pointer<void(char x)>::value);
+ EXPECT_FALSE(is_pointer<double (&)(string x)>::value);
+
+ // Verify that is_pointer<T> is true for some cv-qualified pointer types,
+ // and false for some cv-qualified non-pointer types.
+ EXPECT_TRUE(is_pointer<int* const>::value);
+ EXPECT_TRUE(is_pointer<const void* volatile>::value);
+ EXPECT_TRUE(is_pointer<char** const volatile>::value);
+ EXPECT_FALSE(is_pointer<const int>::value);
+ EXPECT_FALSE(is_pointer<volatile vector<int*> >::value);
+ EXPECT_FALSE(is_pointer<const volatile double>::value);
+}
+
+TEST(TypeTraitsTest, TestIsEnum) {
+// is_enum isn't supported on MSVC or gcc 3.x
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+ // Verify that is_enum is true for enum types.
+ EXPECT_TRUE(is_enum<G>::value);
+ EXPECT_TRUE(is_enum<const G>::value);
+ EXPECT_TRUE(is_enum<volatile G>::value);
+ EXPECT_TRUE(is_enum<const volatile G>::value);
+
+ // Verify that is_enum is false for a few non-enum types.
+ EXPECT_FALSE(is_enum<void>::value);
+ EXPECT_FALSE(is_enum<G&>::value);
+ EXPECT_FALSE(is_enum<G[1]>::value);
+ EXPECT_FALSE(is_enum<const G[1]>::value);
+ EXPECT_FALSE(is_enum<G[]>::value);
+ EXPECT_FALSE(is_enum<int>::value);
+ EXPECT_FALSE(is_enum<float>::value);
+ EXPECT_FALSE(is_enum<A>::value);
+ EXPECT_FALSE(is_enum<A*>::value);
+ EXPECT_FALSE(is_enum<const A>::value);
+ EXPECT_FALSE(is_enum<H>::value);
+ EXPECT_FALSE(is_enum<I>::value);
+ EXPECT_FALSE(is_enum<J>::value);
+ EXPECT_FALSE(is_enum<void()>::value);
+ EXPECT_FALSE(is_enum<void(*)()>::value);
+ EXPECT_FALSE(is_enum<int A::*>::value);
+ EXPECT_FALSE(is_enum<void (A::*)()>::value);
+#endif
+}
+
+TEST(TypeTraitsTest, TestIsReference) {
+ // Verifies that is_reference is true for all reference types.
+ typedef float& RefFloat;
+ EXPECT_TRUE(is_reference<float&>::value);
+ EXPECT_TRUE(is_reference<const int&>::value);
+ EXPECT_TRUE(is_reference<const int*&>::value);
+ EXPECT_TRUE(is_reference<int (&)(bool)>::value);
+ EXPECT_TRUE(is_reference<RefFloat>::value);
+ EXPECT_TRUE(is_reference<const RefFloat>::value);
+ EXPECT_TRUE(is_reference<volatile RefFloat>::value);
+ EXPECT_TRUE(is_reference<const volatile RefFloat>::value);
+
+
+ // Verifies that is_reference is false for all non-reference types.
+ EXPECT_FALSE(is_reference<float>::value);
+ EXPECT_FALSE(is_reference<const float>::value);
+ EXPECT_FALSE(is_reference<volatile float>::value);
+ EXPECT_FALSE(is_reference<const volatile float>::value);
+ EXPECT_FALSE(is_reference<const int*>::value);
+ EXPECT_FALSE(is_reference<int()>::value);
+ EXPECT_FALSE(is_reference<void(*)(const char&)>::value);
+}
+
+TEST(TypeTraitsTest, TestAddReference) {
+ COMPILE_ASSERT_TYPES_EQ(int&, add_reference<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int&, add_reference<const int>::type);
+ COMPILE_ASSERT_TYPES_EQ(volatile int&,
+ add_reference<volatile int>::type);
+ COMPILE_ASSERT_TYPES_EQ(const volatile int&,
+ add_reference<const volatile int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int&, add_reference<int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int&, add_reference<const int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(volatile int&,
+ add_reference<volatile int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(const volatile int&,
+ add_reference<const volatile int&>::type);
+}
+
+TEST(TypeTraitsTest, TestIsPod) {
+ // Verify that arithmetic types and pointers are marked as PODs.
+ EXPECT_TRUE(is_pod<bool>::value);
+ EXPECT_TRUE(is_pod<char>::value);
+ EXPECT_TRUE(is_pod<unsigned char>::value);
+ EXPECT_TRUE(is_pod<signed char>::value);
+ EXPECT_TRUE(is_pod<wchar_t>::value);
+ EXPECT_TRUE(is_pod<int>::value);
+ EXPECT_TRUE(is_pod<unsigned int>::value);
+ EXPECT_TRUE(is_pod<short>::value);
+ EXPECT_TRUE(is_pod<unsigned short>::value);
+ EXPECT_TRUE(is_pod<long>::value);
+ EXPECT_TRUE(is_pod<unsigned long>::value);
+ EXPECT_TRUE(is_pod<float>::value);
+ EXPECT_TRUE(is_pod<double>::value);
+ EXPECT_TRUE(is_pod<long double>::value);
+ EXPECT_TRUE(is_pod<string*>::value);
+ EXPECT_TRUE(is_pod<A*>::value);
+ EXPECT_TRUE(is_pod<const B*>::value);
+ EXPECT_TRUE(is_pod<C**>::value);
+ EXPECT_TRUE(is_pod<const int>::value);
+ EXPECT_TRUE(is_pod<char* volatile>::value);
+ EXPECT_TRUE(is_pod<const volatile double>::value);
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+ EXPECT_TRUE(is_pod<G>::value);
+ EXPECT_TRUE(is_pod<const G>::value);
+ EXPECT_TRUE(is_pod<volatile G>::value);
+ EXPECT_TRUE(is_pod<const volatile G>::value);
+#endif
+
+ // Verify that some non-POD types are not marked as PODs.
+ EXPECT_FALSE(is_pod<void>::value);
+ EXPECT_FALSE(is_pod<string>::value);
+ EXPECT_FALSE((is_pod<pair<int, int> >::value));
+ EXPECT_FALSE(is_pod<A>::value);
+ EXPECT_FALSE(is_pod<B>::value);
+ EXPECT_FALSE(is_pod<C>::value);
+ EXPECT_FALSE(is_pod<const string>::value);
+ EXPECT_FALSE(is_pod<volatile A>::value);
+ EXPECT_FALSE(is_pod<const volatile B>::value);
+}
+
+TEST(TypeTraitsTest, TestHasTrivialConstructor) {
+ // Verify that arithmetic types and pointers have trivial constructors.
+ EXPECT_TRUE(has_trivial_constructor<bool>::value);
+ EXPECT_TRUE(has_trivial_constructor<char>::value);
+ EXPECT_TRUE(has_trivial_constructor<unsigned char>::value);
+ EXPECT_TRUE(has_trivial_constructor<signed char>::value);
+ EXPECT_TRUE(has_trivial_constructor<wchar_t>::value);
+ EXPECT_TRUE(has_trivial_constructor<int>::value);
+ EXPECT_TRUE(has_trivial_constructor<unsigned int>::value);
+ EXPECT_TRUE(has_trivial_constructor<short>::value);
+ EXPECT_TRUE(has_trivial_constructor<unsigned short>::value);
+ EXPECT_TRUE(has_trivial_constructor<long>::value);
+ EXPECT_TRUE(has_trivial_constructor<unsigned long>::value);
+ EXPECT_TRUE(has_trivial_constructor<float>::value);
+ EXPECT_TRUE(has_trivial_constructor<double>::value);
+ EXPECT_TRUE(has_trivial_constructor<long double>::value);
+ EXPECT_TRUE(has_trivial_constructor<string*>::value);
+ EXPECT_TRUE(has_trivial_constructor<A*>::value);
+ EXPECT_TRUE(has_trivial_constructor<const B*>::value);
+ EXPECT_TRUE(has_trivial_constructor<C**>::value);
+
+ // Verify that pairs and arrays of such types have trivial
+ // constructors.
+ typedef int int10[10];
+ EXPECT_TRUE((has_trivial_constructor<pair<int, char*> >::value));
+ EXPECT_TRUE(has_trivial_constructor<int10>::value);
+
+ // Verify that pairs of types without trivial constructors
+ // are not marked as trivial.
+ EXPECT_FALSE((has_trivial_constructor<pair<int, string> >::value));
+ EXPECT_FALSE((has_trivial_constructor<pair<string, int> >::value));
+
+ // Verify that types without trivial constructors are
+ // correctly marked as such.
+ EXPECT_FALSE(has_trivial_constructor<string>::value);
+ EXPECT_FALSE(has_trivial_constructor<vector<int> >::value);
+
+ // Verify that E, which we have declared to have a trivial
+ // constructor, is correctly marked as such.
+ EXPECT_TRUE(has_trivial_constructor<E>::value);
+}
+
+TEST(TypeTraitsTest, TestHasTrivialCopy) {
+ // Verify that arithmetic types and pointers have trivial copy
+ // constructors.
+ EXPECT_TRUE(has_trivial_copy<bool>::value);
+ EXPECT_TRUE(has_trivial_copy<char>::value);
+ EXPECT_TRUE(has_trivial_copy<unsigned char>::value);
+ EXPECT_TRUE(has_trivial_copy<signed char>::value);
+ EXPECT_TRUE(has_trivial_copy<wchar_t>::value);
+ EXPECT_TRUE(has_trivial_copy<int>::value);
+ EXPECT_TRUE(has_trivial_copy<unsigned int>::value);
+ EXPECT_TRUE(has_trivial_copy<short>::value);
+ EXPECT_TRUE(has_trivial_copy<unsigned short>::value);
+ EXPECT_TRUE(has_trivial_copy<long>::value);
+ EXPECT_TRUE(has_trivial_copy<unsigned long>::value);
+ EXPECT_TRUE(has_trivial_copy<float>::value);
+ EXPECT_TRUE(has_trivial_copy<double>::value);
+ EXPECT_TRUE(has_trivial_copy<long double>::value);
+ EXPECT_TRUE(has_trivial_copy<string*>::value);
+ EXPECT_TRUE(has_trivial_copy<A*>::value);
+ EXPECT_TRUE(has_trivial_copy<const B*>::value);
+ EXPECT_TRUE(has_trivial_copy<C**>::value);
+
+ // Verify that pairs and arrays of such types have trivial
+ // copy constructors.
+ typedef int int10[10];
+ EXPECT_TRUE((has_trivial_copy<pair<int, char*> >::value));
+ EXPECT_TRUE(has_trivial_copy<int10>::value);
+
+ // Verify that pairs of types without trivial copy constructors
+ // are not marked as trivial.
+ EXPECT_FALSE((has_trivial_copy<pair<int, string> >::value));
+ EXPECT_FALSE((has_trivial_copy<pair<string, int> >::value));
+
+ // Verify that types without trivial copy constructors are
+ // correctly marked as such.
+ EXPECT_FALSE(has_trivial_copy<string>::value);
+ EXPECT_FALSE(has_trivial_copy<vector<int> >::value);
+
+ // Verify that C, which we have declared to have a trivial
+ // copy constructor, is correctly marked as such.
+ EXPECT_TRUE(has_trivial_copy<C>::value);
+}
+
+TEST(TypeTraitsTest, TestHasTrivialAssign) {
+ // Verify that arithmetic types and pointers have trivial assignment
+ // operators.
+ EXPECT_TRUE(has_trivial_assign<bool>::value);
+ EXPECT_TRUE(has_trivial_assign<char>::value);
+ EXPECT_TRUE(has_trivial_assign<unsigned char>::value);
+ EXPECT_TRUE(has_trivial_assign<signed char>::value);
+ EXPECT_TRUE(has_trivial_assign<wchar_t>::value);
+ EXPECT_TRUE(has_trivial_assign<int>::value);
+ EXPECT_TRUE(has_trivial_assign<unsigned int>::value);
+ EXPECT_TRUE(has_trivial_assign<short>::value);
+ EXPECT_TRUE(has_trivial_assign<unsigned short>::value);
+ EXPECT_TRUE(has_trivial_assign<long>::value);
+ EXPECT_TRUE(has_trivial_assign<unsigned long>::value);
+ EXPECT_TRUE(has_trivial_assign<float>::value);
+ EXPECT_TRUE(has_trivial_assign<double>::value);
+ EXPECT_TRUE(has_trivial_assign<long double>::value);
+ EXPECT_TRUE(has_trivial_assign<string*>::value);
+ EXPECT_TRUE(has_trivial_assign<A*>::value);
+ EXPECT_TRUE(has_trivial_assign<const B*>::value);
+ EXPECT_TRUE(has_trivial_assign<C**>::value);
+
+ // Verify that pairs and arrays of such types have trivial
+ // assignment operators.
+ typedef int int10[10];
+ EXPECT_TRUE((has_trivial_assign<pair<int, char*> >::value));
+ EXPECT_TRUE(has_trivial_assign<int10>::value);
+
+ // Verify that pairs of types without trivial assignment operators
+ // are not marked as trivial.
+ EXPECT_FALSE((has_trivial_assign<pair<int, string> >::value));
+ EXPECT_FALSE((has_trivial_assign<pair<string, int> >::value));
+
+ // Verify that types without trivial assignment operators are
+ // correctly marked as such.
+ EXPECT_FALSE(has_trivial_assign<string>::value);
+ EXPECT_FALSE(has_trivial_assign<vector<int> >::value);
+
+ // Verify that D, which we have declared to have a trivial
+ // assignment operator, is correctly marked as such.
+ EXPECT_TRUE(has_trivial_assign<D>::value);
+}
+
+TEST(TypeTraitsTest, TestHasTrivialDestructor) {
+ // Verify that arithmetic types and pointers have trivial destructors.
+ EXPECT_TRUE(has_trivial_destructor<bool>::value);
+ EXPECT_TRUE(has_trivial_destructor<char>::value);
+ EXPECT_TRUE(has_trivial_destructor<unsigned char>::value);
+ EXPECT_TRUE(has_trivial_destructor<signed char>::value);
+ EXPECT_TRUE(has_trivial_destructor<wchar_t>::value);
+ EXPECT_TRUE(has_trivial_destructor<int>::value);
+ EXPECT_TRUE(has_trivial_destructor<unsigned int>::value);
+ EXPECT_TRUE(has_trivial_destructor<short>::value);
+ EXPECT_TRUE(has_trivial_destructor<unsigned short>::value);
+ EXPECT_TRUE(has_trivial_destructor<long>::value);
+ EXPECT_TRUE(has_trivial_destructor<unsigned long>::value);
+ EXPECT_TRUE(has_trivial_destructor<float>::value);
+ EXPECT_TRUE(has_trivial_destructor<double>::value);
+ EXPECT_TRUE(has_trivial_destructor<long double>::value);
+ EXPECT_TRUE(has_trivial_destructor<string*>::value);
+ EXPECT_TRUE(has_trivial_destructor<A*>::value);
+ EXPECT_TRUE(has_trivial_destructor<const B*>::value);
+ EXPECT_TRUE(has_trivial_destructor<C**>::value);
+
+ // Verify that pairs and arrays of such types have trivial
+ // destructors.
+ typedef int int10[10];
+ EXPECT_TRUE((has_trivial_destructor<pair<int, char*> >::value));
+ EXPECT_TRUE(has_trivial_destructor<int10>::value);
+
+ // Verify that pairs of types without trivial destructors
+ // are not marked as trivial.
+ EXPECT_FALSE((has_trivial_destructor<pair<int, string> >::value));
+ EXPECT_FALSE((has_trivial_destructor<pair<string, int> >::value));
+
+ // Verify that types without trivial destructors are
+ // correctly marked as such.
+ EXPECT_FALSE(has_trivial_destructor<string>::value);
+ EXPECT_FALSE(has_trivial_destructor<vector<int> >::value);
+
+ // Verify that F, which we have declared to have a trivial
+ // destructor, is correctly marked as such.
+ EXPECT_TRUE(has_trivial_destructor<F>::value);
+}
+
+// Tests remove_pointer.
+TEST(TypeTraitsTest, TestRemovePointer) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int*>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int, remove_pointer<const int*>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int* const>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int* volatile>::type);
+}
+
+TEST(TypeTraitsTest, TestRemoveConst) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_const<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_const<const int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int *, remove_const<int * const>::type);
+ // TR1 examples.
+ COMPILE_ASSERT_TYPES_EQ(const int *, remove_const<const int *>::type);
+ COMPILE_ASSERT_TYPES_EQ(volatile int,
+ remove_const<const volatile int>::type);
+}
+
+TEST(TypeTraitsTest, TestRemoveVolatile) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_volatile<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_volatile<volatile int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int *, remove_volatile<int * volatile>::type);
+ // TR1 examples.
+ COMPILE_ASSERT_TYPES_EQ(volatile int *,
+ remove_volatile<volatile int *>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int,
+ remove_volatile<const volatile int>::type);
+}
+
+TEST(TypeTraitsTest, TestRemoveCV) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_cv<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_cv<volatile int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_cv<const int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int *, remove_cv<int * const volatile>::type);
+ // TR1 examples.
+ COMPILE_ASSERT_TYPES_EQ(const volatile int *,
+ remove_cv<const volatile int *>::type);
+ COMPILE_ASSERT_TYPES_EQ(int,
+ remove_cv<const volatile int>::type);
+}
+
+TEST(TypeTraitsTest, TestRemoveReference) {
+ COMPILE_ASSERT_TYPES_EQ(int, remove_reference<int>::type);
+ COMPILE_ASSERT_TYPES_EQ(int, remove_reference<int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(const int, remove_reference<const int&>::type);
+ COMPILE_ASSERT_TYPES_EQ(int*, remove_reference<int * &>::type);
+}
+
+TEST(TypeTraitsTest, TestIsSame) {
+ EXPECT_TRUE((is_same<int32, int32>::value));
+ EXPECT_FALSE((is_same<int32, int64>::value));
+ EXPECT_FALSE((is_same<int64, int32>::value));
+ EXPECT_FALSE((is_same<int, const int>::value));
+
+ EXPECT_TRUE((is_same<void, void>::value));
+ EXPECT_FALSE((is_same<void, int>::value));
+ EXPECT_FALSE((is_same<int, void>::value));
+
+ EXPECT_TRUE((is_same<int*, int*>::value));
+ EXPECT_TRUE((is_same<void*, void*>::value));
+ EXPECT_FALSE((is_same<int*, void*>::value));
+ EXPECT_FALSE((is_same<void*, int*>::value));
+ EXPECT_FALSE((is_same<void*, const void*>::value));
+ EXPECT_FALSE((is_same<void*, void* const>::value));
+
+ EXPECT_TRUE((is_same<Base*, Base*>::value));
+ EXPECT_TRUE((is_same<Derived*, Derived*>::value));
+ EXPECT_FALSE((is_same<Base*, Derived*>::value));
+ EXPECT_FALSE((is_same<Derived*, Base*>::value));
+}
+
+TEST(TypeTraitsTest, TestConvertible) {
+#if !(defined(__GNUC__) && __GNUC__ <= 3)
+ EXPECT_TRUE((is_convertible<int, int>::value));
+ EXPECT_TRUE((is_convertible<int, long>::value));
+ EXPECT_TRUE((is_convertible<long, int>::value));
+
+ EXPECT_TRUE((is_convertible<int*, void*>::value));
+ EXPECT_FALSE((is_convertible<void*, int*>::value));
+
+ EXPECT_TRUE((is_convertible<Derived*, Base*>::value));
+ EXPECT_FALSE((is_convertible<Base*, Derived*>::value));
+ EXPECT_TRUE((is_convertible<Derived*, const Base*>::value));
+ EXPECT_FALSE((is_convertible<const Derived*, Base*>::value));
+#endif
+}
+
+} // anonymous namespace
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc
index af8b3909..be1c90e0 100644
--- a/src/google/protobuf/test_util.cc
+++ b/src/google/protobuf/test_util.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -50,6 +50,14 @@ namespace google {
namespace protobuf {
void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
+ SetOptionalFields(message);
+ AddRepeatedFields1(message);
+ AddRepeatedFields2(message);
+ SetDefaultFields(message);
+ SetOneofFields(message);
+}
+
+void TestUtil::SetOptionalFields(unittest::TestAllTypes* message) {
message->set_optional_int32 (101);
message->set_optional_int64 (102);
message->set_optional_uint32 (103);
@@ -66,10 +74,12 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->set_optional_string ("115");
message->set_optional_bytes ("116");
- message->mutable_optionalgroup ()->set_a(117);
- message->mutable_optional_nested_message ()->set_bb(118);
- message->mutable_optional_foreign_message()->set_c(119);
- message->mutable_optional_import_message ()->set_d(120);
+ message->mutable_optionalgroup ()->set_a(117);
+ message->mutable_optional_nested_message ()->set_bb(118);
+ message->mutable_optional_foreign_message ()->set_c(119);
+ message->mutable_optional_import_message ()->set_d(120);
+ message->mutable_optional_public_import_message()->set_e(126);
+ message->mutable_optional_lazy_message ()->set_bb(127);
message->set_optional_nested_enum (unittest::TestAllTypes::BAZ);
message->set_optional_foreign_enum(unittest::FOREIGN_BAZ );
@@ -87,9 +97,11 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->GetDescriptor()->FindFieldByName("optional_cord"),
"125");
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
- // -----------------------------------------------------------------
+// -------------------------------------------------------------------
+void TestUtil::AddRepeatedFields1(unittest::TestAllTypes* message) {
message->add_repeated_int32 (201);
message->add_repeated_int64 (202);
message->add_repeated_uint32 (203);
@@ -110,6 +122,7 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->add_repeated_nested_message ()->set_bb(218);
message->add_repeated_foreign_message()->set_c(219);
message->add_repeated_import_message ()->set_d(220);
+ message->add_repeated_lazy_message ()->set_bb(227);
message->add_repeated_nested_enum (unittest::TestAllTypes::BAR);
message->add_repeated_foreign_enum(unittest::FOREIGN_BAR );
@@ -125,7 +138,9 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->GetDescriptor()->FindFieldByName("repeated_cord"),
"225");
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
+void TestUtil::AddRepeatedFields2(unittest::TestAllTypes* message) {
// Add a second one of each field.
message->add_repeated_int32 (301);
message->add_repeated_int64 (302);
@@ -147,6 +162,7 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->add_repeated_nested_message ()->set_bb(318);
message->add_repeated_foreign_message()->set_c(319);
message->add_repeated_import_message ()->set_d(320);
+ message->add_repeated_lazy_message ()->set_bb(327);
message->add_repeated_nested_enum (unittest::TestAllTypes::BAZ);
message->add_repeated_foreign_enum(unittest::FOREIGN_BAZ );
@@ -162,9 +178,11 @@ void TestUtil::SetAllFields(unittest::TestAllTypes* message) {
message->GetDescriptor()->FindFieldByName("repeated_cord"),
"325");
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
- // -----------------------------------------------------------------
+// -------------------------------------------------------------------
+void TestUtil::SetDefaultFields(unittest::TestAllTypes* message) {
message->set_default_int32 (401);
message->set_default_int64 (402);
message->set_default_uint32 (403);
@@ -220,6 +238,7 @@ void TestUtil::ModifyRepeatedFields(unittest::TestAllTypes* message) {
message->mutable_repeated_nested_message (1)->set_bb(518);
message->mutable_repeated_foreign_message(1)->set_c(519);
message->mutable_repeated_import_message (1)->set_d(520);
+ message->mutable_repeated_lazy_message (1)->set_bb(527);
message->set_repeated_nested_enum (1, unittest::TestAllTypes::FOO);
message->set_repeated_foreign_enum(1, unittest::FOREIGN_FOO );
@@ -237,6 +256,14 @@ void TestUtil::ModifyRepeatedFields(unittest::TestAllTypes* message) {
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
}
+// ------------------------------------------------------------------
+void TestUtil::SetOneofFields(unittest::TestAllTypes* message) {
+ message->set_oneof_uint32(601);
+ message->mutable_oneof_nested_message()->set_bb(602);
+ message->set_oneof_string("603");
+ message->set_oneof_bytes("604");
+}
+
// -------------------------------------------------------------------
void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
@@ -256,15 +283,19 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_TRUE(message.has_optional_string ());
EXPECT_TRUE(message.has_optional_bytes ());
- EXPECT_TRUE(message.has_optionalgroup ());
- EXPECT_TRUE(message.has_optional_nested_message ());
- EXPECT_TRUE(message.has_optional_foreign_message());
- EXPECT_TRUE(message.has_optional_import_message ());
+ EXPECT_TRUE(message.has_optionalgroup ());
+ EXPECT_TRUE(message.has_optional_nested_message ());
+ EXPECT_TRUE(message.has_optional_foreign_message ());
+ EXPECT_TRUE(message.has_optional_import_message ());
+ EXPECT_TRUE(message.has_optional_public_import_message());
+ EXPECT_TRUE(message.has_optional_lazy_message ());
- EXPECT_TRUE(message.optionalgroup ().has_a());
- EXPECT_TRUE(message.optional_nested_message ().has_bb());
- EXPECT_TRUE(message.optional_foreign_message().has_c());
- EXPECT_TRUE(message.optional_import_message ().has_d());
+ EXPECT_TRUE(message.optionalgroup ().has_a());
+ EXPECT_TRUE(message.optional_nested_message ().has_bb());
+ EXPECT_TRUE(message.optional_foreign_message ().has_c());
+ EXPECT_TRUE(message.optional_import_message ().has_d());
+ EXPECT_TRUE(message.optional_public_import_message().has_e());
+ EXPECT_TRUE(message.optional_lazy_message ().has_bb());
EXPECT_TRUE(message.has_optional_nested_enum ());
EXPECT_TRUE(message.has_optional_foreign_enum());
@@ -287,14 +318,16 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ(110 , message.optional_sfixed64());
EXPECT_EQ(111 , message.optional_float ());
EXPECT_EQ(112 , message.optional_double ());
- EXPECT_EQ(true , message.optional_bool ());
+ EXPECT_TRUE( message.optional_bool ());
EXPECT_EQ("115", message.optional_string ());
EXPECT_EQ("116", message.optional_bytes ());
- EXPECT_EQ(117, message.optionalgroup ().a());
- EXPECT_EQ(118, message.optional_nested_message ().bb());
- EXPECT_EQ(119, message.optional_foreign_message().c());
- EXPECT_EQ(120, message.optional_import_message ().d());
+ EXPECT_EQ(117, message.optionalgroup ().a());
+ EXPECT_EQ(118, message.optional_nested_message ().bb());
+ EXPECT_EQ(119, message.optional_foreign_message ().c());
+ EXPECT_EQ(120, message.optional_import_message ().d());
+ EXPECT_EQ(126, message.optional_public_import_message ().e());
+ EXPECT_EQ(127, message.optional_lazy_message ().bb());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.optional_nested_enum ());
EXPECT_EQ(unittest::FOREIGN_BAZ , message.optional_foreign_enum());
@@ -323,6 +356,7 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_lazy_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -344,7 +378,7 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ(210 , message.repeated_sfixed64(0));
EXPECT_EQ(211 , message.repeated_float (0));
EXPECT_EQ(212 , message.repeated_double (0));
- EXPECT_EQ(true , message.repeated_bool (0));
+ EXPECT_TRUE( message.repeated_bool (0));
EXPECT_EQ("215", message.repeated_string (0));
EXPECT_EQ("216", message.repeated_bytes (0));
@@ -352,6 +386,7 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(227, message.repeated_lazy_message (0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (0));
@@ -370,7 +405,7 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ(310 , message.repeated_sfixed64(1));
EXPECT_EQ(311 , message.repeated_float (1));
EXPECT_EQ(312 , message.repeated_double (1));
- EXPECT_EQ(false, message.repeated_bool (1));
+ EXPECT_FALSE( message.repeated_bool (1));
EXPECT_EQ("315", message.repeated_string (1));
EXPECT_EQ("316", message.repeated_bytes (1));
@@ -378,6 +413,7 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ(318, message.repeated_nested_message (1).bb());
EXPECT_EQ(319, message.repeated_foreign_message(1).c());
EXPECT_EQ(320, message.repeated_import_message (1).d());
+ EXPECT_EQ(327, message.repeated_lazy_message (1).bb());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_BAZ , message.repeated_foreign_enum(1));
@@ -419,7 +455,7 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ(410 , message.default_sfixed64());
EXPECT_EQ(411 , message.default_float ());
EXPECT_EQ(412 , message.default_double ());
- EXPECT_EQ(false, message.default_bool ());
+ EXPECT_FALSE( message.default_bool ());
EXPECT_EQ("415", message.default_string ());
EXPECT_EQ("416", message.default_bytes ());
@@ -427,6 +463,13 @@ void TestUtil::ExpectAllFieldsSet(const unittest::TestAllTypes& message) {
EXPECT_EQ(unittest::FOREIGN_FOO , message.default_foreign_enum());
EXPECT_EQ(unittest_import::IMPORT_FOO, message.default_import_enum ());
+
+ EXPECT_FALSE(message.has_oneof_uint32 ());
+ EXPECT_FALSE(message.has_oneof_nested_message());
+ EXPECT_FALSE(message.has_oneof_string ());
+ EXPECT_TRUE(message.has_oneof_bytes ());
+
+ EXPECT_EQ("604", message.oneof_bytes());
}
// -------------------------------------------------------------------
@@ -449,10 +492,12 @@ void TestUtil::ExpectClear(const unittest::TestAllTypes& message) {
EXPECT_FALSE(message.has_optional_string ());
EXPECT_FALSE(message.has_optional_bytes ());
- EXPECT_FALSE(message.has_optionalgroup ());
- EXPECT_FALSE(message.has_optional_nested_message ());
- EXPECT_FALSE(message.has_optional_foreign_message());
- EXPECT_FALSE(message.has_optional_import_message ());
+ EXPECT_FALSE(message.has_optionalgroup ());
+ EXPECT_FALSE(message.has_optional_nested_message ());
+ EXPECT_FALSE(message.has_optional_foreign_message ());
+ EXPECT_FALSE(message.has_optional_import_message ());
+ EXPECT_FALSE(message.has_optional_public_import_message());
+ EXPECT_FALSE(message.has_optional_lazy_message ());
EXPECT_FALSE(message.has_optional_nested_enum ());
EXPECT_FALSE(message.has_optional_foreign_enum());
@@ -474,20 +519,24 @@ void TestUtil::ExpectClear(const unittest::TestAllTypes& message) {
EXPECT_EQ(0 , message.optional_sfixed64());
EXPECT_EQ(0 , message.optional_float ());
EXPECT_EQ(0 , message.optional_double ());
- EXPECT_EQ(false, message.optional_bool ());
+ EXPECT_FALSE( message.optional_bool ());
EXPECT_EQ("" , message.optional_string ());
EXPECT_EQ("" , message.optional_bytes ());
// Embedded messages should also be clear.
- EXPECT_FALSE(message.optionalgroup ().has_a());
- EXPECT_FALSE(message.optional_nested_message ().has_bb());
- EXPECT_FALSE(message.optional_foreign_message().has_c());
- EXPECT_FALSE(message.optional_import_message ().has_d());
-
- EXPECT_EQ(0, message.optionalgroup ().a());
- EXPECT_EQ(0, message.optional_nested_message ().bb());
- EXPECT_EQ(0, message.optional_foreign_message().c());
- EXPECT_EQ(0, message.optional_import_message ().d());
+ EXPECT_FALSE(message.optionalgroup ().has_a());
+ EXPECT_FALSE(message.optional_nested_message ().has_bb());
+ EXPECT_FALSE(message.optional_foreign_message ().has_c());
+ EXPECT_FALSE(message.optional_import_message ().has_d());
+ EXPECT_FALSE(message.optional_public_import_message().has_e());
+ EXPECT_FALSE(message.optional_lazy_message ().has_bb());
+
+ EXPECT_EQ(0, message.optionalgroup ().a());
+ EXPECT_EQ(0, message.optional_nested_message ().bb());
+ EXPECT_EQ(0, message.optional_foreign_message ().c());
+ EXPECT_EQ(0, message.optional_import_message ().d());
+ EXPECT_EQ(0, message.optional_public_import_message().e());
+ EXPECT_EQ(0, message.optional_lazy_message ().bb());
// Enums without defaults are set to the first value in the enum.
EXPECT_EQ(unittest::TestAllTypes::FOO, message.optional_nested_enum ());
@@ -516,6 +565,7 @@ void TestUtil::ExpectClear(const unittest::TestAllTypes& message) {
EXPECT_EQ(0, message.repeated_nested_message_size ());
EXPECT_EQ(0, message.repeated_foreign_message_size());
EXPECT_EQ(0, message.repeated_import_message_size ());
+ EXPECT_EQ(0, message.repeated_lazy_message_size ());
EXPECT_EQ(0, message.repeated_nested_enum_size ());
EXPECT_EQ(0, message.repeated_foreign_enum_size ());
EXPECT_EQ(0, message.repeated_import_enum_size ());
@@ -558,7 +608,7 @@ void TestUtil::ExpectClear(const unittest::TestAllTypes& message) {
EXPECT_EQ(-50 , message.default_sfixed64());
EXPECT_EQ( 51.5 , message.default_float ());
EXPECT_EQ( 52e3 , message.default_double ());
- EXPECT_EQ(true , message.default_bool ());
+ EXPECT_TRUE( message.default_bool ());
EXPECT_EQ("hello", message.default_string ());
EXPECT_EQ("world", message.default_bytes ());
@@ -566,6 +616,11 @@ void TestUtil::ExpectClear(const unittest::TestAllTypes& message) {
EXPECT_EQ(unittest::FOREIGN_BAR , message.default_foreign_enum());
EXPECT_EQ(unittest_import::IMPORT_BAR, message.default_import_enum ());
+
+ EXPECT_FALSE(message.has_oneof_uint32 ());
+ EXPECT_FALSE(message.has_oneof_nested_message());
+ EXPECT_FALSE(message.has_oneof_string ());
+ EXPECT_FALSE(message.has_oneof_bytes ());
}
// -------------------------------------------------------------------
@@ -595,6 +650,7 @@ void TestUtil::ExpectRepeatedFieldsModified(
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_lazy_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -616,7 +672,7 @@ void TestUtil::ExpectRepeatedFieldsModified(
EXPECT_EQ(210 , message.repeated_sfixed64(0));
EXPECT_EQ(211 , message.repeated_float (0));
EXPECT_EQ(212 , message.repeated_double (0));
- EXPECT_EQ(true , message.repeated_bool (0));
+ EXPECT_TRUE( message.repeated_bool (0));
EXPECT_EQ("215", message.repeated_string (0));
EXPECT_EQ("216", message.repeated_bytes (0));
@@ -624,6 +680,7 @@ void TestUtil::ExpectRepeatedFieldsModified(
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(227, message.repeated_lazy_message (0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.repeated_foreign_enum(0));
@@ -643,7 +700,7 @@ void TestUtil::ExpectRepeatedFieldsModified(
EXPECT_EQ(510 , message.repeated_sfixed64(1));
EXPECT_EQ(511 , message.repeated_float (1));
EXPECT_EQ(512 , message.repeated_double (1));
- EXPECT_EQ(true , message.repeated_bool (1));
+ EXPECT_TRUE( message.repeated_bool (1));
EXPECT_EQ("515", message.repeated_string (1));
EXPECT_EQ("516", message.repeated_bytes (1));
@@ -651,6 +708,7 @@ void TestUtil::ExpectRepeatedFieldsModified(
EXPECT_EQ(518, message.repeated_nested_message (1).bb());
EXPECT_EQ(519, message.repeated_foreign_message(1).c());
EXPECT_EQ(520, message.repeated_import_message (1).d());
+ EXPECT_EQ(527, message.repeated_lazy_message (1).bb());
EXPECT_EQ(unittest::TestAllTypes::FOO, message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_FOO , message.repeated_foreign_enum(1));
@@ -775,7 +833,7 @@ void TestUtil::ExpectPackedFieldsSet(const unittest::TestPackedTypes& message) {
EXPECT_EQ(610 , message.packed_sfixed64(0));
EXPECT_EQ(611 , message.packed_float (0));
EXPECT_EQ(612 , message.packed_double (0));
- EXPECT_EQ(true , message.packed_bool (0));
+ EXPECT_TRUE( message.packed_bool (0));
EXPECT_EQ(unittest::FOREIGN_BAR, message.packed_enum(0));
EXPECT_EQ(701 , message.packed_int32 (1));
@@ -790,7 +848,7 @@ void TestUtil::ExpectPackedFieldsSet(const unittest::TestPackedTypes& message) {
EXPECT_EQ(710 , message.packed_sfixed64(1));
EXPECT_EQ(711 , message.packed_float (1));
EXPECT_EQ(712 , message.packed_double (1));
- EXPECT_EQ(false, message.packed_bool (1));
+ EXPECT_FALSE( message.packed_bool (1));
EXPECT_EQ(unittest::FOREIGN_BAZ, message.packed_enum(1));
}
@@ -825,7 +883,7 @@ void TestUtil::ExpectUnpackedFieldsSet(
EXPECT_EQ(610 , message.unpacked_sfixed64(0));
EXPECT_EQ(611 , message.unpacked_float (0));
EXPECT_EQ(612 , message.unpacked_double (0));
- EXPECT_EQ(true , message.unpacked_bool (0));
+ EXPECT_TRUE( message.unpacked_bool (0));
EXPECT_EQ(unittest::FOREIGN_BAR, message.unpacked_enum(0));
EXPECT_EQ(701 , message.unpacked_int32 (1));
@@ -840,7 +898,7 @@ void TestUtil::ExpectUnpackedFieldsSet(
EXPECT_EQ(710 , message.unpacked_sfixed64(1));
EXPECT_EQ(711 , message.unpacked_float (1));
EXPECT_EQ(712 , message.unpacked_double (1));
- EXPECT_EQ(false, message.unpacked_bool (1));
+ EXPECT_FALSE( message.unpacked_bool (1));
EXPECT_EQ(unittest::FOREIGN_BAZ, message.unpacked_enum(1));
}
@@ -897,7 +955,7 @@ void TestUtil::ExpectPackedFieldsModified(
EXPECT_EQ(610 , message.packed_sfixed64(0));
EXPECT_EQ(611 , message.packed_float (0));
EXPECT_EQ(612 , message.packed_double (0));
- EXPECT_EQ(true , message.packed_bool (0));
+ EXPECT_TRUE( message.packed_bool (0));
EXPECT_EQ(unittest::FOREIGN_BAR, message.packed_enum(0));
// Actually verify the second (modified) elements now.
EXPECT_EQ(801 , message.packed_int32 (1));
@@ -912,7 +970,7 @@ void TestUtil::ExpectPackedFieldsModified(
EXPECT_EQ(810 , message.packed_sfixed64(1));
EXPECT_EQ(811 , message.packed_float (1));
EXPECT_EQ(812 , message.packed_double (1));
- EXPECT_EQ(true , message.packed_bool (1));
+ EXPECT_TRUE( message.packed_bool (1));
EXPECT_EQ(unittest::FOREIGN_FOO, message.packed_enum(1));
}
@@ -953,6 +1011,9 @@ void TestUtil::SetAllExtensions(unittest::TestAllExtensions* message) {
message->SetExtension(unittest::optional_string_piece_extension, "124");
message->SetExtension(unittest::optional_cord_extension, "125");
+ message->MutableExtension(unittest::optional_public_import_message_extension)->set_e(126);
+ message->MutableExtension(unittest::optional_lazy_message_extension)->set_bb(127);
+
// -----------------------------------------------------------------
message->AddExtension(unittest::repeated_int32_extension , 201);
@@ -975,6 +1036,7 @@ void TestUtil::SetAllExtensions(unittest::TestAllExtensions* message) {
message->AddExtension(unittest::repeated_nested_message_extension )->set_bb(218);
message->AddExtension(unittest::repeated_foreign_message_extension)->set_c(219);
message->AddExtension(unittest::repeated_import_message_extension )->set_d(220);
+ message->AddExtension(unittest::repeated_lazy_message_extension )->set_bb(227);
message->AddExtension(unittest::repeated_nested_enum_extension , unittest::TestAllTypes::BAR);
message->AddExtension(unittest::repeated_foreign_enum_extension, unittest::FOREIGN_BAR );
@@ -1004,6 +1066,7 @@ void TestUtil::SetAllExtensions(unittest::TestAllExtensions* message) {
message->AddExtension(unittest::repeated_nested_message_extension )->set_bb(318);
message->AddExtension(unittest::repeated_foreign_message_extension)->set_c(319);
message->AddExtension(unittest::repeated_import_message_extension )->set_d(320);
+ message->AddExtension(unittest::repeated_lazy_message_extension )->set_bb(327);
message->AddExtension(unittest::repeated_nested_enum_extension , unittest::TestAllTypes::BAZ);
message->AddExtension(unittest::repeated_foreign_enum_extension, unittest::FOREIGN_BAZ );
@@ -1036,6 +1099,15 @@ void TestUtil::SetAllExtensions(unittest::TestAllExtensions* message) {
message->SetExtension(unittest::default_string_piece_extension, "424");
message->SetExtension(unittest::default_cord_extension, "425");
+
+ SetOneofFields(message);
+}
+
+void TestUtil::SetOneofFields(unittest::TestAllExtensions* message) {
+ message->SetExtension(unittest::oneof_uint32_extension, 601);
+ message->MutableExtension(unittest::oneof_nested_message_extension)->set_bb(602);
+ message->SetExtension(unittest::oneof_string_extension, "603");
+ message->SetExtension(unittest::oneof_bytes_extension, "604");
}
// -------------------------------------------------------------------
@@ -1073,6 +1145,7 @@ void TestUtil::ModifyRepeatedExtensions(unittest::TestAllExtensions* message) {
message->MutableExtension(unittest::repeated_nested_message_extension , 1)->set_bb(518);
message->MutableExtension(unittest::repeated_foreign_message_extension, 1)->set_c(519);
message->MutableExtension(unittest::repeated_import_message_extension , 1)->set_d(520);
+ message->MutableExtension(unittest::repeated_lazy_message_extension , 1)->set_bb(527);
message->SetExtension(unittest::repeated_nested_enum_extension , 1, unittest::TestAllTypes::FOO);
message->SetExtension(unittest::repeated_foreign_enum_extension, 1, unittest::FOREIGN_FOO );
@@ -1102,15 +1175,19 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension ));
EXPECT_TRUE(message.HasExtension(unittest::optional_bytes_extension ));
- EXPECT_TRUE(message.HasExtension(unittest::optionalgroup_extension ));
- EXPECT_TRUE(message.HasExtension(unittest::optional_nested_message_extension ));
- EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_message_extension));
- EXPECT_TRUE(message.HasExtension(unittest::optional_import_message_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optionalgroup_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_nested_message_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_message_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_import_message_extension ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_public_import_message_extension));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_lazy_message_extension ));
- EXPECT_TRUE(message.GetExtension(unittest::optionalgroup_extension ).has_a());
- EXPECT_TRUE(message.GetExtension(unittest::optional_nested_message_extension ).has_bb());
- EXPECT_TRUE(message.GetExtension(unittest::optional_foreign_message_extension).has_c());
- EXPECT_TRUE(message.GetExtension(unittest::optional_import_message_extension ).has_d());
+ EXPECT_TRUE(message.GetExtension(unittest::optionalgroup_extension ).has_a());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_nested_message_extension ).has_bb());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_foreign_message_extension ).has_c());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_import_message_extension ).has_d());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_public_import_message_extension).has_e());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_lazy_message_extension ).has_bb());
EXPECT_TRUE(message.HasExtension(unittest::optional_nested_enum_extension ));
EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_enum_extension));
@@ -1131,7 +1208,7 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ(110 , message.GetExtension(unittest::optional_sfixed64_extension));
EXPECT_EQ(111 , message.GetExtension(unittest::optional_float_extension ));
EXPECT_EQ(112 , message.GetExtension(unittest::optional_double_extension ));
- EXPECT_EQ(true , message.GetExtension(unittest::optional_bool_extension ));
+ EXPECT_TRUE( message.GetExtension(unittest::optional_bool_extension ));
EXPECT_EQ("115", message.GetExtension(unittest::optional_string_extension ));
EXPECT_EQ("116", message.GetExtension(unittest::optional_bytes_extension ));
@@ -1146,6 +1223,8 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ("124", message.GetExtension(unittest::optional_string_piece_extension));
EXPECT_EQ("125", message.GetExtension(unittest::optional_cord_extension));
+ EXPECT_EQ(126, message.GetExtension(unittest::optional_public_import_message_extension ).e());
+ EXPECT_EQ(127, message.GetExtension(unittest::optional_lazy_message_extension).bb());
// -----------------------------------------------------------------
@@ -1169,6 +1248,7 @@ void TestUtil::ExpectAllExtensionsSet(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1188,7 +1268,7 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ(210 , message.GetExtension(unittest::repeated_sfixed64_extension, 0));
EXPECT_EQ(211 , message.GetExtension(unittest::repeated_float_extension , 0));
EXPECT_EQ(212 , message.GetExtension(unittest::repeated_double_extension , 0));
- EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension , 0));
+ EXPECT_TRUE( message.GetExtension(unittest::repeated_bool_extension , 0));
EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension , 0));
EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension , 0));
@@ -1196,6 +1276,7 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 0));
@@ -1216,7 +1297,7 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ(310 , message.GetExtension(unittest::repeated_sfixed64_extension, 1));
EXPECT_EQ(311 , message.GetExtension(unittest::repeated_float_extension , 1));
EXPECT_EQ(312 , message.GetExtension(unittest::repeated_double_extension , 1));
- EXPECT_EQ(false, message.GetExtension(unittest::repeated_bool_extension , 1));
+ EXPECT_FALSE( message.GetExtension(unittest::repeated_bool_extension , 1));
EXPECT_EQ("315", message.GetExtension(unittest::repeated_string_extension , 1));
EXPECT_EQ("316", message.GetExtension(unittest::repeated_bytes_extension , 1));
@@ -1224,6 +1305,7 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ(318, message.GetExtension(unittest::repeated_nested_message_extension , 1).bb());
EXPECT_EQ(319, message.GetExtension(unittest::repeated_foreign_message_extension, 1).c());
EXPECT_EQ(320, message.GetExtension(unittest::repeated_import_message_extension , 1).d());
+ EXPECT_EQ(327, message.GetExtension(unittest::repeated_lazy_message_extension , 1).bb());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.GetExtension(unittest::repeated_nested_enum_extension , 1));
EXPECT_EQ(unittest::FOREIGN_BAZ , message.GetExtension(unittest::repeated_foreign_enum_extension, 1));
@@ -1269,7 +1351,7 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ(410 , message.GetExtension(unittest::default_sfixed64_extension));
EXPECT_EQ(411 , message.GetExtension(unittest::default_float_extension ));
EXPECT_EQ(412 , message.GetExtension(unittest::default_double_extension ));
- EXPECT_EQ(false, message.GetExtension(unittest::default_bool_extension ));
+ EXPECT_FALSE( message.GetExtension(unittest::default_bool_extension ));
EXPECT_EQ("415", message.GetExtension(unittest::default_string_extension ));
EXPECT_EQ("416", message.GetExtension(unittest::default_bytes_extension ));
@@ -1279,6 +1361,16 @@ void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ("424", message.GetExtension(unittest::default_string_piece_extension));
EXPECT_EQ("425", message.GetExtension(unittest::default_cord_extension));
+
+ EXPECT_TRUE(message.HasExtension(unittest::oneof_uint32_extension));
+ EXPECT_TRUE(message.GetExtension(unittest::oneof_nested_message_extension).has_bb());
+ EXPECT_TRUE(message.HasExtension(unittest::oneof_string_extension));
+ EXPECT_TRUE(message.HasExtension(unittest::oneof_bytes_extension));
+
+ EXPECT_EQ(601, message.GetExtension(unittest::oneof_uint32_extension));
+ EXPECT_EQ(602, message.GetExtension(unittest::oneof_nested_message_extension).bb());
+ EXPECT_EQ("603", message.GetExtension(unittest::oneof_string_extension));
+ EXPECT_EQ("604", message.GetExtension(unittest::oneof_bytes_extension));
}
// -------------------------------------------------------------------
@@ -1307,10 +1399,12 @@ void TestUtil::ExpectExtensionsClear(
EXPECT_FALSE(message.HasExtension(unittest::optional_string_extension ));
EXPECT_FALSE(message.HasExtension(unittest::optional_bytes_extension ));
- EXPECT_FALSE(message.HasExtension(unittest::optionalgroup_extension ));
- EXPECT_FALSE(message.HasExtension(unittest::optional_nested_message_extension ));
- EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_message_extension));
- EXPECT_FALSE(message.HasExtension(unittest::optional_import_message_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optionalgroup_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_nested_message_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_message_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_import_message_extension ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_public_import_message_extension));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_lazy_message_extension ));
EXPECT_FALSE(message.HasExtension(unittest::optional_nested_enum_extension ));
EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_enum_extension));
@@ -1332,20 +1426,24 @@ void TestUtil::ExpectExtensionsClear(
EXPECT_EQ(0 , message.GetExtension(unittest::optional_sfixed64_extension));
EXPECT_EQ(0 , message.GetExtension(unittest::optional_float_extension ));
EXPECT_EQ(0 , message.GetExtension(unittest::optional_double_extension ));
- EXPECT_EQ(false, message.GetExtension(unittest::optional_bool_extension ));
+ EXPECT_FALSE( message.GetExtension(unittest::optional_bool_extension ));
EXPECT_EQ("" , message.GetExtension(unittest::optional_string_extension ));
EXPECT_EQ("" , message.GetExtension(unittest::optional_bytes_extension ));
// Embedded messages should also be clear.
- EXPECT_FALSE(message.GetExtension(unittest::optionalgroup_extension ).has_a());
- EXPECT_FALSE(message.GetExtension(unittest::optional_nested_message_extension ).has_bb());
- EXPECT_FALSE(message.GetExtension(unittest::optional_foreign_message_extension).has_c());
- EXPECT_FALSE(message.GetExtension(unittest::optional_import_message_extension ).has_d());
-
- EXPECT_EQ(0, message.GetExtension(unittest::optionalgroup_extension ).a());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_nested_message_extension ).bb());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_foreign_message_extension).c());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_import_message_extension ).d());
+ EXPECT_FALSE(message.GetExtension(unittest::optionalgroup_extension ).has_a());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_nested_message_extension ).has_bb());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_foreign_message_extension ).has_c());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_import_message_extension ).has_d());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_public_import_message_extension).has_e());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_lazy_message_extension ).has_bb());
+
+ EXPECT_EQ(0, message.GetExtension(unittest::optionalgroup_extension ).a());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_nested_message_extension ).bb());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_foreign_message_extension ).c());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_import_message_extension ).d());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_public_import_message_extension).e());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_lazy_message_extension ).bb());
// Enums without defaults are set to the first value in the enum.
EXPECT_EQ(unittest::TestAllTypes::FOO, message.GetExtension(unittest::optional_nested_enum_extension ));
@@ -1376,6 +1474,7 @@ void TestUtil::ExpectExtensionsClear(
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_nested_message_extension ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_foreign_message_extension));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1420,7 +1519,7 @@ void TestUtil::ExpectExtensionsClear(
EXPECT_EQ(-50 , message.GetExtension(unittest::default_sfixed64_extension));
EXPECT_EQ( 51.5 , message.GetExtension(unittest::default_float_extension ));
EXPECT_EQ( 52e3 , message.GetExtension(unittest::default_double_extension ));
- EXPECT_EQ(true , message.GetExtension(unittest::default_bool_extension ));
+ EXPECT_TRUE( message.GetExtension(unittest::default_bool_extension ));
EXPECT_EQ("hello", message.GetExtension(unittest::default_string_extension ));
EXPECT_EQ("world", message.GetExtension(unittest::default_bytes_extension ));
@@ -1430,6 +1529,11 @@ void TestUtil::ExpectExtensionsClear(
EXPECT_EQ("abc", message.GetExtension(unittest::default_string_piece_extension));
EXPECT_EQ("123", message.GetExtension(unittest::default_cord_extension));
+
+ EXPECT_FALSE(message.HasExtension(unittest::oneof_uint32_extension));
+ EXPECT_FALSE(message.GetExtension(unittest::oneof_nested_message_extension).has_bb());
+ EXPECT_FALSE(message.HasExtension(unittest::oneof_string_extension));
+ EXPECT_FALSE(message.HasExtension(unittest::oneof_bytes_extension));
}
// -------------------------------------------------------------------
@@ -1459,6 +1563,7 @@ void TestUtil::ExpectRepeatedExtensionsModified(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1478,7 +1583,7 @@ void TestUtil::ExpectRepeatedExtensionsModified(
EXPECT_EQ(210 , message.GetExtension(unittest::repeated_sfixed64_extension, 0));
EXPECT_EQ(211 , message.GetExtension(unittest::repeated_float_extension , 0));
EXPECT_EQ(212 , message.GetExtension(unittest::repeated_double_extension , 0));
- EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension , 0));
+ EXPECT_TRUE( message.GetExtension(unittest::repeated_bool_extension , 0));
EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension , 0));
EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension , 0));
@@ -1486,6 +1591,7 @@ void TestUtil::ExpectRepeatedExtensionsModified(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 0));
@@ -1507,7 +1613,7 @@ void TestUtil::ExpectRepeatedExtensionsModified(
EXPECT_EQ(510 , message.GetExtension(unittest::repeated_sfixed64_extension, 1));
EXPECT_EQ(511 , message.GetExtension(unittest::repeated_float_extension , 1));
EXPECT_EQ(512 , message.GetExtension(unittest::repeated_double_extension , 1));
- EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension , 1));
+ EXPECT_TRUE( message.GetExtension(unittest::repeated_bool_extension , 1));
EXPECT_EQ("515", message.GetExtension(unittest::repeated_string_extension , 1));
EXPECT_EQ("516", message.GetExtension(unittest::repeated_bytes_extension , 1));
@@ -1515,6 +1621,7 @@ void TestUtil::ExpectRepeatedExtensionsModified(
EXPECT_EQ(518, message.GetExtension(unittest::repeated_nested_message_extension , 1).bb());
EXPECT_EQ(519, message.GetExtension(unittest::repeated_foreign_message_extension, 1).c());
EXPECT_EQ(520, message.GetExtension(unittest::repeated_import_message_extension , 1).d());
+ EXPECT_EQ(527, message.GetExtension(unittest::repeated_lazy_message_extension , 1).bb());
EXPECT_EQ(unittest::TestAllTypes::FOO, message.GetExtension(unittest::repeated_nested_enum_extension , 1));
EXPECT_EQ(unittest::FOREIGN_FOO , message.GetExtension(unittest::repeated_foreign_enum_extension, 1));
@@ -1609,7 +1716,7 @@ void TestUtil::ExpectPackedExtensionsSet(
EXPECT_EQ(610 , message.GetExtension(unittest::packed_sfixed64_extension, 0));
EXPECT_EQ(611 , message.GetExtension(unittest::packed_float_extension , 0));
EXPECT_EQ(612 , message.GetExtension(unittest::packed_double_extension , 0));
- EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension , 0));
+ EXPECT_TRUE( message.GetExtension(unittest::packed_bool_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAR,
message.GetExtension(unittest::packed_enum_extension, 0));
EXPECT_EQ(701 , message.GetExtension(unittest::packed_int32_extension , 1));
@@ -1624,7 +1731,7 @@ void TestUtil::ExpectPackedExtensionsSet(
EXPECT_EQ(710 , message.GetExtension(unittest::packed_sfixed64_extension, 1));
EXPECT_EQ(711 , message.GetExtension(unittest::packed_float_extension , 1));
EXPECT_EQ(712 , message.GetExtension(unittest::packed_double_extension , 1));
- EXPECT_EQ(false, message.GetExtension(unittest::packed_bool_extension , 1));
+ EXPECT_FALSE( message.GetExtension(unittest::packed_bool_extension , 1));
EXPECT_EQ(unittest::FOREIGN_BAZ,
message.GetExtension(unittest::packed_enum_extension, 1));
}
@@ -1679,7 +1786,7 @@ void TestUtil::ExpectPackedExtensionsModified(
EXPECT_EQ(610 , message.GetExtension(unittest::packed_sfixed64_extension, 0));
EXPECT_EQ(611 , message.GetExtension(unittest::packed_float_extension , 0));
EXPECT_EQ(612 , message.GetExtension(unittest::packed_double_extension , 0));
- EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension , 0));
+ EXPECT_TRUE( message.GetExtension(unittest::packed_bool_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAR,
message.GetExtension(unittest::packed_enum_extension, 0));
@@ -1696,13 +1803,64 @@ void TestUtil::ExpectPackedExtensionsModified(
EXPECT_EQ(810 , message.GetExtension(unittest::packed_sfixed64_extension, 1));
EXPECT_EQ(811 , message.GetExtension(unittest::packed_float_extension , 1));
EXPECT_EQ(812 , message.GetExtension(unittest::packed_double_extension , 1));
- EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension , 1));
+ EXPECT_TRUE( message.GetExtension(unittest::packed_bool_extension , 1));
EXPECT_EQ(unittest::FOREIGN_FOO,
message.GetExtension(unittest::packed_enum_extension, 1));
}
// -------------------------------------------------------------------
+void TestUtil::ExpectUnpackedExtensionsSet(
+ const unittest::TestUnpackedExtensions& message) {
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_int32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_int64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_uint32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_uint64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_sint32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_sint64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_fixed32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_fixed64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_sfixed32_extension));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_sfixed64_extension));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_float_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_double_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_bool_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::unpacked_enum_extension ));
+
+ EXPECT_EQ(601 , message.GetExtension(unittest::unpacked_int32_extension , 0));
+ EXPECT_EQ(602 , message.GetExtension(unittest::unpacked_int64_extension , 0));
+ EXPECT_EQ(603 , message.GetExtension(unittest::unpacked_uint32_extension , 0));
+ EXPECT_EQ(604 , message.GetExtension(unittest::unpacked_uint64_extension , 0));
+ EXPECT_EQ(605 , message.GetExtension(unittest::unpacked_sint32_extension , 0));
+ EXPECT_EQ(606 , message.GetExtension(unittest::unpacked_sint64_extension , 0));
+ EXPECT_EQ(607 , message.GetExtension(unittest::unpacked_fixed32_extension , 0));
+ EXPECT_EQ(608 , message.GetExtension(unittest::unpacked_fixed64_extension , 0));
+ EXPECT_EQ(609 , message.GetExtension(unittest::unpacked_sfixed32_extension, 0));
+ EXPECT_EQ(610 , message.GetExtension(unittest::unpacked_sfixed64_extension, 0));
+ EXPECT_EQ(611 , message.GetExtension(unittest::unpacked_float_extension , 0));
+ EXPECT_EQ(612 , message.GetExtension(unittest::unpacked_double_extension , 0));
+ EXPECT_EQ(true , message.GetExtension(unittest::unpacked_bool_extension , 0));
+ EXPECT_EQ(unittest::FOREIGN_BAR,
+ message.GetExtension(unittest::unpacked_enum_extension, 0));
+ EXPECT_EQ(701 , message.GetExtension(unittest::unpacked_int32_extension , 1));
+ EXPECT_EQ(702 , message.GetExtension(unittest::unpacked_int64_extension , 1));
+ EXPECT_EQ(703 , message.GetExtension(unittest::unpacked_uint32_extension , 1));
+ EXPECT_EQ(704 , message.GetExtension(unittest::unpacked_uint64_extension , 1));
+ EXPECT_EQ(705 , message.GetExtension(unittest::unpacked_sint32_extension , 1));
+ EXPECT_EQ(706 , message.GetExtension(unittest::unpacked_sint64_extension , 1));
+ EXPECT_EQ(707 , message.GetExtension(unittest::unpacked_fixed32_extension , 1));
+ EXPECT_EQ(708 , message.GetExtension(unittest::unpacked_fixed64_extension , 1));
+ EXPECT_EQ(709 , message.GetExtension(unittest::unpacked_sfixed32_extension, 1));
+ EXPECT_EQ(710 , message.GetExtension(unittest::unpacked_sfixed64_extension, 1));
+ EXPECT_EQ(711 , message.GetExtension(unittest::unpacked_float_extension , 1));
+ EXPECT_EQ(712 , message.GetExtension(unittest::unpacked_double_extension , 1));
+ EXPECT_EQ(false, message.GetExtension(unittest::unpacked_bool_extension , 1));
+ EXPECT_EQ(unittest::FOREIGN_BAZ,
+ message.GetExtension(unittest::unpacked_enum_extension, 1));
+}
+
+// -------------------------------------------------------------------
+
void TestUtil::ExpectAllFieldsAndExtensionsInOrder(const string& serialized) {
// We set each field individually, serialize separately, and concatenate all
// the strings in canonical order to determine the expected serialization.
@@ -1750,6 +1908,7 @@ void TestUtil::ExpectLastRepeatedsRemoved(
ASSERT_EQ(1, message.repeated_nested_message_size ());
ASSERT_EQ(1, message.repeated_foreign_message_size());
ASSERT_EQ(1, message.repeated_import_message_size ());
+ ASSERT_EQ(1, message.repeated_import_message_size ());
ASSERT_EQ(1, message.repeated_nested_enum_size ());
ASSERT_EQ(1, message.repeated_foreign_enum_size ());
ASSERT_EQ(1, message.repeated_import_enum_size ());
@@ -1772,7 +1931,7 @@ void TestUtil::ExpectLastRepeatedsRemoved(
EXPECT_EQ(210 , message.repeated_sfixed64(0));
EXPECT_EQ(211 , message.repeated_float (0));
EXPECT_EQ(212 , message.repeated_double (0));
- EXPECT_EQ(true , message.repeated_bool (0));
+ EXPECT_TRUE( message.repeated_bool (0));
EXPECT_EQ("215", message.repeated_string (0));
EXPECT_EQ("216", message.repeated_bytes (0));
@@ -1780,6 +1939,7 @@ void TestUtil::ExpectLastRepeatedsRemoved(
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(220, message.repeated_import_message (0).d());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.repeated_foreign_enum(0));
@@ -1810,6 +1970,7 @@ void TestUtil::ExpectLastRepeatedExtensionsRemoved(
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_nested_message_extension ));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_foreign_message_extension));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1830,7 +1991,7 @@ void TestUtil::ExpectLastRepeatedExtensionsRemoved(
EXPECT_EQ(210 , message.GetExtension(unittest::repeated_sfixed64_extension, 0));
EXPECT_EQ(211 , message.GetExtension(unittest::repeated_float_extension , 0));
EXPECT_EQ(212 , message.GetExtension(unittest::repeated_double_extension , 0));
- EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension , 0));
+ EXPECT_TRUE( message.GetExtension(unittest::repeated_bool_extension , 0));
EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension , 0));
EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension , 0));
@@ -1838,6 +1999,7 @@ void TestUtil::ExpectLastRepeatedExtensionsRemoved(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 0));
@@ -1847,6 +2009,36 @@ void TestUtil::ExpectLastRepeatedExtensionsRemoved(
EXPECT_EQ("225", message.GetExtension(unittest::repeated_cord_extension, 0));
}
+void TestUtil::ExpectLastRepeatedsReleased(
+ const unittest::TestAllTypes& message) {
+ ASSERT_EQ(1, message.repeatedgroup_size ());
+ ASSERT_EQ(1, message.repeated_nested_message_size ());
+ ASSERT_EQ(1, message.repeated_foreign_message_size());
+ ASSERT_EQ(1, message.repeated_import_message_size ());
+ ASSERT_EQ(1, message.repeated_import_message_size ());
+
+ EXPECT_EQ(217, message.repeatedgroup (0).a());
+ EXPECT_EQ(218, message.repeated_nested_message (0).bb());
+ EXPECT_EQ(219, message.repeated_foreign_message(0).c());
+ EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(220, message.repeated_import_message (0).d());
+}
+
+void TestUtil::ExpectLastRepeatedExtensionsReleased(
+ const unittest::TestAllExtensions& message) {
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeatedgroup_extension ));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_nested_message_extension ));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_foreign_message_extension));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
+
+ EXPECT_EQ(217, message.GetExtension(unittest::repeatedgroup_extension , 0).a());
+ EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
+ EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
+ EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
+}
+
void TestUtil::ExpectRepeatedsSwapped(
const unittest::TestAllTypes& message) {
ASSERT_EQ(2, message.repeated_int32_size ());
@@ -1869,6 +2061,7 @@ void TestUtil::ExpectRepeatedsSwapped(
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_import_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -1891,7 +2084,7 @@ void TestUtil::ExpectRepeatedsSwapped(
EXPECT_EQ(210 , message.repeated_sfixed64(1));
EXPECT_EQ(211 , message.repeated_float (1));
EXPECT_EQ(212 , message.repeated_double (1));
- EXPECT_EQ(true , message.repeated_bool (1));
+ EXPECT_TRUE( message.repeated_bool (1));
EXPECT_EQ("215", message.repeated_string (1));
EXPECT_EQ("216", message.repeated_bytes (1));
@@ -1899,6 +2092,7 @@ void TestUtil::ExpectRepeatedsSwapped(
EXPECT_EQ(218, message.repeated_nested_message (1).bb());
EXPECT_EQ(219, message.repeated_foreign_message(1).c());
EXPECT_EQ(220, message.repeated_import_message (1).d());
+ EXPECT_EQ(220, message.repeated_import_message (1).d());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_BAR , message.repeated_foreign_enum(1));
@@ -1916,7 +2110,7 @@ void TestUtil::ExpectRepeatedsSwapped(
EXPECT_EQ(310 , message.repeated_sfixed64(0));
EXPECT_EQ(311 , message.repeated_float (0));
EXPECT_EQ(312 , message.repeated_double (0));
- EXPECT_EQ(false, message.repeated_bool (0));
+ EXPECT_FALSE( message.repeated_bool (0));
EXPECT_EQ("315", message.repeated_string (0));
EXPECT_EQ("316", message.repeated_bytes (0));
@@ -1924,6 +2118,7 @@ void TestUtil::ExpectRepeatedsSwapped(
EXPECT_EQ(318, message.repeated_nested_message (0).bb());
EXPECT_EQ(319, message.repeated_foreign_message(0).c());
EXPECT_EQ(320, message.repeated_import_message (0).d());
+ EXPECT_EQ(320, message.repeated_import_message (0).d());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.repeated_nested_enum (0));
EXPECT_EQ(unittest::FOREIGN_BAZ , message.repeated_foreign_enum(0));
@@ -1953,6 +2148,7 @@ void TestUtil::ExpectRepeatedExtensionsSwapped(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension ));
@@ -1972,7 +2168,7 @@ void TestUtil::ExpectRepeatedExtensionsSwapped(
EXPECT_EQ(210 , message.GetExtension(unittest::repeated_sfixed64_extension, 1));
EXPECT_EQ(211 , message.GetExtension(unittest::repeated_float_extension , 1));
EXPECT_EQ(212 , message.GetExtension(unittest::repeated_double_extension , 1));
- EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension , 1));
+ EXPECT_TRUE( message.GetExtension(unittest::repeated_bool_extension , 1));
EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension , 1));
EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension , 1));
@@ -1980,6 +2176,7 @@ void TestUtil::ExpectRepeatedExtensionsSwapped(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 1).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 1).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 1).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension , 1).bb());
EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 1));
EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 1));
@@ -2000,7 +2197,7 @@ void TestUtil::ExpectRepeatedExtensionsSwapped(
EXPECT_EQ(310 , message.GetExtension(unittest::repeated_sfixed64_extension, 0));
EXPECT_EQ(311 , message.GetExtension(unittest::repeated_float_extension , 0));
EXPECT_EQ(312 , message.GetExtension(unittest::repeated_double_extension , 0));
- EXPECT_EQ(false, message.GetExtension(unittest::repeated_bool_extension , 0));
+ EXPECT_FALSE( message.GetExtension(unittest::repeated_bool_extension , 0));
EXPECT_EQ("315", message.GetExtension(unittest::repeated_string_extension , 0));
EXPECT_EQ("316", message.GetExtension(unittest::repeated_bytes_extension , 0));
@@ -2008,6 +2205,7 @@ void TestUtil::ExpectRepeatedExtensionsSwapped(
EXPECT_EQ(318, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb());
EXPECT_EQ(319, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c());
EXPECT_EQ(320, message.GetExtension(unittest::repeated_import_message_extension , 0).d());
+ EXPECT_EQ(327, message.GetExtension(unittest::repeated_lazy_message_extension , 0).bb());
EXPECT_EQ(unittest::TestAllTypes::BAZ, message.GetExtension(unittest::repeated_nested_enum_extension , 0));
EXPECT_EQ(unittest::FOREIGN_BAZ , message.GetExtension(unittest::repeated_foreign_enum_extension, 0));
@@ -2017,6 +2215,92 @@ void TestUtil::ExpectRepeatedExtensionsSwapped(
EXPECT_EQ("325", message.GetExtension(unittest::repeated_cord_extension, 0));
}
+void TestUtil::SetOneof1(unittest::TestOneof2* message) {
+ message->mutable_foo_lazy_message()->set_qux_int(100);
+ message->set_bar_string("101");
+ message->set_baz_int(102);
+ message->set_baz_string("103");
+}
+
+void TestUtil::SetOneof2(unittest::TestOneof2* message) {
+ message->set_foo_int(200);
+ message->set_bar_enum(unittest::TestOneof2::BAZ);
+ message->set_baz_int(202);
+ message->set_baz_string("203");
+}
+
+void TestUtil::ExpectOneofSet1(const unittest::TestOneof2& message) {
+ ExpectAtMostOneFieldSetInOneof(message);
+
+ EXPECT_TRUE(message.has_foo_lazy_message ());
+ EXPECT_TRUE(message.foo_lazy_message().has_qux_int());
+
+ EXPECT_TRUE(message.has_bar_string());
+ EXPECT_TRUE(message.has_baz_int ());
+ EXPECT_TRUE(message.has_baz_string());
+
+ ASSERT_EQ(0, message.foo_lazy_message().corge_int_size());
+
+ EXPECT_EQ(100 , message.foo_lazy_message().qux_int());
+ EXPECT_EQ("101", message.bar_string ());
+ EXPECT_EQ(102 , message.baz_int ());
+ EXPECT_EQ("103", message.baz_string ());
+}
+
+void TestUtil::ExpectOneofSet2(const unittest::TestOneof2& message) {
+ ExpectAtMostOneFieldSetInOneof(message);
+
+ EXPECT_TRUE(message.has_foo_int ());
+ EXPECT_TRUE(message.has_bar_enum ());
+ EXPECT_TRUE(message.has_baz_int ());
+ EXPECT_TRUE(message.has_baz_string());
+
+ EXPECT_EQ(200 , message.foo_int ());
+ EXPECT_EQ(unittest::TestOneof2::BAZ, message.bar_enum ());
+ EXPECT_EQ(202 , message.baz_int ());
+ EXPECT_EQ("203" , message.baz_string());
+}
+
+void TestUtil::ExpectOneofClear(const unittest::TestOneof2& message) {
+ EXPECT_FALSE(message.has_foo_int());
+ EXPECT_FALSE(message.has_foo_string());
+ EXPECT_FALSE(message.has_foo_bytes());
+ EXPECT_FALSE(message.has_foo_enum());
+ EXPECT_FALSE(message.has_foo_message());
+ EXPECT_FALSE(message.has_foogroup());
+ EXPECT_FALSE(message.has_foo_lazy_message());
+
+ EXPECT_FALSE(message.has_bar_int());
+ EXPECT_FALSE(message.has_bar_string());
+ EXPECT_FALSE(message.has_bar_bytes());
+ EXPECT_FALSE(message.has_bar_enum());
+
+ EXPECT_FALSE(message.has_baz_int());
+ EXPECT_FALSE(message.has_baz_string());
+
+ EXPECT_EQ(unittest::TestOneof2::FOO_NOT_SET, message.foo_case());
+ EXPECT_EQ(unittest::TestOneof2::BAR_NOT_SET, message.bar_case());
+}
+
+void TestUtil::ExpectAtMostOneFieldSetInOneof(
+ const unittest::TestOneof2& message) {
+ int count = 0;
+ if (message.has_foo_int()) count++;
+ if (message.has_foo_string()) count++;
+ if (message.has_foo_bytes()) count++;
+ if (message.has_foo_enum()) count++;
+ if (message.has_foo_message()) count++;
+ if (message.has_foogroup()) count++;
+ if (message.has_foo_lazy_message()) count++;
+ EXPECT_LE(count, 1);
+ count = 0;
+ if (message.has_bar_int()) count++;
+ if (message.has_bar_string()) count++;
+ if (message.has_bar_bytes()) count++;
+ if (message.has_bar_enum()) count++;
+ EXPECT_TRUE(count == 0 || count == 1);
+}
+
// ===================================================================
TestUtil::ReflectionTester::ReflectionTester(
@@ -2031,6 +2315,8 @@ TestUtil::ReflectionTester::ReflectionTester(
pool->FindFieldByName("protobuf_unittest.ForeignMessage.c");
import_d_ =
pool->FindFieldByName("protobuf_unittest_import.ImportMessage.d");
+ import_e_ =
+ pool->FindFieldByName("protobuf_unittest_import.PublicImportMessage.e");
nested_foo_ =
pool->FindEnumValueByName("protobuf_unittest.TestAllTypes.FOO");
nested_bar_ =
@@ -2067,6 +2353,7 @@ TestUtil::ReflectionTester::ReflectionTester(
EXPECT_TRUE(nested_b_ != NULL);
EXPECT_TRUE(foreign_c_ != NULL);
EXPECT_TRUE(import_d_ != NULL);
+ EXPECT_TRUE(import_e_ != NULL);
EXPECT_TRUE(nested_foo_ != NULL);
EXPECT_TRUE(nested_bar_ != NULL);
EXPECT_TRUE(nested_baz_ != NULL);
@@ -2129,6 +2416,12 @@ void TestUtil::ReflectionTester::SetAllFieldsViaReflection(Message* message) {
reflection->SetString(message, F("optional_string_piece"), "124");
reflection->SetString(message, F("optional_cord"), "125");
+ sub_message = reflection->MutableMessage(message, F("optional_public_import_message"));
+ sub_message->GetReflection()->SetInt32(sub_message, import_e_, 126);
+
+ sub_message = reflection->MutableMessage(message, F("optional_lazy_message"));
+ sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 127);
+
// -----------------------------------------------------------------
reflection->AddInt32 (message, F("repeated_int32" ), 201);
@@ -2155,6 +2448,8 @@ void TestUtil::ReflectionTester::SetAllFieldsViaReflection(Message* message) {
sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 219);
sub_message = reflection->AddMessage(message, F("repeated_import_message"));
sub_message->GetReflection()->SetInt32(sub_message, import_d_, 220);
+ sub_message = reflection->AddMessage(message, F("repeated_lazy_message"));
+ sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 227);
reflection->AddEnum(message, F("repeated_nested_enum" ), nested_bar_);
reflection->AddEnum(message, F("repeated_foreign_enum"), foreign_bar_);
@@ -2188,6 +2483,8 @@ void TestUtil::ReflectionTester::SetAllFieldsViaReflection(Message* message) {
sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 319);
sub_message = reflection->AddMessage(message, F("repeated_import_message"));
sub_message->GetReflection()->SetInt32(sub_message, import_d_, 320);
+ sub_message = reflection->AddMessage(message, F("repeated_lazy_message"));
+ sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 327);
reflection->AddEnum(message, F("repeated_nested_enum" ), nested_baz_);
reflection->AddEnum(message, F("repeated_foreign_enum"), foreign_baz_);
@@ -2220,6 +2517,69 @@ void TestUtil::ReflectionTester::SetAllFieldsViaReflection(Message* message) {
reflection->SetString(message, F("default_string_piece"), "424");
reflection->SetString(message, F("default_cord"), "425");
+
+ reflection->SetUInt32(message, F("oneof_uint32" ), 601);
+ sub_message = reflection->MutableMessage(message, F("oneof_nested_message"));
+ sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 602);
+ reflection->SetString(message, F("oneof_string"), "603");
+ reflection->SetString(message, F("oneof_bytes" ), "604");
+}
+
+void TestUtil::ReflectionTester::SetOneofViaReflection(Message* message) {
+ const Descriptor* descriptor = message->GetDescriptor();
+ const Reflection* reflection = message->GetReflection();
+ Message* sub_message = reflection->MutableMessage(
+ message, descriptor->FindFieldByName("foo_lazy_message"));
+ sub_message->GetReflection()->SetInt64(
+ sub_message,
+ descriptor->file()->pool()->FindFieldByName(
+ "protobuf_unittest.TestOneof2.NestedMessage.qux_int"),
+ 100);
+
+ reflection->SetString(message,
+ descriptor->FindFieldByName("bar_cord"),
+ "101");
+ reflection->SetInt32(message,
+ descriptor->FindFieldByName("baz_int"),
+ 102);
+ reflection->SetString(message,
+ descriptor->FindFieldByName("baz_string"),
+ "103");
+}
+
+void TestUtil::ReflectionTester::ExpectOneofSetViaReflection(
+ const Message& message) {
+ const Descriptor* descriptor = message.GetDescriptor();
+ const Reflection* reflection = message.GetReflection();
+ string scratch;
+ EXPECT_TRUE(reflection->HasField(
+ message, descriptor->FindFieldByName("foo_lazy_message")));
+ EXPECT_TRUE(reflection->HasField(
+ message, descriptor->FindFieldByName("bar_cord")));
+ EXPECT_TRUE(reflection->HasField(
+ message, descriptor->FindFieldByName("baz_int")));
+ EXPECT_TRUE(reflection->HasField(
+ message, descriptor->FindFieldByName("baz_string")));
+
+ const Message* sub_message = &reflection->GetMessage(
+ message, descriptor->FindFieldByName("foo_lazy_message"));
+ EXPECT_EQ(100, sub_message->GetReflection()->GetInt64(
+ *sub_message,
+ descriptor->file()->pool()->FindFieldByName(
+ "protobuf_unittest.TestOneof2.NestedMessage.qux_int")));
+
+ EXPECT_EQ("101", reflection->GetString(
+ message, descriptor->FindFieldByName("bar_cord")));
+ EXPECT_EQ("101", reflection->GetStringReference(
+ message, descriptor->FindFieldByName("bar_cord"), &scratch));
+
+ EXPECT_EQ(102, reflection->GetInt32(
+ message, descriptor->FindFieldByName("baz_int")));
+
+ EXPECT_EQ("103", reflection->GetString(
+ message, descriptor->FindFieldByName("baz_string")));
+ EXPECT_EQ("103", reflection->GetStringReference(
+ message, descriptor->FindFieldByName("baz_string"), &scratch));
}
void TestUtil::ReflectionTester::SetPackedFieldsViaReflection(
@@ -2289,10 +2649,12 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_TRUE(reflection->HasField(message, F("optional_string" )));
EXPECT_TRUE(reflection->HasField(message, F("optional_bytes" )));
- EXPECT_TRUE(reflection->HasField(message, F("optionalgroup" )));
- EXPECT_TRUE(reflection->HasField(message, F("optional_nested_message" )));
- EXPECT_TRUE(reflection->HasField(message, F("optional_foreign_message")));
- EXPECT_TRUE(reflection->HasField(message, F("optional_import_message" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optionalgroup" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_nested_message" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_foreign_message" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_import_message" )));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_public_import_message")));
+ EXPECT_TRUE(reflection->HasField(message, F("optional_lazy_message" )));
sub_message = &reflection->GetMessage(message, F("optionalgroup"));
EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, group_a_));
@@ -2302,6 +2664,10 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, foreign_c_));
sub_message = &reflection->GetMessage(message, F("optional_import_message"));
EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, import_d_));
+ sub_message = &reflection->GetMessage(message, F("optional_public_import_message"));
+ EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, import_e_));
+ sub_message = &reflection->GetMessage(message, F("optional_lazy_message"));
+ EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
EXPECT_TRUE(reflection->HasField(message, F("optional_nested_enum" )));
EXPECT_TRUE(reflection->HasField(message, F("optional_foreign_enum")));
@@ -2322,7 +2688,7 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_EQ(110 , reflection->GetInt64 (message, F("optional_sfixed64")));
EXPECT_EQ(111 , reflection->GetFloat (message, F("optional_float" )));
EXPECT_EQ(112 , reflection->GetDouble(message, F("optional_double" )));
- EXPECT_EQ(true , reflection->GetBool (message, F("optional_bool" )));
+ EXPECT_TRUE( reflection->GetBool (message, F("optional_bool" )));
EXPECT_EQ("115", reflection->GetString(message, F("optional_string" )));
EXPECT_EQ("116", reflection->GetString(message, F("optional_bytes" )));
@@ -2337,6 +2703,10 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_EQ(119, sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
sub_message = &reflection->GetMessage(message, F("optional_import_message"));
EXPECT_EQ(120, sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+ sub_message = &reflection->GetMessage(message, F("optional_public_import_message"));
+ EXPECT_EQ(126, sub_message->GetReflection()->GetInt32(*sub_message, import_e_));
+ sub_message = &reflection->GetMessage(message, F("optional_lazy_message"));
+ EXPECT_EQ(127, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
EXPECT_EQ( nested_baz_, reflection->GetEnum(message, F("optional_nested_enum" )));
EXPECT_EQ(foreign_baz_, reflection->GetEnum(message, F("optional_foreign_enum")));
@@ -2347,6 +2717,21 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_EQ("125", reflection->GetString(message, F("optional_cord")));
EXPECT_EQ("125", reflection->GetStringReference(message, F("optional_cord"), &scratch));
+
+ EXPECT_TRUE(reflection->HasField(message, F("oneof_bytes" )));
+ EXPECT_EQ("604", reflection->GetString(message, F("oneof_bytes" )));
+
+ if (base_descriptor_->name() == "TestAllTypes") {
+ EXPECT_FALSE(reflection->HasField(message, F("oneof_uint32")));
+ EXPECT_FALSE(reflection->HasField(message, F("oneof_string")));
+ } else {
+ EXPECT_TRUE(reflection->HasField(message, F("oneof_uint32")));
+ EXPECT_TRUE(reflection->HasField(message, F("oneof_string")));
+ EXPECT_EQ(601 , reflection->GetUInt32(message, F("oneof_uint32")));
+ EXPECT_EQ("603", reflection->GetString(message, F("oneof_string")));
+ sub_message = &reflection->GetMessage(message, F("oneof_nested_message"));
+ EXPECT_EQ(602, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+ }
}
void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
@@ -2377,6 +2762,7 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_nested_message" )));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_foreign_message")));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_import_message" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_lazy_message" )));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_nested_enum" )));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_foreign_enum" )));
ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_import_enum" )));
@@ -2396,7 +2782,7 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
EXPECT_EQ(210 , reflection->GetRepeatedInt64 (message, F("repeated_sfixed64"), 0));
EXPECT_EQ(211 , reflection->GetRepeatedFloat (message, F("repeated_float" ), 0));
EXPECT_EQ(212 , reflection->GetRepeatedDouble(message, F("repeated_double" ), 0));
- EXPECT_EQ(true , reflection->GetRepeatedBool (message, F("repeated_bool" ), 0));
+ EXPECT_TRUE( reflection->GetRepeatedBool (message, F("repeated_bool" ), 0));
EXPECT_EQ("215", reflection->GetRepeatedString(message, F("repeated_string" ), 0));
EXPECT_EQ("216", reflection->GetRepeatedString(message, F("repeated_bytes" ), 0));
@@ -2411,6 +2797,8 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
EXPECT_EQ(219, sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
sub_message = &reflection->GetRepeatedMessage(message, F("repeated_import_message"), 0);
EXPECT_EQ(220, sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+ sub_message = &reflection->GetRepeatedMessage(message, F("repeated_lazy_message"), 0);
+ EXPECT_EQ(227, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
EXPECT_EQ( nested_bar_, reflection->GetRepeatedEnum(message, F("repeated_nested_enum" ),0));
EXPECT_EQ(foreign_bar_, reflection->GetRepeatedEnum(message, F("repeated_foreign_enum"),0));
@@ -2436,7 +2824,7 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
EXPECT_EQ(310 , reflection->GetRepeatedInt64 (message, F("repeated_sfixed64"), 1));
EXPECT_EQ(311 , reflection->GetRepeatedFloat (message, F("repeated_float" ), 1));
EXPECT_EQ(312 , reflection->GetRepeatedDouble(message, F("repeated_double" ), 1));
- EXPECT_EQ(false, reflection->GetRepeatedBool (message, F("repeated_bool" ), 1));
+ EXPECT_FALSE( reflection->GetRepeatedBool (message, F("repeated_bool" ), 1));
EXPECT_EQ("315", reflection->GetRepeatedString(message, F("repeated_string" ), 1));
EXPECT_EQ("316", reflection->GetRepeatedString(message, F("repeated_bytes" ), 1));
@@ -2453,6 +2841,8 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
EXPECT_EQ(319, sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
sub_message = &reflection->GetRepeatedMessage(message, F("repeated_import_message"), 1);
EXPECT_EQ(320, sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+ sub_message = &reflection->GetRepeatedMessage(message, F("repeated_lazy_message"), 1);
+ EXPECT_EQ(327, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
EXPECT_EQ( nested_baz_, reflection->GetRepeatedEnum(message, F("repeated_nested_enum" ),1));
EXPECT_EQ(foreign_baz_, reflection->GetRepeatedEnum(message, F("repeated_foreign_enum"),1));
@@ -2509,7 +2899,7 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection3(
EXPECT_EQ(410 , reflection->GetInt64 (message, F("default_sfixed64")));
EXPECT_EQ(411 , reflection->GetFloat (message, F("default_float" )));
EXPECT_EQ(412 , reflection->GetDouble(message, F("default_double" )));
- EXPECT_EQ(false, reflection->GetBool (message, F("default_bool" )));
+ EXPECT_FALSE( reflection->GetBool (message, F("default_bool" )));
EXPECT_EQ("415", reflection->GetString(message, F("default_string" )));
EXPECT_EQ("416", reflection->GetString(message, F("default_bytes" )));
@@ -2559,7 +2949,7 @@ void TestUtil::ReflectionTester::ExpectPackedFieldsSetViaReflection(
EXPECT_EQ(610 , reflection->GetRepeatedInt64 (message, F("packed_sfixed64"), 0));
EXPECT_EQ(611 , reflection->GetRepeatedFloat (message, F("packed_float" ), 0));
EXPECT_EQ(612 , reflection->GetRepeatedDouble(message, F("packed_double" ), 0));
- EXPECT_EQ(true , reflection->GetRepeatedBool (message, F("packed_bool" ), 0));
+ EXPECT_TRUE( reflection->GetRepeatedBool (message, F("packed_bool" ), 0));
EXPECT_EQ(foreign_bar_,
reflection->GetRepeatedEnum(message, F("packed_enum"), 0));
@@ -2575,7 +2965,7 @@ void TestUtil::ReflectionTester::ExpectPackedFieldsSetViaReflection(
EXPECT_EQ(710 , reflection->GetRepeatedInt64 (message, F("packed_sfixed64"), 1));
EXPECT_EQ(711 , reflection->GetRepeatedFloat (message, F("packed_float" ), 1));
EXPECT_EQ(712 , reflection->GetRepeatedDouble(message, F("packed_double" ), 1));
- EXPECT_EQ(false, reflection->GetRepeatedBool (message, F("packed_bool" ), 1));
+ EXPECT_FALSE( reflection->GetRepeatedBool (message, F("packed_bool" ), 1));
EXPECT_EQ(foreign_baz_,
reflection->GetRepeatedEnum(message, F("packed_enum"), 1));
}
@@ -2609,6 +2999,8 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_FALSE(reflection->HasField(message, F("optional_nested_message" )));
EXPECT_FALSE(reflection->HasField(message, F("optional_foreign_message")));
EXPECT_FALSE(reflection->HasField(message, F("optional_import_message" )));
+ EXPECT_FALSE(reflection->HasField(message, F("optional_public_import_message")));
+ EXPECT_FALSE(reflection->HasField(message, F("optional_lazy_message")));
EXPECT_FALSE(reflection->HasField(message, F("optional_nested_enum" )));
EXPECT_FALSE(reflection->HasField(message, F("optional_foreign_enum")));
@@ -2630,7 +3022,7 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_EQ(0 , reflection->GetInt64 (message, F("optional_sfixed64")));
EXPECT_EQ(0 , reflection->GetFloat (message, F("optional_float" )));
EXPECT_EQ(0 , reflection->GetDouble(message, F("optional_double" )));
- EXPECT_EQ(false, reflection->GetBool (message, F("optional_bool" )));
+ EXPECT_FALSE( reflection->GetBool (message, F("optional_bool" )));
EXPECT_EQ("" , reflection->GetString(message, F("optional_string" )));
EXPECT_EQ("" , reflection->GetString(message, F("optional_bytes" )));
@@ -2650,6 +3042,12 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection(
sub_message = &reflection->GetMessage(message, F("optional_import_message"));
EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, import_d_));
EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+ sub_message = &reflection->GetMessage(message, F("optional_public_import_message"));
+ EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, import_e_));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, import_e_));
+ sub_message = &reflection->GetMessage(message, F("optional_lazy_message"));
+ EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
+ EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
// Enums without defaults are set to the first value in the enum.
EXPECT_EQ( nested_foo_, reflection->GetEnum(message, F("optional_nested_enum" )));
@@ -2683,6 +3081,7 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_nested_message" )));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_foreign_message")));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_import_message" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_lazy_message" )));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_nested_enum" )));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_foreign_enum" )));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_import_enum" )));
@@ -2727,7 +3126,7 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_EQ(-50 , reflection->GetInt64 (message, F("default_sfixed64")));
EXPECT_EQ( 51.5 , reflection->GetFloat (message, F("default_float" )));
EXPECT_EQ( 52e3 , reflection->GetDouble(message, F("default_double" )));
- EXPECT_EQ(true , reflection->GetBool (message, F("default_bool" )));
+ EXPECT_TRUE( reflection->GetBool (message, F("default_bool" )));
EXPECT_EQ("hello", reflection->GetString(message, F("default_string" )));
EXPECT_EQ("world", reflection->GetString(message, F("default_bytes" )));
@@ -2796,6 +3195,8 @@ void TestUtil::ReflectionTester::ModifyRepeatedFieldsViaReflection(
sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 519);
sub_message = reflection->MutableRepeatedMessage(message, F("repeated_import_message"), 1);
sub_message->GetReflection()->SetInt32(sub_message, import_d_, 520);
+ sub_message = reflection->MutableRepeatedMessage(message, F("repeated_lazy_message"), 1);
+ sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 527);
reflection->SetRepeatedEnum(message, F("repeated_nested_enum" ), 1, nested_foo_);
reflection->SetRepeatedEnum(message, F("repeated_foreign_enum"), 1, foreign_foo_);
@@ -2824,7 +3225,8 @@ void TestUtil::ReflectionTester::ModifyPackedFieldsViaReflection(
reflection->SetRepeatedEnum (message, F("packed_enum" ), 1, foreign_foo_);
}
-void TestUtil::ReflectionTester::RemoveLastRepeatedsViaReflection(Message* message) {
+void TestUtil::ReflectionTester::RemoveLastRepeatedsViaReflection(
+ Message* message) {
const Reflection* reflection = message->GetReflection();
vector<const FieldDescriptor*> output;
@@ -2837,6 +3239,26 @@ void TestUtil::ReflectionTester::RemoveLastRepeatedsViaReflection(Message* messa
}
}
+void TestUtil::ReflectionTester::ReleaseLastRepeatedsViaReflection(
+ Message* message, bool expect_extensions_notnull) {
+ const Reflection* reflection = message->GetReflection();
+
+ vector<const FieldDescriptor*> output;
+ reflection->ListFields(*message, &output);
+ for (int i=0; i<output.size(); ++i) {
+ const FieldDescriptor* field = output[i];
+ if (!field->is_repeated()) continue;
+ if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+ Message* released = reflection->ReleaseLast(message, field);
+ if (!field->is_extension() || expect_extensions_notnull) {
+ ASSERT_TRUE(released != NULL) << "ReleaseLast returned NULL for: "
+ << field->name();
+ }
+ delete released;
+ }
+}
+
void TestUtil::ReflectionTester::SwapRepeatedsViaReflection(Message* message) {
const Reflection* reflection = message->GetReflection();
@@ -2850,5 +3272,74 @@ void TestUtil::ReflectionTester::SwapRepeatedsViaReflection(Message* message) {
}
}
+void TestUtil::ReflectionTester::
+SetAllocatedOptionalMessageFieldsToNullViaReflection(
+ Message* message) {
+ const Reflection* reflection = message->GetReflection();
+
+ vector<const FieldDescriptor*> fields;
+ reflection->ListFields(*message, &fields);
+
+ for (int i = 0; i < fields.size(); ++i) {
+ const FieldDescriptor* field = fields[i];
+ if (!field->is_optional() ||
+ field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+ reflection->SetAllocatedMessage(message, NULL, field);
+ }
+}
+
+void TestUtil::ReflectionTester::
+SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+ Message* from_message,
+ Message* to_message) {
+ EXPECT_EQ(from_message->GetDescriptor(), to_message->GetDescriptor());
+ const Reflection* from_reflection = from_message->GetReflection();
+ const Reflection* to_reflection = to_message->GetReflection();
+
+ vector<const FieldDescriptor*> fields;
+ from_reflection->ListFields(*from_message, &fields);
+
+ for (int i = 0; i < fields.size(); ++i) {
+ const FieldDescriptor* field = fields[i];
+ if (!field->is_optional() ||
+ field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+ Message* sub_message =
+ from_reflection->ReleaseMessage(from_message, field);
+ to_reflection->SetAllocatedMessage(to_message, sub_message, field);
+ }
+}
+
+void TestUtil::ReflectionTester::ExpectMessagesReleasedViaReflection(
+ Message* message,
+ TestUtil::ReflectionTester::MessageReleaseState expected_release_state) {
+ const Reflection* reflection = message->GetReflection();
+
+ static const char* fields[] = {
+ "optionalgroup",
+ "optional_nested_message",
+ "optional_foreign_message",
+ "optional_import_message",
+ };
+ for (int i = 0; i < GOOGLE_ARRAYSIZE(fields); i++) {
+ const Message& sub_message = reflection->GetMessage(*message, F(fields[i]));
+ Message* released = reflection->ReleaseMessage(message, F(fields[i]));
+ switch (expected_release_state) {
+ case IS_NULL:
+ EXPECT_TRUE(released == NULL);
+ break;
+ case NOT_NULL:
+ EXPECT_TRUE(released != NULL);
+ EXPECT_EQ(&sub_message, released);
+ break;
+ case CAN_BE_NULL:
+ break;
+ }
+ delete released;
+ EXPECT_FALSE(reflection->HasField(*message, F(fields[i])));
+ }
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h
index 25165f3a..d449c009 100644
--- a/src/google/protobuf/test_util.h
+++ b/src/google/protobuf/test_util.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -43,18 +43,26 @@
namespace google {
namespace protobuf {
-namespace unittest = protobuf_unittest;
+namespace unittest = ::protobuf_unittest;
namespace unittest_import = protobuf_unittest_import;
class TestUtil {
public:
// Set every field in the message to a unique value.
static void SetAllFields(unittest::TestAllTypes* message);
+ static void SetOptionalFields(unittest::TestAllTypes* message);
+ static void AddRepeatedFields1(unittest::TestAllTypes* message);
+ static void AddRepeatedFields2(unittest::TestAllTypes* message);
+ static void SetDefaultFields(unittest::TestAllTypes* message);
+ static void SetOneofFields(unittest::TestAllTypes* message);
static void SetAllExtensions(unittest::TestAllExtensions* message);
+ static void SetOneofFields(unittest::TestAllExtensions* message);
static void SetAllFieldsAndExtensions(unittest::TestFieldOrderings* message);
static void SetPackedFields(unittest::TestPackedTypes* message);
static void SetPackedExtensions(unittest::TestPackedExtensions* message);
static void SetUnpackedFields(unittest::TestUnpackedTypes* message);
+ static void SetOneof1(unittest::TestOneof2* message);
+ static void SetOneof2(unittest::TestOneof2* message);
// Use the repeated versions of the set_*() accessors to modify all the
// repeated fields of the messsage (which should already have been
@@ -75,6 +83,10 @@ class TestUtil {
const unittest::TestPackedExtensions& message);
static void ExpectUnpackedFieldsSet(
const unittest::TestUnpackedTypes& message);
+ static void ExpectUnpackedExtensionsSet(
+ const unittest::TestUnpackedExtensions& message);
+ static void ExpectOneofSet1(const unittest::TestOneof2& message);
+ static void ExpectOneofSet2(const unittest::TestOneof2& message);
// Expect that the message is modified as would be expected from
// Modify*Fields().
@@ -93,6 +105,7 @@ class TestUtil {
static void ExpectPackedClear(const unittest::TestPackedTypes& message);
static void ExpectPackedExtensionsClear(
const unittest::TestPackedExtensions& message);
+ static void ExpectOneofClear(const unittest::TestOneof2& message);
// Check that the passed-in serialization is the canonical serialization we
// expect for a TestFieldOrderings message filled in by
@@ -104,6 +117,10 @@ class TestUtil {
const unittest::TestAllTypes& message);
static void ExpectLastRepeatedExtensionsRemoved(
const unittest::TestAllExtensions& message);
+ static void ExpectLastRepeatedsReleased(
+ const unittest::TestAllTypes& message);
+ static void ExpectLastRepeatedExtensionsReleased(
+ const unittest::TestAllExtensions& message);
// Check that all repeated fields have had their first and last elements
// swapped.
@@ -111,6 +128,9 @@ class TestUtil {
static void ExpectRepeatedExtensionsSwapped(
const unittest::TestAllExtensions& message);
+ static void ExpectAtMostOneFieldSetInOneof(
+ const unittest::TestOneof2 &message);
+
// Like above, but use the reflection interface.
class ReflectionTester {
public:
@@ -132,7 +152,27 @@ class TestUtil {
void ExpectPackedClearViaReflection(const Message& message);
void RemoveLastRepeatedsViaReflection(Message* message);
+ void ReleaseLastRepeatedsViaReflection(
+ Message* message, bool expect_extensions_notnull);
void SwapRepeatedsViaReflection(Message* message);
+ void SetAllocatedOptionalMessageFieldsToNullViaReflection(
+ Message* message);
+ static void SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+ Message* from_message,
+ Message* to_message);
+
+ enum MessageReleaseState {
+ IS_NULL,
+ CAN_BE_NULL,
+ NOT_NULL,
+ };
+ void ExpectMessagesReleasedViaReflection(
+ Message* message, MessageReleaseState expected_release_state);
+
+ // Set and check functions for TestOneof2 messages. No need to construct
+ // the ReflectionTester by TestAllTypes nor TestAllExtensions.
+ static void SetOneofViaReflection(Message* message);
+ static void ExpectOneofSetViaReflection(const Message& message);
private:
const FieldDescriptor* F(const string& name);
@@ -144,6 +184,7 @@ class TestUtil {
const FieldDescriptor* nested_b_;
const FieldDescriptor* foreign_c_;
const FieldDescriptor* import_d_;
+ const FieldDescriptor* import_e_;
const EnumValueDescriptor* nested_foo_;
const EnumValueDescriptor* nested_bar_;
diff --git a/src/google/protobuf/test_util_lite.cc b/src/google/protobuf/test_util_lite.cc
index d7140e0c..88eca0ad 100644
--- a/src/google/protobuf/test_util_lite.cc
+++ b/src/google/protobuf/test_util_lite.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -62,10 +62,12 @@ void TestUtilLite::SetAllFields(unittest::TestAllTypesLite* message) {
message->set_optional_string ("115");
message->set_optional_bytes ("116");
- message->mutable_optionalgroup ()->set_a(117);
- message->mutable_optional_nested_message ()->set_bb(118);
- message->mutable_optional_foreign_message()->set_c(119);
- message->mutable_optional_import_message ()->set_d(120);
+ message->mutable_optionalgroup ()->set_a(117);
+ message->mutable_optional_nested_message ()->set_bb(118);
+ message->mutable_optional_foreign_message ()->set_c(119);
+ message->mutable_optional_import_message ()->set_d(120);
+ message->mutable_optional_public_import_message()->set_e(126);
+ message->mutable_optional_lazy_message ()->set_bb(127);
message->set_optional_nested_enum (unittest::TestAllTypesLite::BAZ );
message->set_optional_foreign_enum(unittest::FOREIGN_LITE_BAZ );
@@ -94,6 +96,7 @@ void TestUtilLite::SetAllFields(unittest::TestAllTypesLite* message) {
message->add_repeated_nested_message ()->set_bb(218);
message->add_repeated_foreign_message()->set_c(219);
message->add_repeated_import_message ()->set_d(220);
+ message->add_repeated_lazy_message ()->set_bb(227);
message->add_repeated_nested_enum (unittest::TestAllTypesLite::BAR );
message->add_repeated_foreign_enum(unittest::FOREIGN_LITE_BAR );
@@ -121,6 +124,7 @@ void TestUtilLite::SetAllFields(unittest::TestAllTypesLite* message) {
message->add_repeated_nested_message ()->set_bb(318);
message->add_repeated_foreign_message()->set_c(319);
message->add_repeated_import_message ()->set_d(320);
+ message->add_repeated_lazy_message ()->set_bb(327);
message->add_repeated_nested_enum (unittest::TestAllTypesLite::BAZ );
message->add_repeated_foreign_enum(unittest::FOREIGN_LITE_BAZ );
@@ -149,6 +153,11 @@ void TestUtilLite::SetAllFields(unittest::TestAllTypesLite* message) {
message->set_default_foreign_enum(unittest::FOREIGN_LITE_FOO );
message->set_default_import_enum (unittest_import::IMPORT_LITE_FOO);
+
+ message->set_oneof_uint32(601);
+ message->mutable_oneof_nested_message()->set_bb(602);
+ message->set_oneof_string("603");
+ message->set_oneof_bytes("604");
}
// -------------------------------------------------------------------
@@ -174,6 +183,7 @@ void TestUtilLite::ModifyRepeatedFields(unittest::TestAllTypesLite* message) {
message->mutable_repeated_nested_message (1)->set_bb(518);
message->mutable_repeated_foreign_message(1)->set_c(519);
message->mutable_repeated_import_message (1)->set_d(520);
+ message->mutable_repeated_lazy_message (1)->set_bb(527);
message->set_repeated_nested_enum (1, unittest::TestAllTypesLite::FOO );
message->set_repeated_foreign_enum(1, unittest::FOREIGN_LITE_FOO );
@@ -201,15 +211,19 @@ void TestUtilLite::ExpectAllFieldsSet(
EXPECT_TRUE(message.has_optional_string ());
EXPECT_TRUE(message.has_optional_bytes ());
- EXPECT_TRUE(message.has_optionalgroup ());
- EXPECT_TRUE(message.has_optional_nested_message ());
- EXPECT_TRUE(message.has_optional_foreign_message());
- EXPECT_TRUE(message.has_optional_import_message ());
+ EXPECT_TRUE(message.has_optionalgroup ());
+ EXPECT_TRUE(message.has_optional_nested_message ());
+ EXPECT_TRUE(message.has_optional_foreign_message ());
+ EXPECT_TRUE(message.has_optional_import_message ());
+ EXPECT_TRUE(message.has_optional_public_import_message());
+ EXPECT_TRUE(message.has_optional_lazy_message ());
- EXPECT_TRUE(message.optionalgroup ().has_a());
- EXPECT_TRUE(message.optional_nested_message ().has_bb());
- EXPECT_TRUE(message.optional_foreign_message().has_c());
- EXPECT_TRUE(message.optional_import_message ().has_d());
+ EXPECT_TRUE(message.optionalgroup ().has_a());
+ EXPECT_TRUE(message.optional_nested_message ().has_bb());
+ EXPECT_TRUE(message.optional_foreign_message ().has_c());
+ EXPECT_TRUE(message.optional_import_message ().has_d());
+ EXPECT_TRUE(message.optional_public_import_message().has_e());
+ EXPECT_TRUE(message.optional_lazy_message ().has_bb());
EXPECT_TRUE(message.has_optional_nested_enum ());
EXPECT_TRUE(message.has_optional_foreign_enum());
@@ -232,10 +246,12 @@ void TestUtilLite::ExpectAllFieldsSet(
EXPECT_EQ("115", message.optional_string ());
EXPECT_EQ("116", message.optional_bytes ());
- EXPECT_EQ(117, message.optionalgroup ().a());
- EXPECT_EQ(118, message.optional_nested_message ().bb());
- EXPECT_EQ(119, message.optional_foreign_message().c());
- EXPECT_EQ(120, message.optional_import_message ().d());
+ EXPECT_EQ(117, message.optionalgroup ().a());
+ EXPECT_EQ(118, message.optional_nested_message ().bb());
+ EXPECT_EQ(119, message.optional_foreign_message ().c());
+ EXPECT_EQ(120, message.optional_import_message ().d());
+ EXPECT_EQ(126, message.optional_public_import_message().e());
+ EXPECT_EQ(127, message.optional_lazy_message ().bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAZ , message.optional_nested_enum ());
EXPECT_EQ(unittest::FOREIGN_LITE_BAZ , message.optional_foreign_enum());
@@ -264,6 +280,7 @@ void TestUtilLite::ExpectAllFieldsSet(
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_lazy_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -289,6 +306,7 @@ void TestUtilLite::ExpectAllFieldsSet(
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(227, message.repeated_lazy_message (0).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAR , message.repeated_nested_enum (0));
@@ -315,6 +333,7 @@ void TestUtilLite::ExpectAllFieldsSet(
EXPECT_EQ(318, message.repeated_nested_message (1).bb());
EXPECT_EQ(319, message.repeated_foreign_message(1).c());
EXPECT_EQ(320, message.repeated_import_message (1).d());
+ EXPECT_EQ(327, message.repeated_lazy_message (1).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAZ , message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_LITE_BAZ , message.repeated_foreign_enum(1));
@@ -364,6 +383,13 @@ void TestUtilLite::ExpectAllFieldsSet(
EXPECT_EQ(unittest::FOREIGN_LITE_FOO , message.default_foreign_enum());
EXPECT_EQ(unittest_import::IMPORT_LITE_FOO, message.default_import_enum ());
+
+ EXPECT_FALSE(message.has_oneof_uint32 ());
+ EXPECT_FALSE(message.has_oneof_nested_message());
+ EXPECT_FALSE(message.has_oneof_string ());
+ EXPECT_TRUE(message.has_oneof_bytes ());
+
+ EXPECT_EQ("604", message.oneof_bytes());
}
// -------------------------------------------------------------------
@@ -386,10 +412,12 @@ void TestUtilLite::ExpectClear(const unittest::TestAllTypesLite& message) {
EXPECT_FALSE(message.has_optional_string ());
EXPECT_FALSE(message.has_optional_bytes ());
- EXPECT_FALSE(message.has_optionalgroup ());
- EXPECT_FALSE(message.has_optional_nested_message ());
- EXPECT_FALSE(message.has_optional_foreign_message());
- EXPECT_FALSE(message.has_optional_import_message ());
+ EXPECT_FALSE(message.has_optionalgroup ());
+ EXPECT_FALSE(message.has_optional_nested_message ());
+ EXPECT_FALSE(message.has_optional_foreign_message ());
+ EXPECT_FALSE(message.has_optional_import_message ());
+ EXPECT_FALSE(message.has_optional_public_import_message());
+ EXPECT_FALSE(message.has_optional_lazy_message ());
EXPECT_FALSE(message.has_optional_nested_enum ());
EXPECT_FALSE(message.has_optional_foreign_enum());
@@ -414,10 +442,12 @@ void TestUtilLite::ExpectClear(const unittest::TestAllTypesLite& message) {
EXPECT_EQ("" , message.optional_bytes ());
// Embedded messages should also be clear.
- EXPECT_FALSE(message.optionalgroup ().has_a());
- EXPECT_FALSE(message.optional_nested_message ().has_bb());
- EXPECT_FALSE(message.optional_foreign_message().has_c());
- EXPECT_FALSE(message.optional_import_message ().has_d());
+ EXPECT_FALSE(message.optionalgroup ().has_a());
+ EXPECT_FALSE(message.optional_nested_message ().has_bb());
+ EXPECT_FALSE(message.optional_foreign_message ().has_c());
+ EXPECT_FALSE(message.optional_import_message ().has_d());
+ EXPECT_FALSE(message.optional_public_import_message().has_e());
+ EXPECT_FALSE(message.optional_lazy_message ().has_bb());
EXPECT_EQ(0, message.optionalgroup ().a());
EXPECT_EQ(0, message.optional_nested_message ().bb());
@@ -451,6 +481,7 @@ void TestUtilLite::ExpectClear(const unittest::TestAllTypesLite& message) {
EXPECT_EQ(0, message.repeated_nested_message_size ());
EXPECT_EQ(0, message.repeated_foreign_message_size());
EXPECT_EQ(0, message.repeated_import_message_size ());
+ EXPECT_EQ(0, message.repeated_lazy_message_size ());
EXPECT_EQ(0, message.repeated_nested_enum_size ());
EXPECT_EQ(0, message.repeated_foreign_enum_size ());
EXPECT_EQ(0, message.repeated_import_enum_size ());
@@ -499,6 +530,11 @@ void TestUtilLite::ExpectClear(const unittest::TestAllTypesLite& message) {
EXPECT_EQ(unittest::FOREIGN_LITE_BAR , message.default_foreign_enum());
EXPECT_EQ(unittest_import::IMPORT_LITE_BAR, message.default_import_enum ());
+
+ EXPECT_FALSE(message.has_oneof_uint32 ());
+ EXPECT_FALSE(message.has_oneof_nested_message());
+ EXPECT_FALSE(message.has_oneof_string ());
+ EXPECT_FALSE(message.has_oneof_bytes ());
}
// -------------------------------------------------------------------
@@ -528,6 +564,7 @@ void TestUtilLite::ExpectRepeatedFieldsModified(
ASSERT_EQ(2, message.repeated_nested_message_size ());
ASSERT_EQ(2, message.repeated_foreign_message_size());
ASSERT_EQ(2, message.repeated_import_message_size ());
+ ASSERT_EQ(2, message.repeated_lazy_message_size ());
ASSERT_EQ(2, message.repeated_nested_enum_size ());
ASSERT_EQ(2, message.repeated_foreign_enum_size ());
ASSERT_EQ(2, message.repeated_import_enum_size ());
@@ -553,6 +590,7 @@ void TestUtilLite::ExpectRepeatedFieldsModified(
EXPECT_EQ(218, message.repeated_nested_message (0).bb());
EXPECT_EQ(219, message.repeated_foreign_message(0).c());
EXPECT_EQ(220, message.repeated_import_message (0).d());
+ EXPECT_EQ(227, message.repeated_lazy_message (0).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAR , message.repeated_nested_enum (0));
EXPECT_EQ(unittest::FOREIGN_LITE_BAR , message.repeated_foreign_enum(0));
@@ -580,6 +618,7 @@ void TestUtilLite::ExpectRepeatedFieldsModified(
EXPECT_EQ(518, message.repeated_nested_message (1).bb());
EXPECT_EQ(519, message.repeated_foreign_message(1).c());
EXPECT_EQ(520, message.repeated_import_message (1).d());
+ EXPECT_EQ(527, message.repeated_lazy_message (1).bb());
EXPECT_EQ(unittest::TestAllTypesLite::FOO , message.repeated_nested_enum (1));
EXPECT_EQ(unittest::FOREIGN_LITE_FOO , message.repeated_foreign_enum(1));
@@ -787,10 +826,12 @@ void TestUtilLite::SetAllExtensions(unittest::TestAllExtensionsLite* message) {
message->SetExtension(unittest::optional_string_extension_lite , "115");
message->SetExtension(unittest::optional_bytes_extension_lite , "116");
- message->MutableExtension(unittest::optionalgroup_extension_lite )->set_a(117);
- message->MutableExtension(unittest::optional_nested_message_extension_lite )->set_bb(118);
- message->MutableExtension(unittest::optional_foreign_message_extension_lite)->set_c(119);
- message->MutableExtension(unittest::optional_import_message_extension_lite )->set_d(120);
+ message->MutableExtension(unittest::optionalgroup_extension_lite )->set_a(117);
+ message->MutableExtension(unittest::optional_nested_message_extension_lite )->set_bb(118);
+ message->MutableExtension(unittest::optional_foreign_message_extension_lite )->set_c(119);
+ message->MutableExtension(unittest::optional_import_message_extension_lite )->set_d(120);
+ message->MutableExtension(unittest::optional_public_import_message_extension_lite)->set_e(126);
+ message->MutableExtension(unittest::optional_lazy_message_extension_lite )->set_bb(127);
message->SetExtension(unittest::optional_nested_enum_extension_lite , unittest::TestAllTypesLite::BAZ );
message->SetExtension(unittest::optional_foreign_enum_extension_lite, unittest::FOREIGN_LITE_BAZ );
@@ -819,6 +860,7 @@ void TestUtilLite::SetAllExtensions(unittest::TestAllExtensionsLite* message) {
message->AddExtension(unittest::repeated_nested_message_extension_lite )->set_bb(218);
message->AddExtension(unittest::repeated_foreign_message_extension_lite)->set_c(219);
message->AddExtension(unittest::repeated_import_message_extension_lite )->set_d(220);
+ message->AddExtension(unittest::repeated_lazy_message_extension_lite )->set_bb(227);
message->AddExtension(unittest::repeated_nested_enum_extension_lite , unittest::TestAllTypesLite::BAR );
message->AddExtension(unittest::repeated_foreign_enum_extension_lite, unittest::FOREIGN_LITE_BAR );
@@ -846,6 +888,7 @@ void TestUtilLite::SetAllExtensions(unittest::TestAllExtensionsLite* message) {
message->AddExtension(unittest::repeated_nested_message_extension_lite )->set_bb(318);
message->AddExtension(unittest::repeated_foreign_message_extension_lite)->set_c(319);
message->AddExtension(unittest::repeated_import_message_extension_lite )->set_d(320);
+ message->AddExtension(unittest::repeated_lazy_message_extension_lite )->set_bb(327);
message->AddExtension(unittest::repeated_nested_enum_extension_lite , unittest::TestAllTypesLite::BAZ );
message->AddExtension(unittest::repeated_foreign_enum_extension_lite, unittest::FOREIGN_LITE_BAZ );
@@ -874,6 +917,11 @@ void TestUtilLite::SetAllExtensions(unittest::TestAllExtensionsLite* message) {
message->SetExtension(unittest::default_foreign_enum_extension_lite, unittest::FOREIGN_LITE_FOO );
message->SetExtension(unittest::default_import_enum_extension_lite , unittest_import::IMPORT_LITE_FOO);
+
+ message->SetExtension(unittest::oneof_uint32_extension_lite, 601);
+ message->MutableExtension(unittest::oneof_nested_message_extension_lite)->set_bb(602);;
+ message->SetExtension(unittest::oneof_string_extension_lite, "603");
+ message->SetExtension(unittest::oneof_bytes_extension_lite, "604");
}
// -------------------------------------------------------------------
@@ -900,6 +948,7 @@ void TestUtilLite::ModifyRepeatedExtensions(
message->MutableExtension(unittest::repeated_nested_message_extension_lite , 1)->set_bb(518);
message->MutableExtension(unittest::repeated_foreign_message_extension_lite, 1)->set_c(519);
message->MutableExtension(unittest::repeated_import_message_extension_lite , 1)->set_d(520);
+ message->MutableExtension(unittest::repeated_lazy_message_extension_lite , 1)->set_bb(527);
message->SetExtension(unittest::repeated_nested_enum_extension_lite , 1, unittest::TestAllTypesLite::FOO );
message->SetExtension(unittest::repeated_foreign_enum_extension_lite, 1, unittest::FOREIGN_LITE_FOO );
@@ -927,15 +976,19 @@ void TestUtilLite::ExpectAllExtensionsSet(
EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension_lite ));
EXPECT_TRUE(message.HasExtension(unittest::optional_bytes_extension_lite ));
- EXPECT_TRUE(message.HasExtension(unittest::optionalgroup_extension_lite ));
- EXPECT_TRUE(message.HasExtension(unittest::optional_nested_message_extension_lite ));
- EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_message_extension_lite));
- EXPECT_TRUE(message.HasExtension(unittest::optional_import_message_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optionalgroup_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_nested_message_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_message_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_import_message_extension_lite ));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_public_import_message_extension_lite));
+ EXPECT_TRUE(message.HasExtension(unittest::optional_lazy_message_extension_lite ));
- EXPECT_TRUE(message.GetExtension(unittest::optionalgroup_extension_lite ).has_a());
- EXPECT_TRUE(message.GetExtension(unittest::optional_nested_message_extension_lite ).has_bb());
- EXPECT_TRUE(message.GetExtension(unittest::optional_foreign_message_extension_lite).has_c());
- EXPECT_TRUE(message.GetExtension(unittest::optional_import_message_extension_lite ).has_d());
+ EXPECT_TRUE(message.GetExtension(unittest::optionalgroup_extension_lite ).has_a());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_nested_message_extension_lite ).has_bb());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_foreign_message_extension_lite ).has_c());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_import_message_extension_lite ).has_d());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_public_import_message_extension_lite).has_e());
+ EXPECT_TRUE(message.GetExtension(unittest::optional_lazy_message_extension_lite ).has_bb());
EXPECT_TRUE(message.HasExtension(unittest::optional_nested_enum_extension_lite ));
EXPECT_TRUE(message.HasExtension(unittest::optional_foreign_enum_extension_lite));
@@ -958,10 +1011,12 @@ void TestUtilLite::ExpectAllExtensionsSet(
EXPECT_EQ("115", message.GetExtension(unittest::optional_string_extension_lite ));
EXPECT_EQ("116", message.GetExtension(unittest::optional_bytes_extension_lite ));
- EXPECT_EQ(117, message.GetExtension(unittest::optionalgroup_extension_lite ).a());
- EXPECT_EQ(118, message.GetExtension(unittest::optional_nested_message_extension_lite ).bb());
- EXPECT_EQ(119, message.GetExtension(unittest::optional_foreign_message_extension_lite).c());
- EXPECT_EQ(120, message.GetExtension(unittest::optional_import_message_extension_lite ).d());
+ EXPECT_EQ(117, message.GetExtension(unittest::optionalgroup_extension_lite ).a());
+ EXPECT_EQ(118, message.GetExtension(unittest::optional_nested_message_extension_lite ).bb());
+ EXPECT_EQ(119, message.GetExtension(unittest::optional_foreign_message_extension_lite ).c());
+ EXPECT_EQ(120, message.GetExtension(unittest::optional_import_message_extension_lite ).d());
+ EXPECT_EQ(126, message.GetExtension(unittest::optional_public_import_message_extension_lite).e());
+ EXPECT_EQ(127, message.GetExtension(unittest::optional_lazy_message_extension_lite ).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAZ , message.GetExtension(unittest::optional_nested_enum_extension_lite ));
EXPECT_EQ(unittest::FOREIGN_LITE_BAZ , message.GetExtension(unittest::optional_foreign_enum_extension_lite));
@@ -990,6 +1045,7 @@ void TestUtilLite::ExpectAllExtensionsSet(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension_lite));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension_lite ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension_lite ));
@@ -1015,6 +1071,7 @@ void TestUtilLite::ExpectAllExtensionsSet(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension_lite , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension_lite, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension_lite , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension_lite , 0).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAR , message.GetExtension(unittest::repeated_nested_enum_extension_lite , 0));
EXPECT_EQ(unittest::FOREIGN_LITE_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 0));
@@ -1041,6 +1098,7 @@ void TestUtilLite::ExpectAllExtensionsSet(
EXPECT_EQ(318, message.GetExtension(unittest::repeated_nested_message_extension_lite , 1).bb());
EXPECT_EQ(319, message.GetExtension(unittest::repeated_foreign_message_extension_lite, 1).c());
EXPECT_EQ(320, message.GetExtension(unittest::repeated_import_message_extension_lite , 1).d());
+ EXPECT_EQ(327, message.GetExtension(unittest::repeated_lazy_message_extension_lite , 1).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAZ , message.GetExtension(unittest::repeated_nested_enum_extension_lite , 1));
EXPECT_EQ(unittest::FOREIGN_LITE_BAZ , message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 1));
@@ -1090,6 +1148,16 @@ void TestUtilLite::ExpectAllExtensionsSet(
EXPECT_EQ(unittest::FOREIGN_LITE_FOO , message.GetExtension(unittest::default_foreign_enum_extension_lite));
EXPECT_EQ(unittest_import::IMPORT_LITE_FOO, message.GetExtension(unittest::default_import_enum_extension_lite ));
+
+ EXPECT_TRUE(message.HasExtension(unittest::oneof_uint32_extension_lite));
+ EXPECT_TRUE(message.GetExtension(unittest::oneof_nested_message_extension_lite).has_bb());
+ EXPECT_TRUE(message.HasExtension(unittest::oneof_string_extension_lite));
+ EXPECT_TRUE(message.HasExtension(unittest::oneof_bytes_extension_lite));
+
+ EXPECT_EQ(601, message.GetExtension(unittest::oneof_uint32_extension_lite));
+ EXPECT_EQ(602, message.GetExtension(unittest::oneof_nested_message_extension_lite).bb());
+ EXPECT_EQ("603", message.GetExtension(unittest::oneof_string_extension_lite));
+ EXPECT_EQ("604", message.GetExtension(unittest::oneof_bytes_extension_lite));
}
// -------------------------------------------------------------------
@@ -1118,10 +1186,12 @@ void TestUtilLite::ExpectExtensionsClear(
EXPECT_FALSE(message.HasExtension(unittest::optional_string_extension_lite ));
EXPECT_FALSE(message.HasExtension(unittest::optional_bytes_extension_lite ));
- EXPECT_FALSE(message.HasExtension(unittest::optionalgroup_extension_lite ));
- EXPECT_FALSE(message.HasExtension(unittest::optional_nested_message_extension_lite ));
- EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_message_extension_lite));
- EXPECT_FALSE(message.HasExtension(unittest::optional_import_message_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optionalgroup_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_nested_message_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_message_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_import_message_extension_lite ));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_public_import_message_extension_lite));
+ EXPECT_FALSE(message.HasExtension(unittest::optional_lazy_message_extension_lite ));
EXPECT_FALSE(message.HasExtension(unittest::optional_nested_enum_extension_lite ));
EXPECT_FALSE(message.HasExtension(unittest::optional_foreign_enum_extension_lite));
@@ -1146,15 +1216,19 @@ void TestUtilLite::ExpectExtensionsClear(
EXPECT_EQ("" , message.GetExtension(unittest::optional_bytes_extension_lite ));
// Embedded messages should also be clear.
- EXPECT_FALSE(message.GetExtension(unittest::optionalgroup_extension_lite ).has_a());
- EXPECT_FALSE(message.GetExtension(unittest::optional_nested_message_extension_lite ).has_bb());
- EXPECT_FALSE(message.GetExtension(unittest::optional_foreign_message_extension_lite).has_c());
- EXPECT_FALSE(message.GetExtension(unittest::optional_import_message_extension_lite ).has_d());
-
- EXPECT_EQ(0, message.GetExtension(unittest::optionalgroup_extension_lite ).a());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_nested_message_extension_lite ).bb());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_foreign_message_extension_lite).c());
- EXPECT_EQ(0, message.GetExtension(unittest::optional_import_message_extension_lite ).d());
+ EXPECT_FALSE(message.GetExtension(unittest::optionalgroup_extension_lite ).has_a());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_nested_message_extension_lite ).has_bb());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_foreign_message_extension_lite ).has_c());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_import_message_extension_lite ).has_d());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_public_import_message_extension_lite).has_e());
+ EXPECT_FALSE(message.GetExtension(unittest::optional_lazy_message_extension_lite ).has_bb());
+
+ EXPECT_EQ(0, message.GetExtension(unittest::optionalgroup_extension_lite ).a());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_nested_message_extension_lite ).bb());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_foreign_message_extension_lite ).c());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_import_message_extension_lite ).d());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_public_import_message_extension_lite).e());
+ EXPECT_EQ(0, message.GetExtension(unittest::optional_lazy_message_extension_lite ).bb());
// Enums without defaults are set to the first value in the enum.
EXPECT_EQ(unittest::TestAllTypesLite::FOO , message.GetExtension(unittest::optional_nested_enum_extension_lite ));
@@ -1183,6 +1257,7 @@ void TestUtilLite::ExpectExtensionsClear(
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_nested_message_extension_lite ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_foreign_message_extension_lite));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_import_message_extension_lite ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_lazy_message_extension_lite ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_nested_enum_extension_lite ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_foreign_enum_extension_lite ));
EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_import_enum_extension_lite ));
@@ -1231,6 +1306,11 @@ void TestUtilLite::ExpectExtensionsClear(
EXPECT_EQ(unittest::FOREIGN_LITE_BAR , message.GetExtension(unittest::default_foreign_enum_extension_lite));
EXPECT_EQ(unittest_import::IMPORT_LITE_BAR, message.GetExtension(unittest::default_import_enum_extension_lite ));
+
+ EXPECT_FALSE(message.HasExtension(unittest::oneof_uint32_extension_lite));
+ EXPECT_FALSE(message.GetExtension(unittest::oneof_nested_message_extension_lite).has_bb());
+ EXPECT_FALSE(message.HasExtension(unittest::oneof_string_extension_lite));
+ EXPECT_FALSE(message.HasExtension(unittest::oneof_bytes_extension_lite));
}
// -------------------------------------------------------------------
@@ -1260,6 +1340,7 @@ void TestUtilLite::ExpectRepeatedExtensionsModified(
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension_lite));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension_lite ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_lazy_message_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension_lite ));
ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension_lite ));
@@ -1285,6 +1366,7 @@ void TestUtilLite::ExpectRepeatedExtensionsModified(
EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension_lite , 0).bb());
EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension_lite, 0).c());
EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension_lite , 0).d());
+ EXPECT_EQ(227, message.GetExtension(unittest::repeated_lazy_message_extension_lite , 0).bb());
EXPECT_EQ(unittest::TestAllTypesLite::BAR , message.GetExtension(unittest::repeated_nested_enum_extension_lite , 0));
EXPECT_EQ(unittest::FOREIGN_LITE_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 0));
@@ -1312,6 +1394,7 @@ void TestUtilLite::ExpectRepeatedExtensionsModified(
EXPECT_EQ(518, message.GetExtension(unittest::repeated_nested_message_extension_lite , 1).bb());
EXPECT_EQ(519, message.GetExtension(unittest::repeated_foreign_message_extension_lite, 1).c());
EXPECT_EQ(520, message.GetExtension(unittest::repeated_import_message_extension_lite , 1).d());
+ EXPECT_EQ(527, message.GetExtension(unittest::repeated_lazy_message_extension_lite , 1).bb());
EXPECT_EQ(unittest::TestAllTypesLite::FOO , message.GetExtension(unittest::repeated_nested_enum_extension_lite , 1));
EXPECT_EQ(unittest::FOREIGN_LITE_FOO , message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 1));
diff --git a/src/google/protobuf/test_util_lite.h b/src/google/protobuf/test_util_lite.h
index ca35aaa4..f250c937 100644
--- a/src/google/protobuf/test_util_lite.h
+++ b/src/google/protobuf/test_util_lite.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/testdata/bad_utf8_string b/src/google/protobuf/testdata/bad_utf8_string
new file mode 100644
index 00000000..a1337ec6
--- /dev/null
+++ b/src/google/protobuf/testdata/bad_utf8_string
@@ -0,0 +1 @@
+rÿ \ No newline at end of file
diff --git a/src/google/protobuf/testdata/golden_message b/src/google/protobuf/testdata/golden_message
index 94898e49..0b7e6552 100644
--- a/src/google/protobuf/testdata/golden_message
+++ b/src/google/protobuf/testdata/golden_message
Binary files differ
diff --git a/src/google/protobuf/testdata/golden_message_oneof_implemented b/src/google/protobuf/testdata/golden_message_oneof_implemented
new file mode 100644
index 00000000..b48c8985
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_message_oneof_implemented
Binary files differ
diff --git a/src/google/protobuf/testdata/golden_message_proto3 b/src/google/protobuf/testdata/golden_message_proto3
new file mode 100644
index 00000000..934f36fa
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_message_proto3
Binary files differ
diff --git a/src/google/protobuf/testdata/text_format_unittest_data.txt b/src/google/protobuf/testdata/text_format_unittest_data.txt
index feea8f7b..7a874b54 100644
--- a/src/google/protobuf/testdata/text_format_unittest_data.txt
+++ b/src/google/protobuf/testdata/text_format_unittest_data.txt
@@ -30,6 +30,12 @@ optional_foreign_enum: FOREIGN_BAZ
optional_import_enum: IMPORT_BAZ
optional_string_piece: "124"
optional_cord: "125"
+optional_public_import_message {
+ e: 126
+}
+optional_lazy_message {
+ bb: 127
+}
repeated_int32: 201
repeated_int32: 301
repeated_int64: 202
@@ -94,6 +100,12 @@ repeated_string_piece: "224"
repeated_string_piece: "324"
repeated_cord: "225"
repeated_cord: "325"
+repeated_lazy_message {
+ bb: 227
+}
+repeated_lazy_message {
+ bb: 327
+}
default_int32: 401
default_int64: 402
default_uint32: 403
@@ -114,3 +126,9 @@ default_foreign_enum: FOREIGN_FOO
default_import_enum: IMPORT_FOO
default_string_piece: "424"
default_cord: "425"
+oneof_uint32: 601
+oneof_nested_message {
+ bb: 602
+}
+oneof_string: "603"
+oneof_bytes: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt b/src/google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt
new file mode 100644
index 00000000..ec95e1e8
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt
@@ -0,0 +1,129 @@
+optional_int32: 101
+optional_int64: 102
+optional_uint32: 103
+optional_uint64: 104
+optional_sint32: 105
+optional_sint64: 106
+optional_fixed32: 107
+optional_fixed64: 108
+optional_sfixed32: 109
+optional_sfixed64: 110
+optional_float: 111
+optional_double: 112
+optional_bool: true
+optional_string: "115"
+optional_bytes: "116"
+OptionalGroup {
+ a: 117
+}
+optional_nested_message {
+ bb: 118
+}
+optional_foreign_message {
+ c: 119
+}
+optional_import_message {
+ d: 120
+}
+optional_nested_enum: BAZ
+optional_foreign_enum: FOREIGN_BAZ
+optional_import_enum: IMPORT_BAZ
+optional_string_piece: "124"
+optional_cord: "125"
+optional_public_import_message {
+ e: 126
+}
+optional_lazy_message {
+ bb: 127
+}
+repeated_int32: 201
+repeated_int32: 301
+repeated_int64: 202
+repeated_int64: 302
+repeated_uint32: 203
+repeated_uint32: 303
+repeated_uint64: 204
+repeated_uint64: 304
+repeated_sint32: 205
+repeated_sint32: 305
+repeated_sint64: 206
+repeated_sint64: 306
+repeated_fixed32: 207
+repeated_fixed32: 307
+repeated_fixed64: 208
+repeated_fixed64: 308
+repeated_sfixed32: 209
+repeated_sfixed32: 309
+repeated_sfixed64: 210
+repeated_sfixed64: 310
+repeated_float: 211
+repeated_float: 311
+repeated_double: 212
+repeated_double: 312
+repeated_bool: true
+repeated_bool: false
+repeated_string: "215"
+repeated_string: "315"
+repeated_bytes: "216"
+repeated_bytes: "316"
+RepeatedGroup {
+ a: 217
+}
+RepeatedGroup {
+ a: 317
+}
+repeated_nested_message {
+ bb: 218
+}
+repeated_nested_message {
+ bb: 318
+}
+repeated_foreign_message {
+ c: 219
+}
+repeated_foreign_message {
+ c: 319
+}
+repeated_import_message {
+ d: 220
+}
+repeated_import_message {
+ d: 320
+}
+repeated_nested_enum: BAR
+repeated_nested_enum: BAZ
+repeated_foreign_enum: FOREIGN_BAR
+repeated_foreign_enum: FOREIGN_BAZ
+repeated_import_enum: IMPORT_BAR
+repeated_import_enum: IMPORT_BAZ
+repeated_string_piece: "224"
+repeated_string_piece: "324"
+repeated_cord: "225"
+repeated_cord: "325"
+repeated_lazy_message {
+ bb: 227
+}
+repeated_lazy_message {
+ bb: 327
+}
+default_int32: 401
+default_int64: 402
+default_uint32: 403
+default_uint64: 404
+default_sint32: 405
+default_sint64: 406
+default_fixed32: 407
+default_fixed64: 408
+default_sfixed32: 409
+default_sfixed64: 410
+default_float: 411
+default_double: 412
+default_bool: false
+default_string: "415"
+default_bytes: "416"
+default_nested_enum: FOO
+default_foreign_enum: FOREIGN_FOO
+default_import_enum: IMPORT_FOO
+default_string_piece: "424"
+default_cord: "425"
+oneof_bytes: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_data_pointy.txt b/src/google/protobuf/testdata/text_format_unittest_data_pointy.txt
new file mode 100644
index 00000000..e1011ebf
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_data_pointy.txt
@@ -0,0 +1,134 @@
+optional_int32: 101
+optional_int64: 102
+optional_uint32: 103
+optional_uint64: 104
+optional_sint32: 105
+optional_sint64: 106
+optional_fixed32: 107
+optional_fixed64: 108
+optional_sfixed32: 109
+optional_sfixed64: 110
+optional_float: 111
+optional_double: 112
+optional_bool: true
+optional_string: "115"
+optional_bytes: "116"
+OptionalGroup <
+ a: 117
+>
+optional_nested_message <
+ bb: 118
+>
+optional_foreign_message <
+ c: 119
+>
+optional_import_message <
+ d: 120
+>
+optional_nested_enum: BAZ
+optional_foreign_enum: FOREIGN_BAZ
+optional_import_enum: IMPORT_BAZ
+optional_string_piece: "124"
+optional_cord: "125"
+optional_public_import_message <
+ e: 126
+>
+optional_lazy_message <
+ bb: 127
+>
+repeated_int32: 201
+repeated_int32: 301
+repeated_int64: 202
+repeated_int64: 302
+repeated_uint32: 203
+repeated_uint32: 303
+repeated_uint64: 204
+repeated_uint64: 304
+repeated_sint32: 205
+repeated_sint32: 305
+repeated_sint64: 206
+repeated_sint64: 306
+repeated_fixed32: 207
+repeated_fixed32: 307
+repeated_fixed64: 208
+repeated_fixed64: 308
+repeated_sfixed32: 209
+repeated_sfixed32: 309
+repeated_sfixed64: 210
+repeated_sfixed64: 310
+repeated_float: 211
+repeated_float: 311
+repeated_double: 212
+repeated_double: 312
+repeated_bool: true
+repeated_bool: false
+repeated_string: "215"
+repeated_string: "315"
+repeated_bytes: "216"
+repeated_bytes: "316"
+RepeatedGroup <
+ a: 217
+>
+RepeatedGroup <
+ a: 317
+>
+repeated_nested_message <
+ bb: 218
+>
+repeated_nested_message <
+ bb: 318
+>
+repeated_foreign_message <
+ c: 219
+>
+repeated_foreign_message <
+ c: 319
+>
+repeated_import_message <
+ d: 220
+>
+repeated_import_message <
+ d: 320
+>
+repeated_nested_enum: BAR
+repeated_nested_enum: BAZ
+repeated_foreign_enum: FOREIGN_BAR
+repeated_foreign_enum: FOREIGN_BAZ
+repeated_import_enum: IMPORT_BAR
+repeated_import_enum: IMPORT_BAZ
+repeated_string_piece: "224"
+repeated_string_piece: "324"
+repeated_cord: "225"
+repeated_cord: "325"
+repeated_lazy_message <
+ bb: 227
+>
+repeated_lazy_message <
+ bb: 327
+>
+default_int32: 401
+default_int64: 402
+default_uint32: 403
+default_uint64: 404
+default_sint32: 405
+default_sint64: 406
+default_fixed32: 407
+default_fixed64: 408
+default_sfixed32: 409
+default_sfixed64: 410
+default_float: 411
+default_double: 412
+default_bool: false
+default_string: "415"
+default_bytes: "416"
+default_nested_enum: FOO
+default_foreign_enum: FOREIGN_FOO
+default_import_enum: IMPORT_FOO
+default_string_piece: "424"
+default_cord: "425"
+oneof_uint32: 601
+oneof_nested_message <
+ bb: 602
+>
+oneof_string: "603"
+oneof_bytes: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt b/src/google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt
new file mode 100644
index 00000000..95109f62
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt
@@ -0,0 +1,129 @@
+optional_int32: 101
+optional_int64: 102
+optional_uint32: 103
+optional_uint64: 104
+optional_sint32: 105
+optional_sint64: 106
+optional_fixed32: 107
+optional_fixed64: 108
+optional_sfixed32: 109
+optional_sfixed64: 110
+optional_float: 111
+optional_double: 112
+optional_bool: true
+optional_string: "115"
+optional_bytes: "116"
+OptionalGroup <
+ a: 117
+>
+optional_nested_message <
+ bb: 118
+>
+optional_foreign_message <
+ c: 119
+>
+optional_import_message <
+ d: 120
+>
+optional_nested_enum: BAZ
+optional_foreign_enum: FOREIGN_BAZ
+optional_import_enum: IMPORT_BAZ
+optional_string_piece: "124"
+optional_cord: "125"
+optional_public_import_message <
+ e: 126
+>
+optional_lazy_message <
+ bb: 127
+>
+repeated_int32: 201
+repeated_int32: 301
+repeated_int64: 202
+repeated_int64: 302
+repeated_uint32: 203
+repeated_uint32: 303
+repeated_uint64: 204
+repeated_uint64: 304
+repeated_sint32: 205
+repeated_sint32: 305
+repeated_sint64: 206
+repeated_sint64: 306
+repeated_fixed32: 207
+repeated_fixed32: 307
+repeated_fixed64: 208
+repeated_fixed64: 308
+repeated_sfixed32: 209
+repeated_sfixed32: 309
+repeated_sfixed64: 210
+repeated_sfixed64: 310
+repeated_float: 211
+repeated_float: 311
+repeated_double: 212
+repeated_double: 312
+repeated_bool: true
+repeated_bool: false
+repeated_string: "215"
+repeated_string: "315"
+repeated_bytes: "216"
+repeated_bytes: "316"
+RepeatedGroup <
+ a: 217
+>
+RepeatedGroup <
+ a: 317
+>
+repeated_nested_message <
+ bb: 218
+>
+repeated_nested_message <
+ bb: 318
+>
+repeated_foreign_message <
+ c: 219
+>
+repeated_foreign_message <
+ c: 319
+>
+repeated_import_message <
+ d: 220
+>
+repeated_import_message <
+ d: 320
+>
+repeated_nested_enum: BAR
+repeated_nested_enum: BAZ
+repeated_foreign_enum: FOREIGN_BAR
+repeated_foreign_enum: FOREIGN_BAZ
+repeated_import_enum: IMPORT_BAR
+repeated_import_enum: IMPORT_BAZ
+repeated_string_piece: "224"
+repeated_string_piece: "324"
+repeated_cord: "225"
+repeated_cord: "325"
+repeated_lazy_message <
+ bb: 227
+>
+repeated_lazy_message <
+ bb: 327
+>
+default_int32: 401
+default_int64: 402
+default_uint32: 403
+default_uint64: 404
+default_sint32: 405
+default_sint64: 406
+default_fixed32: 407
+default_fixed64: 408
+default_sfixed32: 409
+default_sfixed64: 410
+default_float: 411
+default_double: 412
+default_bool: false
+default_string: "415"
+default_bytes: "416"
+default_nested_enum: FOO
+default_foreign_enum: FOREIGN_FOO
+default_import_enum: IMPORT_FOO
+default_string_piece: "424"
+default_cord: "425"
+oneof_bytes: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt b/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
index 057beae8..8c8b1eb4 100644
--- a/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
+++ b/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
@@ -30,6 +30,12 @@
[protobuf_unittest.optional_import_enum_extension]: IMPORT_BAZ
[protobuf_unittest.optional_string_piece_extension]: "124"
[protobuf_unittest.optional_cord_extension]: "125"
+[protobuf_unittest.optional_public_import_message_extension] {
+ e: 126
+}
+[protobuf_unittest.optional_lazy_message_extension] {
+ bb: 127
+}
[protobuf_unittest.repeated_int32_extension]: 201
[protobuf_unittest.repeated_int32_extension]: 301
[protobuf_unittest.repeated_int64_extension]: 202
@@ -94,6 +100,12 @@
[protobuf_unittest.repeated_string_piece_extension]: "324"
[protobuf_unittest.repeated_cord_extension]: "225"
[protobuf_unittest.repeated_cord_extension]: "325"
+[protobuf_unittest.repeated_lazy_message_extension] {
+ bb: 227
+}
+[protobuf_unittest.repeated_lazy_message_extension] {
+ bb: 327
+}
[protobuf_unittest.default_int32_extension]: 401
[protobuf_unittest.default_int64_extension]: 402
[protobuf_unittest.default_uint32_extension]: 403
@@ -114,3 +126,9 @@
[protobuf_unittest.default_import_enum_extension]: IMPORT_FOO
[protobuf_unittest.default_string_piece_extension]: "424"
[protobuf_unittest.default_cord_extension]: "425"
+[protobuf_unittest.oneof_uint32_extension]: 601
+[protobuf_unittest.oneof_nested_message_extension] {
+ bb: 602
+}
+[protobuf_unittest.oneof_string_extension]: "603"
+[protobuf_unittest.oneof_bytes_extension]: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt b/src/google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt
new file mode 100644
index 00000000..132f7445
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt
@@ -0,0 +1,134 @@
+[protobuf_unittest.optional_int32_extension]: 101
+[protobuf_unittest.optional_int64_extension]: 102
+[protobuf_unittest.optional_uint32_extension]: 103
+[protobuf_unittest.optional_uint64_extension]: 104
+[protobuf_unittest.optional_sint32_extension]: 105
+[protobuf_unittest.optional_sint64_extension]: 106
+[protobuf_unittest.optional_fixed32_extension]: 107
+[protobuf_unittest.optional_fixed64_extension]: 108
+[protobuf_unittest.optional_sfixed32_extension]: 109
+[protobuf_unittest.optional_sfixed64_extension]: 110
+[protobuf_unittest.optional_float_extension]: 111
+[protobuf_unittest.optional_double_extension]: 112
+[protobuf_unittest.optional_bool_extension]: true
+[protobuf_unittest.optional_string_extension]: "115"
+[protobuf_unittest.optional_bytes_extension]: "116"
+[protobuf_unittest.optionalgroup_extension] <
+ a: 117
+>
+[protobuf_unittest.optional_nested_message_extension] <
+ bb: 118
+>
+[protobuf_unittest.optional_foreign_message_extension] <
+ c: 119
+>
+[protobuf_unittest.optional_import_message_extension] <
+ d: 120
+>
+[protobuf_unittest.optional_nested_enum_extension]: BAZ
+[protobuf_unittest.optional_foreign_enum_extension]: FOREIGN_BAZ
+[protobuf_unittest.optional_import_enum_extension]: IMPORT_BAZ
+[protobuf_unittest.optional_string_piece_extension]: "124"
+[protobuf_unittest.optional_cord_extension]: "125"
+[protobuf_unittest.optional_public_import_message_extension] <
+ e: 126
+>
+[protobuf_unittest.optional_lazy_message_extension] <
+ bb: 127
+>
+[protobuf_unittest.repeated_int32_extension]: 201
+[protobuf_unittest.repeated_int32_extension]: 301
+[protobuf_unittest.repeated_int64_extension]: 202
+[protobuf_unittest.repeated_int64_extension]: 302
+[protobuf_unittest.repeated_uint32_extension]: 203
+[protobuf_unittest.repeated_uint32_extension]: 303
+[protobuf_unittest.repeated_uint64_extension]: 204
+[protobuf_unittest.repeated_uint64_extension]: 304
+[protobuf_unittest.repeated_sint32_extension]: 205
+[protobuf_unittest.repeated_sint32_extension]: 305
+[protobuf_unittest.repeated_sint64_extension]: 206
+[protobuf_unittest.repeated_sint64_extension]: 306
+[protobuf_unittest.repeated_fixed32_extension]: 207
+[protobuf_unittest.repeated_fixed32_extension]: 307
+[protobuf_unittest.repeated_fixed64_extension]: 208
+[protobuf_unittest.repeated_fixed64_extension]: 308
+[protobuf_unittest.repeated_sfixed32_extension]: 209
+[protobuf_unittest.repeated_sfixed32_extension]: 309
+[protobuf_unittest.repeated_sfixed64_extension]: 210
+[protobuf_unittest.repeated_sfixed64_extension]: 310
+[protobuf_unittest.repeated_float_extension]: 211
+[protobuf_unittest.repeated_float_extension]: 311
+[protobuf_unittest.repeated_double_extension]: 212
+[protobuf_unittest.repeated_double_extension]: 312
+[protobuf_unittest.repeated_bool_extension]: true
+[protobuf_unittest.repeated_bool_extension]: false
+[protobuf_unittest.repeated_string_extension]: "215"
+[protobuf_unittest.repeated_string_extension]: "315"
+[protobuf_unittest.repeated_bytes_extension]: "216"
+[protobuf_unittest.repeated_bytes_extension]: "316"
+[protobuf_unittest.repeatedgroup_extension] <
+ a: 217
+>
+[protobuf_unittest.repeatedgroup_extension] <
+ a: 317
+>
+[protobuf_unittest.repeated_nested_message_extension] <
+ bb: 218
+>
+[protobuf_unittest.repeated_nested_message_extension] <
+ bb: 318
+>
+[protobuf_unittest.repeated_foreign_message_extension] <
+ c: 219
+>
+[protobuf_unittest.repeated_foreign_message_extension] <
+ c: 319
+>
+[protobuf_unittest.repeated_import_message_extension] <
+ d: 220
+>
+[protobuf_unittest.repeated_import_message_extension] <
+ d: 320
+>
+[protobuf_unittest.repeated_nested_enum_extension]: BAR
+[protobuf_unittest.repeated_nested_enum_extension]: BAZ
+[protobuf_unittest.repeated_foreign_enum_extension]: FOREIGN_BAR
+[protobuf_unittest.repeated_foreign_enum_extension]: FOREIGN_BAZ
+[protobuf_unittest.repeated_import_enum_extension]: IMPORT_BAR
+[protobuf_unittest.repeated_import_enum_extension]: IMPORT_BAZ
+[protobuf_unittest.repeated_string_piece_extension]: "224"
+[protobuf_unittest.repeated_string_piece_extension]: "324"
+[protobuf_unittest.repeated_cord_extension]: "225"
+[protobuf_unittest.repeated_cord_extension]: "325"
+[protobuf_unittest.repeated_lazy_message_extension] <
+ bb: 227
+>
+[protobuf_unittest.repeated_lazy_message_extension] <
+ bb: 327
+>
+[protobuf_unittest.default_int32_extension]: 401
+[protobuf_unittest.default_int64_extension]: 402
+[protobuf_unittest.default_uint32_extension]: 403
+[protobuf_unittest.default_uint64_extension]: 404
+[protobuf_unittest.default_sint32_extension]: 405
+[protobuf_unittest.default_sint64_extension]: 406
+[protobuf_unittest.default_fixed32_extension]: 407
+[protobuf_unittest.default_fixed64_extension]: 408
+[protobuf_unittest.default_sfixed32_extension]: 409
+[protobuf_unittest.default_sfixed64_extension]: 410
+[protobuf_unittest.default_float_extension]: 411
+[protobuf_unittest.default_double_extension]: 412
+[protobuf_unittest.default_bool_extension]: false
+[protobuf_unittest.default_string_extension]: "415"
+[protobuf_unittest.default_bytes_extension]: "416"
+[protobuf_unittest.default_nested_enum_extension]: FOO
+[protobuf_unittest.default_foreign_enum_extension]: FOREIGN_FOO
+[protobuf_unittest.default_import_enum_extension]: IMPORT_FOO
+[protobuf_unittest.default_string_piece_extension]: "424"
+[protobuf_unittest.default_cord_extension]: "425"
+[protobuf_unittest.oneof_uint32_extension]: 601
+[protobuf_unittest.oneof_nested_message_extension] <
+ bb: 602
+>
+[protobuf_unittest.oneof_string_extension]: "603"
+[protobuf_unittest.oneof_bytes_extension]: "604"
diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc
index e224781d..3d07b127 100644
--- a/src/google/protobuf/testing/file.cc
+++ b/src/google/protobuf/testing/file.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -82,6 +82,24 @@ void File::ReadFileToStringOrDie(const string& name, string* output) {
GOOGLE_CHECK(ReadFileToString(name, output)) << "Could not read: " << name;
}
+bool File::WriteStringToFile(const string& contents, const string& name) {
+ FILE* file = fopen(name.c_str(), "wb");
+ if (file == NULL) {
+ GOOGLE_LOG(ERROR) << "fopen(" << name << ", \"wb\"): " << strerror(errno);
+ return false;
+ }
+
+ if (fwrite(contents.data(), 1, contents.size(), file) != contents.size()) {
+ GOOGLE_LOG(ERROR) << "fwrite(" << name << "): " << strerror(errno);
+ return false;
+ }
+
+ if (fclose(file) != 0) {
+ return false;
+ }
+ return true;
+}
+
void File::WriteStringToFileOrDie(const string& contents, const string& name) {
FILE* file = fopen(name.c_str(), "wb");
GOOGLE_CHECK(file != NULL)
@@ -115,6 +133,8 @@ bool File::RecursivelyCreateDir(const string& path, int mode) {
void File::DeleteRecursively(const string& name,
void* dummy1, void* dummy2) {
+ if (name.empty()) return;
+
// We don't care too much about error checking here since this is only used
// in tests to delete temporary directories that are under /tmp anyway.
@@ -172,5 +192,9 @@ void File::DeleteRecursively(const string& name,
#endif
}
+bool File::ChangeWorkingDirectory(const string& new_working_directory) {
+ return chdir(new_working_directory.c_str()) == 0;
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/testing/file.h b/src/google/protobuf/testing/file.h
index a6b1c764..2f63f80e 100644
--- a/src/google/protobuf/testing/file.h
+++ b/src/google/protobuf/testing/file.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -56,6 +56,10 @@ class File {
static void ReadFileToStringOrDie(const string& name, string* output);
// Create a file and write a string to it.
+ static bool WriteStringToFile(const string& contents,
+ const string& name);
+
+ // Same as above, but crash on failure.
static void WriteStringToFileOrDie(const string& contents,
const string& name);
@@ -73,6 +77,19 @@ class File {
static void DeleteRecursively(const string& name,
void* dummy1, void* dummy2);
+ // Change working directory to given directory.
+ static bool ChangeWorkingDirectory(const string& new_working_directory);
+
+ static bool GetContents(
+ const string& name, string* output, bool /*is_default*/) {
+ return ReadFileToString(name, output);
+ }
+
+ static bool SetContents(
+ const string& name, const string& contents, bool /*is_default*/) {
+ return WriteStringToFile(contents, name);
+ }
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(File);
};
diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc
index cd094d0c..d72fa5c0 100644
--- a/src/google/protobuf/testing/googletest.cc
+++ b/src/google/protobuf/testing/googletest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -223,16 +223,17 @@ ScopedMemoryLog::~ScopedMemoryLog() {
active_log_ = NULL;
}
-const vector<string>& ScopedMemoryLog::GetMessages(LogLevel dummy) const {
- GOOGLE_CHECK_EQ(dummy, ERROR);
- return messages_;
+const vector<string>& ScopedMemoryLog::GetMessages(LogLevel level) {
+ GOOGLE_CHECK(level == ERROR ||
+ level == WARNING);
+ return messages_[level];
}
void ScopedMemoryLog::HandleLog(LogLevel level, const char* filename,
int line, const string& message) {
GOOGLE_CHECK(active_log_ != NULL);
- if (level == ERROR) {
- active_log_->messages_.push_back(message);
+ if (level == ERROR || level == WARNING) {
+ active_log_->messages_[level].push_back(message);
}
}
diff --git a/src/google/protobuf/testing/googletest.h b/src/google/protobuf/testing/googletest.h
index 71444c96..c0d99e69 100644
--- a/src/google/protobuf/testing/googletest.h
+++ b/src/google/protobuf/testing/googletest.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,9 +34,15 @@
#ifndef GOOGLE_PROTOBUF_GOOGLETEST_H__
#define GOOGLE_PROTOBUF_GOOGLETEST_H__
+#include <map>
#include <vector>
#include <google/protobuf/stubs/common.h>
+// Disable death tests if we use exceptions in CHECK().
+#if !PROTOBUF_USE_EXCEPTIONS && defined(GTEST_HAS_DEATH_TEST)
+#define PROTOBUF_HAS_DEATH_TEST
+#endif
+
namespace google {
namespace protobuf {
@@ -60,6 +66,7 @@ string GetCapturedTestStderr();
// ScopedMemoryLog refers to LOGLEVEL_ERROR as just ERROR.
#undef ERROR // defend against promiscuous windows.h
static const LogLevel ERROR = LOGLEVEL_ERROR;
+static const LogLevel WARNING = LOGLEVEL_WARNING;
// Receives copies of all LOG(ERROR) messages while in scope. Sample usage:
// {
@@ -74,14 +81,11 @@ class ScopedMemoryLog {
ScopedMemoryLog();
virtual ~ScopedMemoryLog();
- // Fetches all messages logged. The internal version of this class
- // would only fetch messages at the given security level, but the protobuf
- // open source version ignores the argument since we always pass ERROR
- // anyway.
- const vector<string>& GetMessages(LogLevel dummy) const;
+ // Fetches all messages with the given severity level.
+ const vector<string>& GetMessages(LogLevel error);
private:
- vector<string> messages_;
+ map<LogLevel, vector<string> > messages_;
LogHandler* old_handler_;
static void HandleLog(LogLevel level, const char* filename, int line,
diff --git a/src/google/protobuf/testing/zcgunzip.cc b/src/google/protobuf/testing/zcgunzip.cc
index a6197854..daf74ff1 100644
--- a/src/google/protobuf/testing/zcgunzip.cc
+++ b/src/google/protobuf/testing/zcgunzip.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2009 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/testing/zcgzip.cc b/src/google/protobuf/testing/zcgzip.cc
index 9133275c..a4101999 100644
--- a/src/google/protobuf/testing/zcgzip.cc
+++ b/src/google/protobuf/testing/zcgzip.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2009 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 1494ebd7..ec070c51 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,6 +32,7 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <algorithm>
#include <float.h>
#include <math.h>
#include <stdio.h>
@@ -42,17 +43,35 @@
#include <google/protobuf/text_format.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
+namespace {
+
+inline bool IsHexNumber(const string& str) {
+ return (str.length() >= 2 && str[0] == '0' &&
+ (str[1] == 'x' || str[1] == 'X'));
+}
+
+inline bool IsOctNumber(const string& str) {
+ return (str.length() >= 2 && str[0] == '0' &&
+ (str[1] >= '0' && str[1] < '8'));
+}
+
+} // namespace
+
string Message::DebugString() const {
string debug_string;
@@ -94,6 +113,73 @@ void Message::PrintDebugString() const {
// ===========================================================================
+// Implementation of the parse information tree class.
+TextFormat::ParseInfoTree::ParseInfoTree() { }
+
+TextFormat::ParseInfoTree::~ParseInfoTree() {
+ // Remove any nested information trees, as they are owned by this tree.
+ for (NestedMap::iterator it = nested_.begin(); it != nested_.end(); ++it) {
+ STLDeleteElements(&(it->second));
+ }
+}
+
+void TextFormat::ParseInfoTree::RecordLocation(
+ const FieldDescriptor* field,
+ TextFormat::ParseLocation location) {
+ locations_[field].push_back(location);
+}
+
+TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::CreateNested(
+ const FieldDescriptor* field) {
+ // Owned by us in the map.
+ TextFormat::ParseInfoTree* instance = new TextFormat::ParseInfoTree();
+ vector<TextFormat::ParseInfoTree*>* trees = &nested_[field];
+ GOOGLE_CHECK(trees);
+ trees->push_back(instance);
+ return instance;
+}
+
+void CheckFieldIndex(const FieldDescriptor* field, int index) {
+ if (field == NULL) { return; }
+
+ if (field->is_repeated() && index == -1) {
+ GOOGLE_LOG(DFATAL) << "Index must be in range of repeated field values. "
+ << "Field: " << field->name();
+ } else if (!field->is_repeated() && index != -1) {
+ GOOGLE_LOG(DFATAL) << "Index must be -1 for singular fields."
+ << "Field: " << field->name();
+ }
+}
+
+TextFormat::ParseLocation TextFormat::ParseInfoTree::GetLocation(
+ const FieldDescriptor* field, int index) const {
+ CheckFieldIndex(field, index);
+ if (index == -1) { index = 0; }
+
+ const vector<TextFormat::ParseLocation>* locations =
+ FindOrNull(locations_, field);
+ if (locations == NULL || index >= locations->size()) {
+ return TextFormat::ParseLocation();
+ }
+
+ return (*locations)[index];
+}
+
+TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::GetTreeForNested(
+ const FieldDescriptor* field, int index) const {
+ CheckFieldIndex(field, index);
+ if (index == -1) { index = 0; }
+
+ const vector<TextFormat::ParseInfoTree*>* trees = FindOrNull(nested_, field);
+ if (trees == NULL || index >= trees->size()) {
+ return NULL;
+ }
+
+ return (*trees)[index];
+}
+
+
+// ===========================================================================
// Internal class for parsing an ASCII representation of a Protocol Message.
// This class makes use of the Protocol Message compiler's tokenizer found
// in //google/protobuf/io/tokenizer.h. Note that class's Parse
@@ -108,9 +194,10 @@ void Message::PrintDebugString() const {
class TextFormat::Parser::ParserImpl {
public:
- // Determines if repeated values for a non-repeated field are
- // permitted, e.g., the string "foo: 1 foo: 2" for a
- // required/optional field named "foo".
+ // Determines if repeated values for non-repeated fields and
+ // oneofs are permitted, e.g., the string "foo: 1 foo: 2" for a
+ // required/optional field named "foo", or "baz: 1 qux: 2"
+ // where "baz" and "qux" are members of the same oneof.
enum SingularOverwritePolicy {
ALLOW_SINGULAR_OVERWRITES = 0, // the last value is retained
FORBID_SINGULAR_OVERWRITES = 1, // an error is issued
@@ -120,13 +207,24 @@ class TextFormat::Parser::ParserImpl {
io::ZeroCopyInputStream* input_stream,
io::ErrorCollector* error_collector,
TextFormat::Finder* finder,
- SingularOverwritePolicy singular_overwrite_policy)
+ ParseInfoTree* parse_info_tree,
+ SingularOverwritePolicy singular_overwrite_policy,
+ bool allow_case_insensitive_field,
+ bool allow_unknown_field,
+ bool allow_unknown_enum,
+ bool allow_field_number,
+ bool allow_relaxed_whitespace)
: error_collector_(error_collector),
finder_(finder),
+ parse_info_tree_(parse_info_tree),
tokenizer_error_collector_(this),
tokenizer_(input_stream, &tokenizer_error_collector_),
root_message_type_(root_message_type),
singular_overwrite_policy_(singular_overwrite_policy),
+ allow_case_insensitive_field_(allow_case_insensitive_field),
+ allow_unknown_field_(allow_unknown_field),
+ allow_unknown_enum_(allow_unknown_enum),
+ allow_field_number_(allow_field_number),
had_errors_(false) {
// For backwards-compatibility with proto1, we need to allow the 'f' suffix
// for floats.
@@ -135,6 +233,11 @@ class TextFormat::Parser::ParserImpl {
// '#' starts a comment.
tokenizer_.set_comment_style(io::Tokenizer::SH_COMMENT_STYLE);
+ if (allow_relaxed_whitespace) {
+ tokenizer_.set_require_space_after_number(false);
+ tokenizer_.set_allow_multiline_strings(true);
+ }
+
// Consume the starting token.
tokenizer_.Next();
}
@@ -146,7 +249,7 @@ class TextFormat::Parser::ParserImpl {
// GOOGLE_LOG(ERROR)).
bool Parse(Message* output) {
// Consume fields until we cannot do so anymore.
- while(true) {
+ while (true) {
if (LookingAtType(io::Tokenizer::TYPE_END)) {
return !had_errors_;
}
@@ -217,20 +320,21 @@ class TextFormat::Parser::ParserImpl {
message);
}
- // Consumes the specified message with the given starting delimeter.
- // This method checks to see that the end delimeter at the conclusion of
- // the consumption matches the starting delimeter passed in here.
- bool ConsumeMessage(Message* message, const string delimeter) {
+ // Consumes the specified message with the given starting delimiter.
+ // This method checks to see that the end delimiter at the conclusion of
+ // the consumption matches the starting delimiter passed in here.
+ bool ConsumeMessage(Message* message, const string delimiter) {
while (!LookingAt(">") && !LookingAt("}")) {
DO(ConsumeField(message));
}
- // Confirm that we have a valid ending delimeter.
- DO(Consume(delimeter));
+ // Confirm that we have a valid ending delimiter.
+ DO(Consume(delimiter));
return true;
}
+
// Consumes the current field (as returned by the tokenizer) on the
// passed in message.
bool ConsumeField(Message* message) {
@@ -240,6 +344,8 @@ class TextFormat::Parser::ParserImpl {
string field_name;
const FieldDescriptor* field = NULL;
+ int start_line = tokenizer_.current().line;
+ int start_column = tokenizer_.current().column;
if (TryConsume("[")) {
// Extension.
@@ -257,67 +363,129 @@ class TextFormat::Parser::ParserImpl {
: reflection->FindKnownExtensionByName(field_name));
if (field == NULL) {
- ReportError("Extension \"" + field_name + "\" is not defined or "
- "is not an extension of \"" +
- descriptor->full_name() + "\".");
- return false;
+ if (!allow_unknown_field_) {
+ ReportError("Extension \"" + field_name + "\" is not defined or "
+ "is not an extension of \"" +
+ descriptor->full_name() + "\".");
+ return false;
+ } else {
+ ReportWarning("Extension \"" + field_name + "\" is not defined or "
+ "is not an extension of \"" +
+ descriptor->full_name() + "\".");
+ }
}
} else {
DO(ConsumeIdentifier(&field_name));
- field = descriptor->FindFieldByName(field_name);
- // Group names are expected to be capitalized as they appear in the
- // .proto file, which actually matches their type names, not their field
- // names.
- if (field == NULL) {
- string lower_field_name = field_name;
- LowerString(&lower_field_name);
- field = descriptor->FindFieldByName(lower_field_name);
- // If the case-insensitive match worked but the field is NOT a group,
- if (field != NULL && field->type() != FieldDescriptor::TYPE_GROUP) {
+ int32 field_number;
+ if (allow_field_number_ && safe_strto32(field_name, &field_number)) {
+ if (descriptor->IsExtensionNumber(field_number)) {
+ field = reflection->FindKnownExtensionByNumber(field_number);
+ } else {
+ field = descriptor->FindFieldByNumber(field_number);
+ }
+ } else {
+ field = descriptor->FindFieldByName(field_name);
+ // Group names are expected to be capitalized as they appear in the
+ // .proto file, which actually matches their type names, not their
+ // field names.
+ if (field == NULL) {
+ string lower_field_name = field_name;
+ LowerString(&lower_field_name);
+ field = descriptor->FindFieldByName(lower_field_name);
+ // If the case-insensitive match worked but the field is NOT a group,
+ if (field != NULL && field->type() != FieldDescriptor::TYPE_GROUP) {
+ field = NULL;
+ }
+ }
+ // Again, special-case group names as described above.
+ if (field != NULL && field->type() == FieldDescriptor::TYPE_GROUP
+ && field->message_type()->name() != field_name) {
field = NULL;
}
- }
- // Again, special-case group names as described above.
- if (field != NULL && field->type() == FieldDescriptor::TYPE_GROUP
- && field->message_type()->name() != field_name) {
- field = NULL;
+
+ if (field == NULL && allow_case_insensitive_field_) {
+ string lower_field_name = field_name;
+ LowerString(&lower_field_name);
+ field = descriptor->FindFieldByLowercaseName(lower_field_name);
+ }
}
if (field == NULL) {
- ReportError("Message type \"" + descriptor->full_name() +
- "\" has no field named \"" + field_name + "\".");
- return false;
+ if (!allow_unknown_field_) {
+ ReportError("Message type \"" + descriptor->full_name() +
+ "\" has no field named \"" + field_name + "\".");
+ return false;
+ } else {
+ ReportWarning("Message type \"" + descriptor->full_name() +
+ "\" has no field named \"" + field_name + "\".");
+ }
}
}
- // Fail if the field is not repeated and it has already been specified.
- if ((singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) &&
- !field->is_repeated() && reflection->HasField(*message, field)) {
- ReportError("Non-repeated field \"" + field_name +
- "\" is specified multiple times.");
- return false;
+ // Skips unknown field.
+ if (field == NULL) {
+ GOOGLE_CHECK(allow_unknown_field_);
+ // Try to guess the type of this field.
+ // If this field is not a message, there should be a ":" between the
+ // field name and the field value and also the field value should not
+ // start with "{" or "<" which indicates the beginning of a message body.
+ // If there is no ":" or there is a "{" or "<" after ":", this field has
+ // to be a message or the input is ill-formed.
+ if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
+ return SkipFieldValue();
+ } else {
+ return SkipFieldMessage();
+ }
+ }
+
+ if (singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) {
+ // Fail if the field is not repeated and it has already been specified.
+ if (!field->is_repeated() && reflection->HasField(*message, field)) {
+ ReportError("Non-repeated field \"" + field_name +
+ "\" is specified multiple times.");
+ return false;
+ }
+ // Fail if the field is a member of a oneof and another member has already
+ // been specified.
+ const OneofDescriptor* oneof = field->containing_oneof();
+ if (oneof != NULL && reflection->HasOneof(*message, oneof)) {
+ const FieldDescriptor* other_field =
+ reflection->GetOneofFieldDescriptor(*message, oneof);
+ ReportError("Field \"" + field_name + "\" is specified along with "
+ "field \"" + other_field->name() + "\", another member "
+ "of oneof \"" + oneof->name() + "\".");
+ return false;
+ }
}
// Perform special handling for embedded message types.
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// ':' is optional here.
TryConsume(":");
- DO(ConsumeFieldMessage(message, reflection, field));
} else {
+ // ':' is required here.
DO(Consume(":"));
- if (field->is_repeated() && TryConsume("[")) {
- // Short repeated format, e.g. "foo: [1, 2, 3]"
- while (true) {
+ }
+
+ if (field->is_repeated() && TryConsume("[")) {
+ // Short repeated format, e.g. "foo: [1, 2, 3]"
+ while (true) {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Perform special handling for embedded message types.
+ DO(ConsumeFieldMessage(message, reflection, field));
+ } else {
DO(ConsumeFieldValue(message, reflection, field));
- if (TryConsume("]")) {
- break;
- }
- DO(Consume(","));
}
- } else {
- DO(ConsumeFieldValue(message, reflection, field));
+ if (TryConsume("]")) {
+ break;
+ }
+ DO(Consume(","));
}
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ DO(ConsumeFieldMessage(message, reflection, field));
+ } else {
+ DO(ConsumeFieldValue(message, reflection, field));
}
// For historical reasons, fields may optionally be separated by commas or
@@ -329,26 +497,95 @@ class TextFormat::Parser::ParserImpl {
+ field_name + "\"");
}
+ // If a parse info tree exists, add the location for the parsed
+ // field.
+ if (parse_info_tree_ != NULL) {
+ RecordLocation(parse_info_tree_, field,
+ ParseLocation(start_line, start_column));
+ }
+
+ return true;
+ }
+
+ // Skips the next field including the field's name and value.
+ bool SkipField() {
+ string field_name;
+ if (TryConsume("[")) {
+ // Extension name.
+ DO(ConsumeIdentifier(&field_name));
+ while (TryConsume(".")) {
+ string part;
+ DO(ConsumeIdentifier(&part));
+ field_name += ".";
+ field_name += part;
+ }
+ DO(Consume("]"));
+ } else {
+ DO(ConsumeIdentifier(&field_name));
+ }
+
+ // Try to guess the type of this field.
+ // If this field is not a message, there should be a ":" between the
+ // field name and the field value and also the field value should not
+ // start with "{" or "<" which indicates the beginning of a message body.
+ // If there is no ":" or there is a "{" or "<" after ":", this field has
+ // to be a message or the input is ill-formed.
+ if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
+ DO(SkipFieldValue());
+ } else {
+ DO(SkipFieldMessage());
+ }
+ // For historical reasons, fields may optionally be separated by commas or
+ // semicolons.
+ TryConsume(";") || TryConsume(",");
return true;
}
bool ConsumeFieldMessage(Message* message,
const Reflection* reflection,
const FieldDescriptor* field) {
- string delimeter;
+
+ // If the parse information tree is not NULL, create a nested one
+ // for the nested message.
+ ParseInfoTree* parent = parse_info_tree_;
+ if (parent != NULL) {
+ parse_info_tree_ = CreateNested(parent, field);
+ }
+
+ string delimiter;
if (TryConsume("<")) {
- delimeter = ">";
+ delimiter = ">";
} else {
DO(Consume("{"));
- delimeter = "}";
+ delimiter = "}";
}
if (field->is_repeated()) {
- DO(ConsumeMessage(reflection->AddMessage(message, field), delimeter));
+ DO(ConsumeMessage(reflection->AddMessage(message, field), delimiter));
} else {
DO(ConsumeMessage(reflection->MutableMessage(message, field),
- delimeter));
+ delimiter));
+ }
+
+ // Reset the parse information tree.
+ parse_info_tree_ = parent;
+ return true;
+ }
+
+ // Skips the whole body of a message including the beginning delimiter and
+ // the ending delimiter.
+ bool SkipFieldMessage() {
+ string delimiter;
+ if (TryConsume("<")) {
+ delimiter = ">";
+ } else {
+ DO(Consume("{"));
+ delimiter = "}";
+ }
+ while (!LookingAt(">") && !LookingAt("}")) {
+ DO(SkipField());
}
+ DO(Consume(delimiter));
return true;
}
@@ -424,9 +661,9 @@ class TextFormat::Parser::ParserImpl {
} else {
string value;
DO(ConsumeIdentifier(&value));
- if (value == "true" || value == "t") {
+ if (value == "true" || value == "True" || value == "t") {
SET_FIELD(Bool, true);
- } else if (value == "false" || value == "f") {
+ } else if (value == "false" || value == "False" || value == "f") {
SET_FIELD(Bool, false);
} else {
ReportError("Invalid value for boolean field \"" + field->name()
@@ -459,9 +696,15 @@ class TextFormat::Parser::ParserImpl {
}
if (enum_value == NULL) {
- ReportError("Unknown enumeration value of \"" + value + "\" for "
- "field \"" + field->name() + "\".");
- return false;
+ if (!allow_unknown_enum_) {
+ ReportError("Unknown enumeration value of \"" + value + "\" for "
+ "field \"" + field->name() + "\".");
+ return false;
+ } else {
+ ReportWarning("Unknown enumeration value of \"" + value + "\" for "
+ "field \"" + field->name() + "\".");
+ return true;
+ }
}
SET_FIELD(Enum, enum_value);
@@ -479,6 +722,60 @@ class TextFormat::Parser::ParserImpl {
return true;
}
+ bool SkipFieldValue() {
+ if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+ while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+ tokenizer_.Next();
+ }
+ return true;
+ }
+ // Possible field values other than string:
+ // 12345 => TYPE_INTEGER
+ // -12345 => TYPE_SYMBOL + TYPE_INTEGER
+ // 1.2345 => TYPE_FLOAT
+ // -1.2345 => TYPE_SYMBOL + TYPE_FLOAT
+ // inf => TYPE_IDENTIFIER
+ // -inf => TYPE_SYMBOL + TYPE_IDENTIFIER
+ // TYPE_INTEGER => TYPE_IDENTIFIER
+ // Divides them into two group, one with TYPE_SYMBOL
+ // and the other without:
+ // Group one:
+ // 12345 => TYPE_INTEGER
+ // 1.2345 => TYPE_FLOAT
+ // inf => TYPE_IDENTIFIER
+ // TYPE_INTEGER => TYPE_IDENTIFIER
+ // Group two:
+ // -12345 => TYPE_SYMBOL + TYPE_INTEGER
+ // -1.2345 => TYPE_SYMBOL + TYPE_FLOAT
+ // -inf => TYPE_SYMBOL + TYPE_IDENTIFIER
+ // As we can see, the field value consists of an optional '-' and one of
+ // TYPE_INTEGER, TYPE_FLOAT and TYPE_IDENTIFIER.
+ bool has_minus = TryConsume("-");
+ if (!LookingAtType(io::Tokenizer::TYPE_INTEGER) &&
+ !LookingAtType(io::Tokenizer::TYPE_FLOAT) &&
+ !LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+ return false;
+ }
+ // Combination of '-' and TYPE_IDENTIFIER may result in an invalid field
+ // value while other combinations all generate valid values.
+ // We check if the value of this combination is valid here.
+ // TYPE_IDENTIFIER after a '-' should be one of the float values listed
+ // below:
+ // inf, inff, infinity, nan
+ if (has_minus && LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+ string text = tokenizer_.current().text;
+ LowerString(&text);
+ if (text != "inf" &&
+ text != "infinity" &&
+ text != "nan") {
+ ReportError("Invalid float number: " + text);
+ return false;
+ }
+ }
+ tokenizer_.Next();
+ return true;
+ }
+
// Returns true if the current token's text is equal to that specified.
bool LookingAt(const string& text) {
return tokenizer_.current().text == text;
@@ -492,15 +789,23 @@ class TextFormat::Parser::ParserImpl {
// Consumes an identifier and saves its value in the identifier parameter.
// Returns false if the token is not of type IDENTFIER.
bool ConsumeIdentifier(string* identifier) {
- if (!LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
- ReportError("Expected identifier.");
- return false;
+ if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+ *identifier = tokenizer_.current().text;
+ tokenizer_.Next();
+ return true;
}
- *identifier = tokenizer_.current().text;
+ // If allow_field_numer_ or allow_unknown_field_ is true, we should able
+ // to parse integer identifiers.
+ if ((allow_field_number_ || allow_unknown_field_)
+ && LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+ *identifier = tokenizer_.current().text;
+ tokenizer_.Next();
+ return true;
+ }
- tokenizer_.Next();
- return true;
+ ReportError("Expected identifier.");
+ return false;
}
// Consumes a string and saves its value in the text parameter.
@@ -567,6 +872,29 @@ class TextFormat::Parser::ParserImpl {
return true;
}
+ // Consumes a uint64 and saves its value in the value parameter.
+ // Accepts decimal numbers only, rejects hex or oct numbers.
+ bool ConsumeUnsignedDecimalInteger(uint64* value, uint64 max_value) {
+ if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+ ReportError("Expected integer.");
+ return false;
+ }
+
+ const string& text = tokenizer_.current().text;
+ if (IsHexNumber(text) || IsOctNumber(text)) {
+ ReportError("Expect a decimal number.");
+ return false;
+ }
+
+ if (!io::Tokenizer::ParseInteger(text, max_value, value)) {
+ ReportError("Integer out of range.");
+ return false;
+ }
+
+ tokenizer_.Next();
+ return true;
+ }
+
// Consumes a double and saves its value in the value parameter.
// Note that since the tokenizer does not support negative numbers,
// we actually may consume an additional token (for the minus sign) in this
@@ -584,7 +912,7 @@ class TextFormat::Parser::ParserImpl {
if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
// We have found an integer value for the double.
uint64 integer_value;
- DO(ConsumeUnsignedInteger(&integer_value, kuint64max));
+ DO(ConsumeUnsignedDecimalInteger(&integer_value, kuint64max));
*value = static_cast<double>(integer_value);
} else if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) {
@@ -596,7 +924,8 @@ class TextFormat::Parser::ParserImpl {
} else if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
string text = tokenizer_.current().text;
LowerString(&text);
- if (text == "inf" || text == "infinity") {
+ if (text == "inf" ||
+ text == "infinity") {
*value = std::numeric_limits<double>::infinity();
tokenizer_.Next();
} else if (text == "nan") {
@@ -653,7 +982,7 @@ class TextFormat::Parser::ParserImpl {
explicit ParserErrorCollector(TextFormat::Parser::ParserImpl* parser) :
parser_(parser) { }
- virtual ~ParserErrorCollector() { };
+ virtual ~ParserErrorCollector() { }
virtual void AddError(int line, int column, const string& message) {
parser_->ReportError(line, column, message);
@@ -670,10 +999,15 @@ class TextFormat::Parser::ParserImpl {
io::ErrorCollector* error_collector_;
TextFormat::Finder* finder_;
+ ParseInfoTree* parse_info_tree_;
ParserErrorCollector tokenizer_error_collector_;
io::Tokenizer tokenizer_;
const Descriptor* root_message_type_;
SingularOverwritePolicy singular_overwrite_policy_;
+ const bool allow_case_insensitive_field_;
+ const bool allow_unknown_field_;
+ const bool allow_unknown_enum_;
+ const bool allow_field_number_;
bool had_errors_;
};
@@ -699,7 +1033,7 @@ class TextFormat::Printer::TextGenerator {
~TextGenerator() {
// Only BackUp() if we're sure we've successfully called Next() at least
// once.
- if (buffer_size_ > 0) {
+ if (!failed_ && buffer_size_ > 0) {
output_->BackUp(buffer_size_);
}
}
@@ -809,7 +1143,14 @@ TextFormat::Finder::~Finder() {
TextFormat::Parser::Parser()
: error_collector_(NULL),
finder_(NULL),
- allow_partial_(false) {
+ parse_info_tree_(NULL),
+ allow_partial_(false),
+ allow_case_insensitive_field_(false),
+ allow_unknown_field_(false),
+ allow_unknown_enum_(false),
+ allow_field_number_(false),
+ allow_relaxed_whitespace_(false),
+ allow_singular_overwrites_(false) {
}
TextFormat::Parser::~Parser() {}
@@ -817,8 +1158,18 @@ TextFormat::Parser::~Parser() {}
bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
Message* output) {
output->Clear();
+
+ ParserImpl::SingularOverwritePolicy overwrites_policy =
+ allow_singular_overwrites_
+ ? ParserImpl::ALLOW_SINGULAR_OVERWRITES
+ : ParserImpl::FORBID_SINGULAR_OVERWRITES;
+
ParserImpl parser(output->GetDescriptor(), input, error_collector_,
- finder_, ParserImpl::FORBID_SINGULAR_OVERWRITES);
+ finder_, parse_info_tree_,
+ overwrites_policy,
+ allow_case_insensitive_field_, allow_unknown_field_,
+ allow_unknown_enum_, allow_field_number_,
+ allow_relaxed_whitespace_);
return MergeUsingImpl(input, output, &parser);
}
@@ -831,7 +1182,11 @@ bool TextFormat::Parser::ParseFromString(const string& input,
bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
Message* output) {
ParserImpl parser(output->GetDescriptor(), input, error_collector_,
- finder_, ParserImpl::ALLOW_SINGULAR_OVERWRITES);
+ finder_, parse_info_tree_,
+ ParserImpl::ALLOW_SINGULAR_OVERWRITES,
+ allow_case_insensitive_field_, allow_unknown_field_,
+ allow_unknown_enum_, allow_field_number_,
+ allow_relaxed_whitespace_);
return MergeUsingImpl(input, output, &parser);
}
@@ -841,7 +1196,7 @@ bool TextFormat::Parser::MergeFromString(const string& input,
return Merge(&input_stream, output);
}
-bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input,
+bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* /* input */,
Message* output,
ParserImpl* parser_impl) {
if (!parser_impl->Parse(output)) return false;
@@ -849,7 +1204,7 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input,
vector<string> missing_fields;
output->FindInitializationErrors(&missing_fields);
parser_impl->ReportError(-1, 0, "Message missing required fields: " +
- JoinStrings(missing_fields, ", "));
+ Join(missing_fields, ", "));
return false;
}
return true;
@@ -861,7 +1216,11 @@ bool TextFormat::Parser::ParseFieldValueFromString(
Message* output) {
io::ArrayInputStream input_stream(input.data(), input.size());
ParserImpl parser(output->GetDescriptor(), &input_stream, error_collector_,
- finder_, ParserImpl::ALLOW_SINGULAR_OVERWRITES);
+ finder_, parse_info_tree_,
+ ParserImpl::ALLOW_SINGULAR_OVERWRITES,
+ allow_case_insensitive_field_, allow_unknown_field_,
+ allow_unknown_enum_, allow_field_number_,
+ allow_relaxed_whitespace_);
return parser.ParseField(field, output);
}
@@ -887,13 +1246,123 @@ bool TextFormat::Parser::ParseFieldValueFromString(
// ===========================================================================
+// The default implementation for FieldValuePrinter. The base class just
+// does simple formatting. That way, deriving classes could decide to fallback
+// to that behavior.
+TextFormat::FieldValuePrinter::FieldValuePrinter() {}
+TextFormat::FieldValuePrinter::~FieldValuePrinter() {}
+string TextFormat::FieldValuePrinter::PrintBool(bool val) const {
+ return val ? "true" : "false";
+}
+string TextFormat::FieldValuePrinter::PrintInt32(int32 val) const {
+ return SimpleItoa(val);
+}
+string TextFormat::FieldValuePrinter::PrintUInt32(uint32 val) const {
+ return SimpleItoa(val);
+}
+string TextFormat::FieldValuePrinter::PrintInt64(int64 val) const {
+ return SimpleItoa(val);
+}
+string TextFormat::FieldValuePrinter::PrintUInt64(uint64 val) const {
+ return SimpleItoa(val);
+}
+string TextFormat::FieldValuePrinter::PrintFloat(float val) const {
+ return SimpleFtoa(val);
+}
+string TextFormat::FieldValuePrinter::PrintDouble(double val) const {
+ return SimpleDtoa(val);
+}
+string TextFormat::FieldValuePrinter::PrintString(const string& val) const {
+ return StrCat("\"", CEscape(val), "\"");
+}
+string TextFormat::FieldValuePrinter::PrintBytes(const string& val) const {
+ return PrintString(val);
+}
+string TextFormat::FieldValuePrinter::PrintEnum(int32 val,
+ const string& name) const {
+ return name;
+}
+string TextFormat::FieldValuePrinter::PrintFieldName(
+ const Message& message,
+ const Reflection* reflection,
+ const FieldDescriptor* field) const {
+ if (field->is_extension()) {
+ // We special-case MessageSet elements for compatibility with proto1.
+ if (field->containing_type()->options().message_set_wire_format()
+ && field->type() == FieldDescriptor::TYPE_MESSAGE
+ && field->is_optional()
+ && field->extension_scope() == field->message_type()) {
+ return StrCat("[", field->message_type()->full_name(), "]");
+ } else {
+ return StrCat("[", field->full_name(), "]");
+ }
+ } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ // Groups must be serialized with their original capitalization.
+ return field->message_type()->name();
+ } else {
+ return field->name();
+ }
+}
+string TextFormat::FieldValuePrinter::PrintMessageStart(
+ const Message& message,
+ int field_index,
+ int field_count,
+ bool single_line_mode) const {
+ return single_line_mode ? " { " : " {\n";
+}
+string TextFormat::FieldValuePrinter::PrintMessageEnd(
+ const Message& message,
+ int field_index,
+ int field_count,
+ bool single_line_mode) const {
+ return single_line_mode ? "} " : "}\n";
+}
+
+namespace {
+// Our own specialization: for UTF8 escaped strings.
+class FieldValuePrinterUtf8Escaping : public TextFormat::FieldValuePrinter {
+ public:
+ virtual string PrintString(const string& val) const {
+ return StrCat("\"", strings::Utf8SafeCEscape(val), "\"");
+ }
+ virtual string PrintBytes(const string& val) const {
+ return TextFormat::FieldValuePrinter::PrintString(val);
+ }
+};
+
+} // namespace
+
TextFormat::Printer::Printer()
: initial_indent_level_(0),
single_line_mode_(false),
+ use_field_number_(false),
use_short_repeated_primitives_(false),
- utf8_string_escaping_(false) {}
+ hide_unknown_fields_(false),
+ print_message_fields_in_index_order_(false) {
+ SetUseUtf8StringEscaping(false);
+}
+
+TextFormat::Printer::~Printer() {
+ STLDeleteValues(&custom_printers_);
+}
+
+void TextFormat::Printer::SetUseUtf8StringEscaping(bool as_utf8) {
+ SetDefaultFieldValuePrinter(as_utf8
+ ? new FieldValuePrinterUtf8Escaping()
+ : new FieldValuePrinter());
+}
+
+void TextFormat::Printer::SetDefaultFieldValuePrinter(
+ const FieldValuePrinter* printer) {
+ default_field_value_printer_.reset(printer);
+}
-TextFormat::Printer::~Printer() {}
+bool TextFormat::Printer::RegisterFieldValuePrinter(
+ const FieldDescriptor* field,
+ const FieldValuePrinter* printer) {
+ return field != NULL && printer != NULL &&
+ custom_printers_.insert(std::make_pair(field, printer)).second;
+}
bool TextFormat::Printer::PrintToString(const Message& message,
string* output) const {
@@ -902,9 +1371,7 @@ bool TextFormat::Printer::PrintToString(const Message& message,
output->clear();
io::StringOutputStream output_stream(output);
- bool result = Print(message, &output_stream);
-
- return result;
+ return Print(message, &output_stream);
}
bool TextFormat::Printer::PrintUnknownFieldsToString(
@@ -938,15 +1405,30 @@ bool TextFormat::Printer::PrintUnknownFields(
return !generator.failed();
}
+namespace {
+// Comparison functor for sorting FieldDescriptors by field index.
+struct FieldIndexSorter {
+ bool operator()(const FieldDescriptor* left,
+ const FieldDescriptor* right) const {
+ return left->index() < right->index();
+ }
+};
+} // namespace
+
void TextFormat::Printer::Print(const Message& message,
TextGenerator& generator) const {
const Reflection* reflection = message.GetReflection();
vector<const FieldDescriptor*> fields;
reflection->ListFields(message, &fields);
+ if (print_message_fields_in_index_order_) {
+ std::sort(fields.begin(), fields.end(), FieldIndexSorter());
+ }
for (int i = 0; i < fields.size(); i++) {
PrintField(message, reflection, fields[i], generator);
}
- PrintUnknownFields(reflection->GetUnknownFields(message), generator);
+ if (!hide_unknown_fields_) {
+ PrintUnknownFields(reflection->GetUnknownFields(message), generator);
+ }
}
void TextFormat::Printer::PrintFieldValueToString(
@@ -985,35 +1467,30 @@ void TextFormat::Printer::PrintField(const Message& message,
}
for (int j = 0; j < count; ++j) {
+ const int field_index = field->is_repeated() ? j : -1;
+
PrintFieldName(message, reflection, field, generator);
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- if (single_line_mode_) {
- generator.Print(" { ");
- } else {
- generator.Print(" {\n");
- generator.Indent();
- }
+ const FieldValuePrinter* printer = FindWithDefault(
+ custom_printers_, field, default_field_value_printer_.get());
+ const Message& sub_message =
+ field->is_repeated()
+ ? reflection->GetRepeatedMessage(message, field, j)
+ : reflection->GetMessage(message, field);
+ generator.Print(
+ printer->PrintMessageStart(
+ sub_message, field_index, count, single_line_mode_));
+ generator.Indent();
+ Print(sub_message, generator);
+ generator.Outdent();
+ generator.Print(
+ printer->PrintMessageEnd(
+ sub_message, field_index, count, single_line_mode_));
} else {
generator.Print(": ");
- }
-
- // Write the field value.
- int field_index = j;
- if (!field->is_repeated()) {
- field_index = -1;
- }
-
- PrintFieldValue(message, reflection, field, field_index, generator);
-
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- if (single_line_mode_) {
- generator.Print("} ");
- } else {
- generator.Outdent();
- generator.Print("}\n");
- }
- } else {
+ // Write the field value.
+ PrintFieldValue(message, reflection, field, field_index, generator);
if (single_line_mode_) {
generator.Print(" ");
} else {
@@ -1048,26 +1525,16 @@ void TextFormat::Printer::PrintFieldName(const Message& message,
const Reflection* reflection,
const FieldDescriptor* field,
TextGenerator& generator) const {
- if (field->is_extension()) {
- generator.Print("[");
- // We special-case MessageSet elements for compatibility with proto1.
- if (field->containing_type()->options().message_set_wire_format()
- && field->type() == FieldDescriptor::TYPE_MESSAGE
- && field->is_optional()
- && field->extension_scope() == field->message_type()) {
- generator.Print(field->message_type()->full_name());
- } else {
- generator.Print(field->full_name());
- }
- generator.Print("]");
- } else {
- if (field->type() == FieldDescriptor::TYPE_GROUP) {
- // Groups must be serialized with their original capitalization.
- generator.Print(field->message_type()->name());
- } else {
- generator.Print(field->name());
- }
+ // if use_field_number_ is true, prints field number instead
+ // of field name.
+ if (use_field_number_) {
+ generator.Print(SimpleItoa(field->number()));
+ return;
}
+
+ const FieldValuePrinter* printer = FindWithDefault(
+ custom_printers_, field, default_field_value_printer_.get());
+ generator.Print(printer->PrintFieldName(message, reflection, field));
}
void TextFormat::Printer::PrintFieldValue(
@@ -1079,62 +1546,69 @@ void TextFormat::Printer::PrintFieldValue(
GOOGLE_DCHECK(field->is_repeated() || (index == -1))
<< "Index must be -1 for non-repeated fields";
+ const FieldValuePrinter* printer
+ = FindWithDefault(custom_printers_, field,
+ default_field_value_printer_.get());
+
switch (field->cpp_type()) {
-#define OUTPUT_FIELD(CPPTYPE, METHOD, TO_STRING) \
- case FieldDescriptor::CPPTYPE_##CPPTYPE: \
- generator.Print(TO_STRING(field->is_repeated() ? \
- reflection->GetRepeated##METHOD(message, field, index) : \
- reflection->Get##METHOD(message, field))); \
- break; \
-
- OUTPUT_FIELD( INT32, Int32, SimpleItoa);
- OUTPUT_FIELD( INT64, Int64, SimpleItoa);
- OUTPUT_FIELD(UINT32, UInt32, SimpleItoa);
- OUTPUT_FIELD(UINT64, UInt64, SimpleItoa);
- OUTPUT_FIELD( FLOAT, Float, SimpleFtoa);
- OUTPUT_FIELD(DOUBLE, Double, SimpleDtoa);
+#define OUTPUT_FIELD(CPPTYPE, METHOD) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ generator.Print(printer->Print##METHOD(field->is_repeated() \
+ ? reflection->GetRepeated##METHOD(message, field, index) \
+ : reflection->Get##METHOD(message, field))); \
+ break
+
+ OUTPUT_FIELD( INT32, Int32);
+ OUTPUT_FIELD( INT64, Int64);
+ OUTPUT_FIELD(UINT32, UInt32);
+ OUTPUT_FIELD(UINT64, UInt64);
+ OUTPUT_FIELD( FLOAT, Float);
+ OUTPUT_FIELD(DOUBLE, Double);
+ OUTPUT_FIELD( BOOL, Bool);
#undef OUTPUT_FIELD
- case FieldDescriptor::CPPTYPE_STRING: {
- string scratch;
- const string& value = field->is_repeated() ?
- reflection->GetRepeatedStringReference(
- message, field, index, &scratch) :
- reflection->GetStringReference(message, field, &scratch);
-
- generator.Print("\"");
- if (utf8_string_escaping_) {
- generator.Print(strings::Utf8SafeCEscape(value));
- } else {
- generator.Print(CEscape(value));
- }
- generator.Print("\"");
-
- break;
+ case FieldDescriptor::CPPTYPE_STRING: {
+ string scratch;
+ const string& value = field->is_repeated()
+ ? reflection->GetRepeatedStringReference(
+ message, field, index, &scratch)
+ : reflection->GetStringReference(message, field, &scratch);
+ if (field->type() == FieldDescriptor::TYPE_STRING) {
+ generator.Print(printer->PrintString(value));
+ } else {
+ GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_BYTES);
+ generator.Print(printer->PrintBytes(value));
}
+ break;
+ }
- case FieldDescriptor::CPPTYPE_BOOL:
- if (field->is_repeated()) {
- generator.Print(reflection->GetRepeatedBool(message, field, index)
- ? "true" : "false");
- } else {
- generator.Print(reflection->GetBool(message, field)
- ? "true" : "false");
- }
- break;
-
- case FieldDescriptor::CPPTYPE_ENUM:
- generator.Print(field->is_repeated() ?
- reflection->GetRepeatedEnum(message, field, index)->name() :
- reflection->GetEnum(message, field)->name());
- break;
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ 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<int> 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;
+ }
- case FieldDescriptor::CPPTYPE_MESSAGE:
- Print(field->is_repeated() ?
- reflection->GetRepeatedMessage(message, field, index) :
- reflection->GetMessage(message, field),
- generator);
- break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ Print(field->is_repeated()
+ ? reflection->GetRepeatedMessage(message, field, index)
+ : reflection->GetMessage(message, field),
+ generator);
+ break;
}
}
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index 03c04910..9e2cb070 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -38,9 +38,17 @@
#ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__
#define GOOGLE_PROTOBUF_TEXT_FORMAT_H__
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
-#include <google/protobuf/message.h>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
namespace google {
namespace protobuf {
@@ -82,6 +90,41 @@ class LIBPROTOBUF_EXPORT TextFormat {
int index,
string* output);
+ // The default printer that converts scalar values from fields into
+ // their string representation.
+ // You can derive from this FieldValuePrinter if you want to have
+ // fields to be printed in a different way and register it at the
+ // Printer.
+ class LIBPROTOBUF_EXPORT FieldValuePrinter {
+ public:
+ FieldValuePrinter();
+ virtual ~FieldValuePrinter();
+ virtual string PrintBool(bool val) const;
+ virtual string PrintInt32(int32 val) const;
+ virtual string PrintUInt32(uint32 val) const;
+ virtual string PrintInt64(int64 val) const;
+ virtual string PrintUInt64(uint64 val) const;
+ virtual string PrintFloat(float val) const;
+ virtual string PrintDouble(double val) const;
+ virtual string PrintString(const string& val) const;
+ virtual string PrintBytes(const string& val) const;
+ virtual string PrintEnum(int32 val, const string& name) const;
+ virtual string PrintFieldName(const Message& message,
+ const Reflection* reflection,
+ const FieldDescriptor* field) const;
+ virtual string PrintMessageStart(const Message& message,
+ int field_index,
+ int field_count,
+ bool single_line_mode) const;
+ virtual string PrintMessageEnd(const Message& message,
+ int field_index,
+ int field_count,
+ bool single_line_mode) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldValuePrinter);
+ };
+
// Class for those users which require more fine-grained control over how
// a protobuffer message is printed out.
class LIBPROTOBUF_EXPORT Printer {
@@ -117,6 +160,15 @@ class LIBPROTOBUF_EXPORT TextFormat {
single_line_mode_ = single_line_mode;
}
+ bool IsInSingleLineMode() {
+ return single_line_mode_;
+ }
+
+ // If use_field_number is true, uses field number instead of field name.
+ void SetUseFieldNumber(bool use_field_number) {
+ use_field_number_ = use_field_number;
+ }
+
// Set true to print repeated primitives in a format like:
// field_name: [1, 2, 3, 4]
// instead of printing each value on its own line. Short format applies
@@ -129,11 +181,41 @@ class LIBPROTOBUF_EXPORT TextFormat {
// Set true to output UTF-8 instead of ASCII. The only difference
// is that bytes >= 0x80 in string fields will not be escaped,
// because they are assumed to be part of UTF-8 multi-byte
- // sequences.
- void SetUseUtf8StringEscaping(bool as_utf8) {
- utf8_string_escaping_ = as_utf8;
+ // sequences. This will change the default FieldValuePrinter.
+ void SetUseUtf8StringEscaping(bool as_utf8);
+
+ // Set the default FieldValuePrinter that is used for all fields that
+ // don't have a field-specific printer registered.
+ // Takes ownership of the printer.
+ void SetDefaultFieldValuePrinter(const FieldValuePrinter* printer);
+
+ // Sets whether we want to hide unknown fields or not.
+ // Usually unknown fields are printed in a generic way that includes the
+ // tag number of the field instead of field name. However, sometimes it
+ // is useful to be able to print the message without unknown fields (e.g.
+ // for the python protobuf version to maintain consistency between its pure
+ // python and c++ implementations).
+ void SetHideUnknownFields(bool hide) {
+ hide_unknown_fields_ = hide;
}
+ // If print_message_fields_in_index_order is true, print fields of a proto
+ // message using the order defined in source code instead of the field
+ // number. By default, use the field number order.
+ void SetPrintMessageFieldsInIndexOrder(
+ bool print_message_fields_in_index_order) {
+ print_message_fields_in_index_order_ =
+ print_message_fields_in_index_order;
+ }
+
+ // Register a custom field-specific FieldValuePrinter for fields
+ // with a particular FieldDescriptor.
+ // Returns "true" if the registration succeeded, or "false", if there is
+ // already a printer for that FieldDescriptor.
+ // Takes ownership of the printer on successful registration.
+ bool RegisterFieldValuePrinter(const FieldDescriptor* field,
+ const FieldValuePrinter* printer);
+
private:
// Forward declaration of an internal class used to print the text
// output to the OutputStream (see text_format.cc for implementation).
@@ -181,14 +263,35 @@ class LIBPROTOBUF_EXPORT TextFormat {
bool single_line_mode_;
+ bool use_field_number_;
+
bool use_short_repeated_primitives_;
- bool utf8_string_escaping_;
+ bool hide_unknown_fields_;
+
+ bool print_message_fields_in_index_order_;
+
+ google::protobuf::scoped_ptr<const FieldValuePrinter> default_field_value_printer_;
+ typedef map<const FieldDescriptor*,
+ const FieldValuePrinter*> CustomPrinterMap;
+ CustomPrinterMap custom_printers_;
};
// Parses a text-format protocol message from the given input stream to
- // the given message object. This function parses the format written
- // by Print().
+ // the given message object. This function parses the human-readable format
+ // written by Print(). Returns true on success. The message is cleared first,
+ // even if the function fails -- See Merge() to avoid this behavior.
+ //
+ // Example input: "user {\n id: 123 extra { gender: MALE language: 'en' }\n}"
+ //
+ // One use for this function is parsing handwritten strings in test code.
+ // Another use is to parse the output from google::protobuf::Message::DebugString()
+ // (or ShortDebugString()), because these functions output using
+ // google::protobuf::TextFormat::Print().
+ //
+ // If you would like to read a protocol buffer serialized in the
+ // (non-human-readable) binary wire format, see
+ // google::protobuf::MessageLite::ParseFromString().
static bool Parse(io::ZeroCopyInputStream* input, Message* output);
// Like Parse(), but reads directly from a string.
static bool ParseFromString(const string& input, Message* output);
@@ -220,6 +323,57 @@ class LIBPROTOBUF_EXPORT TextFormat {
const string& name) const = 0;
};
+ // A location in the parsed text.
+ struct ParseLocation {
+ int line;
+ int column;
+
+ ParseLocation() : line(-1), column(-1) {}
+ ParseLocation(int line_param, int column_param)
+ : line(line_param), column(column_param) {}
+ };
+
+ // Data structure which is populated with the locations of each field
+ // value parsed from the text.
+ class LIBPROTOBUF_EXPORT ParseInfoTree {
+ public:
+ ParseInfoTree();
+ ~ParseInfoTree();
+
+ // Returns the parse location for index-th value of the field in the parsed
+ // text. If none exists, returns a location with line = -1. Index should be
+ // -1 for not-repeated fields.
+ ParseLocation GetLocation(const FieldDescriptor* field, int index) const;
+
+ // Returns the parse info tree for the given field, which must be a message
+ // type. The nested information tree is owned by the root tree and will be
+ // deleted when it is deleted.
+ ParseInfoTree* GetTreeForNested(const FieldDescriptor* field,
+ int index) const;
+
+ private:
+ // Allow the text format parser to record information into the tree.
+ friend class TextFormat;
+
+ // Records the starting location of a single value for a field.
+ void RecordLocation(const FieldDescriptor* field, ParseLocation location);
+
+ // Create and records a nested tree for a nested message field.
+ ParseInfoTree* CreateNested(const FieldDescriptor* field);
+
+ // Defines the map from the index-th field descriptor to its parse location.
+ typedef map<const FieldDescriptor*, vector<ParseLocation> > LocationMap;
+
+ // Defines the map from the index-th field descriptor to the nested parse
+ // info tree.
+ typedef map<const FieldDescriptor*, vector<ParseInfoTree*> > NestedMap;
+
+ LocationMap locations_;
+ NestedMap nested_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParseInfoTree);
+ };
+
// For more control over parsing, use this class.
class LIBPROTOBUF_EXPORT Parser {
public:
@@ -248,17 +402,36 @@ class LIBPROTOBUF_EXPORT TextFormat {
finder_ = finder;
}
+ // Sets where location information about the parse will be written. If NULL
+ // (the default), then no location will be written.
+ void WriteLocationsTo(ParseInfoTree* tree) {
+ parse_info_tree_ = tree;
+ }
+
// Normally parsing fails if, after parsing, output->IsInitialized()
// returns false. Call AllowPartialMessage(true) to skip this check.
void AllowPartialMessage(bool allow) {
allow_partial_ = allow;
}
+ // Allow field names to be matched case-insensitively.
+ // This is not advisable if there are fields that only differ in case, or
+ // if you want to enforce writing in the canonical form.
+ // This is 'false' by default.
+ void AllowCaseInsensitiveField(bool allow) {
+ allow_case_insensitive_field_ = allow;
+ }
+
// Like TextFormat::ParseFieldValueFromString
bool ParseFieldValueFromString(const string& input,
const FieldDescriptor* field,
Message* output);
+
+ void AllowFieldNumber(bool allow) {
+ allow_field_number_ = allow;
+ }
+
private:
// Forward declaration of an internal class used to parse text
// representations (see text_format.cc for implementation).
@@ -272,13 +445,43 @@ class LIBPROTOBUF_EXPORT TextFormat {
io::ErrorCollector* error_collector_;
Finder* finder_;
+ ParseInfoTree* parse_info_tree_;
bool allow_partial_;
+ bool allow_case_insensitive_field_;
+ bool allow_unknown_field_;
+ bool allow_unknown_enum_;
+ bool allow_field_number_;
+ bool allow_relaxed_whitespace_;
+ bool allow_singular_overwrites_;
};
+
private:
+ // Hack: ParseInfoTree declares TextFormat as a friend which should extend
+ // the friendship to TextFormat::Parser::ParserImpl, but unfortunately some
+ // old compilers (e.g. GCC 3.4.6) don't implement this correctly. We provide
+ // helpers for ParserImpl to call methods of ParseInfoTree.
+ static inline void RecordLocation(ParseInfoTree* info_tree,
+ const FieldDescriptor* field,
+ ParseLocation location);
+ static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree,
+ const FieldDescriptor* field);
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat);
};
+inline void TextFormat::RecordLocation(ParseInfoTree* info_tree,
+ const FieldDescriptor* field,
+ ParseLocation location) {
+ info_tree->RecordLocation(field, location);
+}
+
+
+inline TextFormat::ParseInfoTree* TextFormat::CreateNested(
+ ParseInfoTree* info_tree, const FieldDescriptor* field) {
+ return info_tree->CreateNested(field);
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 00ea8c3c..477fdcbd 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -74,10 +74,11 @@ const string kEscapeTestStringEscaped =
class TextFormatTest : public testing::Test {
public:
static void SetUpTestCase() {
- File::ReadFileToStringOrDie(
- TestSourceDir()
- + "/google/protobuf/testdata/text_format_unittest_data.txt",
- &static_proto_debug_string_);
+ GOOGLE_CHECK_OK(File::GetContents(
+ TestSourceDir() +
+ "/google/protobuf/"
+ "testdata/text_format_unittest_data_oneof_implemented.txt",
+ &static_proto_debug_string_, true));
}
TextFormatTest() : proto_debug_string_(static_proto_debug_string_) {}
@@ -95,11 +96,10 @@ string TextFormatTest::static_proto_debug_string_;
class TextFormatExtensionsTest : public testing::Test {
public:
static void SetUpTestCase() {
- File::ReadFileToStringOrDie(
- TestSourceDir()
- + "/google/protobuf/testdata/"
- "text_format_unittest_extensions_data.txt",
- &static_proto_debug_string_);
+ GOOGLE_CHECK_OK(File::GetContents(TestSourceDir() +
+ "/google/protobuf/testdata/"
+ "text_format_unittest_extensions_data.txt",
+ &static_proto_debug_string_, true));
}
TextFormatExtensionsTest()
@@ -205,16 +205,25 @@ TEST_F(TextFormatTest, StringEscape) {
TEST_F(TextFormatTest, Utf8DebugString) {
// Set the string value to test.
proto_.set_optional_string("\350\260\267\346\255\214");
+ proto_.set_optional_bytes("\350\260\267\346\255\214");
// Get the DebugString from the proto.
string debug_string = proto_.DebugString();
string utf8_debug_string = proto_.Utf8DebugString();
// Hardcode a correct value to test against.
- string correct_utf8_string = "optional_string: "
+ string correct_utf8_string =
+ "optional_string: "
"\"\350\260\267\346\255\214\""
+ "\n"
+ "optional_bytes: "
+ "\"\\350\\260\\267\\346\\255\\214\""
"\n";
- string correct_string = "optional_string: "
+ string correct_string =
+ "optional_string: "
+ "\"\\350\\260\\267\\346\\255\\214\""
+ "\n"
+ "optional_bytes: "
"\"\\350\\260\\267\\346\\255\\214\""
"\n";
@@ -253,6 +262,31 @@ TEST_F(TextFormatTest, PrintUnknownFields) {
message.DebugString());
}
+TEST_F(TextFormatTest, PrintUnknownFieldsHidden) {
+ // Test printing of unknown fields in a message when suppressed.
+
+ unittest::OneString message;
+ message.set_data("data");
+ UnknownFieldSet* unknown_fields = message.mutable_unknown_fields();
+
+ unknown_fields->AddVarint(5, 1);
+ unknown_fields->AddFixed32(5, 2);
+ unknown_fields->AddFixed64(5, 3);
+ unknown_fields->AddLengthDelimited(5, "4");
+ unknown_fields->AddGroup(5)->AddVarint(10, 5);
+
+ unknown_fields->AddVarint(8, 1);
+ unknown_fields->AddVarint(8, 2);
+ unknown_fields->AddVarint(8, 3);
+
+ TextFormat::Printer printer;
+ printer.SetHideUnknownFields(true);
+ string output;
+ printer.PrintToString(message, &output);
+
+ EXPECT_EQ("data: \"data\"\n", output);
+}
+
TEST_F(TextFormatTest, PrintUnknownMessage) {
// Test heuristic printing of messages in an UnknownFieldSet.
@@ -339,6 +373,161 @@ TEST_F(TextFormatTest, PrintMessageSingleLine) {
text);
}
+TEST_F(TextFormatTest, PrintBufferTooSmall) {
+ // Test printing a message to a buffer that is too small.
+
+ protobuf_unittest::TestAllTypes message;
+
+ message.add_repeated_string("abc");
+ message.add_repeated_string("def");
+
+ char buffer[1] = "";
+ io::ArrayOutputStream output_stream(buffer, 1);
+ EXPECT_FALSE(TextFormat::Print(message, &output_stream));
+ EXPECT_EQ(buffer[0], 'r');
+ EXPECT_EQ(output_stream.ByteCount(), 1);
+}
+
+// A printer that appends 'u' to all unsigned int32.
+class CustomUInt32FieldValuePrinter : public TextFormat::FieldValuePrinter {
+ public:
+ virtual string PrintUInt32(uint32 val) const {
+ return StrCat(FieldValuePrinter::PrintUInt32(val), "u");
+ }
+};
+
+TEST_F(TextFormatTest, DefaultCustomFieldPrinter) {
+ protobuf_unittest::TestAllTypes message;
+
+ message.set_optional_uint32(42);
+ message.add_repeated_uint32(1);
+ message.add_repeated_uint32(2);
+ message.add_repeated_uint32(3);
+
+ TextFormat::Printer printer;
+ printer.SetDefaultFieldValuePrinter(new CustomUInt32FieldValuePrinter());
+ // Let's see if that works well together with the repeated primitives:
+ printer.SetUseShortRepeatedPrimitives(true);
+ string text;
+ printer.PrintToString(message, &text);
+ EXPECT_EQ("optional_uint32: 42u\nrepeated_uint32: [1u, 2u, 3u]\n", text);
+}
+
+class CustomInt32FieldValuePrinter : public TextFormat::FieldValuePrinter {
+ public:
+ virtual string PrintInt32(int32 val) const {
+ return StrCat("value-is(", FieldValuePrinter::PrintInt32(val), ")");
+ }
+};
+
+TEST_F(TextFormatTest, FieldSpecificCustomPrinter) {
+ protobuf_unittest::TestAllTypes message;
+
+ message.set_optional_int32(42); // This will be handled by our Printer.
+ message.add_repeated_int32(42); // This will be printed as number.
+
+ TextFormat::Printer printer;
+ EXPECT_TRUE(printer.RegisterFieldValuePrinter(
+ message.GetDescriptor()->FindFieldByName("optional_int32"),
+ new CustomInt32FieldValuePrinter()));
+ string text;
+ printer.PrintToString(message, &text);
+ EXPECT_EQ("optional_int32: value-is(42)\nrepeated_int32: 42\n", text);
+}
+
+TEST_F(TextFormatTest, ErrorCasesRegisteringFieldValuePrinterShouldFail) {
+ protobuf_unittest::TestAllTypes message;
+ TextFormat::Printer printer;
+ // NULL printer.
+ EXPECT_FALSE(printer.RegisterFieldValuePrinter(
+ message.GetDescriptor()->FindFieldByName("optional_int32"),
+ NULL));
+ // Because registration fails, the ownership of this printer is never taken.
+ TextFormat::FieldValuePrinter my_field_printer;
+ // NULL field
+ EXPECT_FALSE(printer.RegisterFieldValuePrinter(NULL, &my_field_printer));
+}
+
+class CustomMessageFieldValuePrinter : public TextFormat::FieldValuePrinter {
+ public:
+ virtual string PrintInt32(int32 v) const {
+ return StrCat(FieldValuePrinter::PrintInt32(v), " # x", ToHex(v));
+ }
+
+ virtual string PrintMessageStart(const Message& message,
+ int field_index,
+ int field_count,
+ bool single_line_mode) const {
+ if (single_line_mode) {
+ return " { ";
+ }
+ return StrCat(
+ " { # ", message.GetDescriptor()->name(), ": ", field_index, "\n");
+ }
+};
+
+TEST_F(TextFormatTest, CustomPrinterForComments) {
+ protobuf_unittest::TestAllTypes message;
+ message.mutable_optional_nested_message();
+ message.mutable_optional_import_message()->set_d(42);
+ message.add_repeated_nested_message();
+ message.add_repeated_nested_message();
+ message.add_repeated_import_message()->set_d(43);
+ message.add_repeated_import_message()->set_d(44);
+ TextFormat::Printer printer;
+ CustomMessageFieldValuePrinter my_field_printer;
+ printer.SetDefaultFieldValuePrinter(new CustomMessageFieldValuePrinter());
+ string text;
+ printer.PrintToString(message, &text);
+ EXPECT_EQ(
+ "optional_nested_message { # NestedMessage: -1\n"
+ "}\n"
+ "optional_import_message { # ImportMessage: -1\n"
+ " d: 42 # x2a\n"
+ "}\n"
+ "repeated_nested_message { # NestedMessage: 0\n"
+ "}\n"
+ "repeated_nested_message { # NestedMessage: 1\n"
+ "}\n"
+ "repeated_import_message { # ImportMessage: 0\n"
+ " d: 43 # x2b\n"
+ "}\n"
+ "repeated_import_message { # ImportMessage: 1\n"
+ " d: 44 # x2c\n"
+ "}\n",
+ text);
+}
+
+class CustomMultilineCommentPrinter : public TextFormat::FieldValuePrinter {
+ public:
+ virtual string PrintMessageStart(const Message& message,
+ int field_index,
+ int field_count,
+ bool single_line_comment) const {
+ return StrCat(" { # 1\n", " # 2\n");
+ }
+};
+
+TEST_F(TextFormatTest, CustomPrinterForMultilineComments) {
+ protobuf_unittest::TestAllTypes message;
+ message.mutable_optional_nested_message();
+ message.mutable_optional_import_message()->set_d(42);
+ TextFormat::Printer printer;
+ CustomMessageFieldValuePrinter my_field_printer;
+ printer.SetDefaultFieldValuePrinter(new CustomMultilineCommentPrinter());
+ string text;
+ printer.PrintToString(message, &text);
+ EXPECT_EQ(
+ "optional_nested_message { # 1\n"
+ " # 2\n"
+ "}\n"
+ "optional_import_message { # 1\n"
+ " # 2\n"
+ " d: 42\n"
+ "}\n",
+ text);
+}
+
TEST_F(TextFormatTest, ParseBasic) {
io::ArrayInputStream input_stream(proto_debug_string_.data(),
proto_debug_string_.size());
@@ -397,7 +586,7 @@ TEST_F(TextFormatTest, ParseConcatenatedString) {
// Compare.
EXPECT_EQ("foobar", proto_.optional_string());
- // Create a parse string with multiple parts on seperate lines.
+ // Create a parse string with multiple parts on separate lines.
parse_string = "optional_string: \"foo\"\n"
"\"bar\"\n";
@@ -434,7 +623,11 @@ TEST_F(TextFormatTest, ParseShortRepeatedForm) {
" 3]\n"
// Note that while the printer won't print repeated strings in short-form,
// the parser will accept them.
- "repeated_string: [ \"foo\", 'bar' ]\n";
+ "repeated_string: [ \"foo\", 'bar' ]\n"
+ // Repeated message
+ "repeated_nested_message: [ { bb: 1 }, { bb : 2 }]\n"
+ // Repeated group
+ "RepeatedGroup [{ a: 3 },{ a: 4 }]\n";
ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto_));
@@ -451,8 +644,17 @@ TEST_F(TextFormatTest, ParseShortRepeatedForm) {
ASSERT_EQ(2, proto_.repeated_string_size());
EXPECT_EQ("foo", proto_.repeated_string(0));
EXPECT_EQ("bar", proto_.repeated_string(1));
+
+ ASSERT_EQ(2, proto_.repeated_nested_message_size());
+ EXPECT_EQ(1, proto_.repeated_nested_message(0).bb());
+ EXPECT_EQ(2, proto_.repeated_nested_message(1).bb());
+
+ ASSERT_EQ(2, proto_.repeatedgroup_size());
+ EXPECT_EQ(3, proto_.repeatedgroup(0).a());
+ EXPECT_EQ(4, proto_.repeatedgroup(1).a());
}
+
TEST_F(TextFormatTest, Comments) {
// Test that comments are ignored.
@@ -705,6 +907,27 @@ TEST_F(TextFormatTest, ParseExotic) {
message.repeated_string(0));
}
+TEST_F(TextFormatTest, PrintFieldsInIndexOrder) {
+ protobuf_unittest::TestFieldOrderings message;
+ // Fields are listed in index order instead of field number.
+ message.set_my_string("Test String"); // Field number 11
+ message.set_my_int(12345); // Field number 1
+ message.set_my_float(0.999); // Field number 101
+ TextFormat::Printer printer;
+ string text;
+
+ // By default, print in field number order.
+ printer.PrintToString(message, &text);
+ EXPECT_EQ("my_int: 12345\nmy_string: \"Test String\"\nmy_float: 0.999\n",
+ text);
+
+ // Print in index order.
+ printer.SetPrintMessageFieldsInIndexOrder(true);
+ printer.PrintToString(message, &text);
+ EXPECT_EQ("my_string: \"Test String\"\nmy_int: 12345\nmy_float: 0.999\n",
+ text);
+}
+
class TextFormatParserTest : public testing::Test {
protected:
void ExpectFailure(const string& input, const string& message, int line,
@@ -723,11 +946,31 @@ class TextFormatParserTest : public testing::Test {
TextFormat::Parser parser;
MockErrorCollector error_collector;
parser.RecordErrorsTo(&error_collector);
- EXPECT_EQ(parser.ParseFromString(input, proto), expected_result);
+ EXPECT_EQ(expected_result, parser.ParseFromString(input, proto))
+ << input << " -> " << proto->DebugString();
EXPECT_EQ(SimpleItoa(line) + ":" + SimpleItoa(col) + ": " + message + "\n",
error_collector.text_);
}
+ void ExpectSuccessAndTree(const string& input, Message* proto,
+ TextFormat::ParseInfoTree* info_tree) {
+ TextFormat::Parser parser;
+ MockErrorCollector error_collector;
+ parser.RecordErrorsTo(&error_collector);
+ parser.WriteLocationsTo(info_tree);
+
+ EXPECT_TRUE(parser.ParseFromString(input, proto));
+ }
+
+ void ExpectLocation(TextFormat::ParseInfoTree* tree,
+ const Descriptor* d, const string& field_name,
+ int index, int line, int column) {
+ TextFormat::ParseLocation location = tree->GetLocation(
+ d->FindFieldByName(field_name), index);
+ EXPECT_EQ(line, location.line);
+ EXPECT_EQ(column, location.column);
+ }
+
// An error collector which simply concatenates all its errors into a big
// block of text which can be checked.
class MockErrorCollector : public io::ErrorCollector {
@@ -749,6 +992,71 @@ class TextFormatParserTest : public testing::Test {
};
};
+TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) {
+ scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+ const Descriptor* d = message->GetDescriptor();
+
+ string stringData =
+ "optional_int32: 1\n"
+ "optional_int64: 2\n"
+ " optional_double: 2.4\n"
+ "repeated_int32: 5\n"
+ "repeated_int32: 10\n"
+ "optional_nested_message <\n"
+ " bb: 78\n"
+ ">\n"
+ "repeated_nested_message <\n"
+ " bb: 79\n"
+ ">\n"
+ "repeated_nested_message <\n"
+ " bb: 80\n"
+ ">";
+
+
+ TextFormat::ParseInfoTree tree;
+ ExpectSuccessAndTree(stringData, message.get(), &tree);
+
+ // Verify that the tree has the correct positions.
+ ExpectLocation(&tree, d, "optional_int32", -1, 0, 0);
+ ExpectLocation(&tree, d, "optional_int64", -1, 1, 0);
+ ExpectLocation(&tree, d, "optional_double", -1, 2, 2);
+
+ ExpectLocation(&tree, d, "repeated_int32", 0, 3, 0);
+ ExpectLocation(&tree, d, "repeated_int32", 1, 4, 0);
+
+ ExpectLocation(&tree, d, "optional_nested_message", -1, 5, 0);
+ ExpectLocation(&tree, d, "repeated_nested_message", 0, 8, 0);
+ ExpectLocation(&tree, d, "repeated_nested_message", 1, 11, 0);
+
+ // Check for fields not set. For an invalid field, the location returned
+ // should be -1, -1.
+ ExpectLocation(&tree, d, "repeated_int64", 0, -1, -1);
+ ExpectLocation(&tree, d, "repeated_int32", 6, -1, -1);
+ ExpectLocation(&tree, d, "some_unknown_field", -1, -1, -1);
+
+ // Verify inside the nested message.
+ const FieldDescriptor* nested_field =
+ d->FindFieldByName("optional_nested_message");
+
+ TextFormat::ParseInfoTree* nested_tree =
+ tree.GetTreeForNested(nested_field, -1);
+ ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 6, 2);
+
+ // Verify inside another nested message.
+ nested_field = d->FindFieldByName("repeated_nested_message");
+ nested_tree = tree.GetTreeForNested(nested_field, 0);
+ ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 9, 2);
+
+ nested_tree = tree.GetTreeForNested(nested_field, 1);
+ ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 12, 2);
+
+ // Verify a NULL tree for an unknown nested field.
+ TextFormat::ParseInfoTree* unknown_nested_tree =
+ tree.GetTreeForNested(nested_field, 2);
+
+ EXPECT_EQ(NULL, unknown_nested_tree);
+}
+
TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
const Descriptor* d = message->GetDescriptor();
@@ -759,6 +1067,12 @@ TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
EXPECT_EQ(value, message->optional_##name()); \
EXPECT_TRUE(message->has_optional_##name());
+#define EXPECT_BOOL_FIELD(name, value, valuestring) \
+ EXPECT_TRUE(TextFormat::ParseFieldValueFromString( \
+ valuestring, d->FindFieldByName("optional_" #name), message.get())); \
+ EXPECT_TRUE(message->optional_##name() == value); \
+ EXPECT_TRUE(message->has_optional_##name());
+
#define EXPECT_FLOAT_FIELD(name, value, valuestring) \
EXPECT_TRUE(TextFormat::ParseFieldValueFromString( \
valuestring, d->FindFieldByName("optional_" #name), message.get())); \
@@ -816,17 +1130,20 @@ TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
EXPECT_INVALID(fixed64, "1,2");
// bool
- EXPECT_FIELD(bool, true, "true");
- EXPECT_FIELD(bool, false, "false");
- EXPECT_FIELD(bool, true, "1");
- EXPECT_FIELD(bool, true, "t");
- EXPECT_FIELD(bool, false, "0");
- EXPECT_FIELD(bool, false, "f");
+ EXPECT_BOOL_FIELD(bool, true, "true");
+ EXPECT_BOOL_FIELD(bool, false, "false");
+ EXPECT_BOOL_FIELD(bool, true, "1");
+ EXPECT_BOOL_FIELD(bool, true, "t");
+ EXPECT_BOOL_FIELD(bool, false, "0");
+ EXPECT_BOOL_FIELD(bool, false, "f");
+ EXPECT_FIELD(bool, true, "True");
+ EXPECT_FIELD(bool, false, "False");
+ EXPECT_INVALID(bool, "tRue");
+ EXPECT_INVALID(bool, "faLse");
EXPECT_INVALID(bool, "2");
EXPECT_INVALID(bool, "-0");
EXPECT_INVALID(bool, "on");
EXPECT_INVALID(bool, "a");
- EXPECT_INVALID(bool, "True");
// float
EXPECT_FIELD(float, 1, "1");
@@ -843,6 +1160,9 @@ TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
EXPECT_DOUBLE_FIELD(double, 3e5, "3e5");
EXPECT_INVALID(double, "a");
EXPECT_INVALID(double, "1,2");
+ // Rejects hex and oct numbers for a double field.
+ EXPECT_INVALID(double, "0xf");
+ EXPECT_INVALID(double, "012");
// string
EXPECT_FIELD(string, "hello", "\"hello\"");
@@ -863,6 +1183,7 @@ TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
EXPECT_INVALID(nested_message, "any");
#undef EXPECT_FIELD
+#undef EXPECT_BOOL_FIELD
#undef EXPECT_FLOAT_FIELD
#undef EXPECT_DOUBLE_FIELD
#undef EXPECT_INVALID
@@ -904,6 +1225,22 @@ TEST_F(TextFormatParserTest, InvalidCapitalization) {
1, 16);
}
+TEST_F(TextFormatParserTest, AllowIgnoreCapitalizationError) {
+ TextFormat::Parser parser;
+ protobuf_unittest::TestAllTypes proto;
+
+ // These fields have a mismatching case.
+ EXPECT_FALSE(parser.ParseFromString("Optional_Double: 10.0", &proto));
+ EXPECT_FALSE(parser.ParseFromString("oPtIoNaLgRoUp { a: 15 }", &proto));
+
+ // ... but are parsed correctly if we match case insensitive.
+ parser.AllowCaseInsensitiveField(true);
+ EXPECT_TRUE(parser.ParseFromString("Optional_Double: 10.0", &proto));
+ EXPECT_EQ(10.0, proto.optional_double());
+ EXPECT_TRUE(parser.ParseFromString("oPtIoNaLgRoUp { a: 15 }", &proto));
+ EXPECT_EQ(15, proto.optionalgroup().a());
+}
+
TEST_F(TextFormatParserTest, InvalidFieldValues) {
// Invalid values for a double/float field.
ExpectFailure("optional_double: \"hello\"\n", "Expected double.", 1, 18);
@@ -921,10 +1258,10 @@ TEST_F(TextFormatParserTest, InvalidFieldValues) {
1, 16);
ExpectFailure("optional_int32: 0x80000000\n",
"Integer out of range.", 1, 17);
- ExpectFailure("optional_int32: -0x80000001\n",
- "Integer out of range.", 1, 18);
ExpectFailure("optional_int64: 0x8000000000000000\n",
"Integer out of range.", 1, 17);
+ ExpectFailure("optional_int32: -0x80000001\n",
+ "Integer out of range.", 1, 18);
ExpectFailure("optional_int64: -0x8000000000000001\n",
"Integer out of range.", 1, 18);
@@ -987,12 +1324,12 @@ TEST_F(TextFormatParserTest, InvalidFieldValues) {
"Expected \":\", found \"{\".", 1, 22);
}
-TEST_F(TextFormatParserTest, MessageDelimeters) {
- // Non-matching delimeters.
+TEST_F(TextFormatParserTest, MessageDelimiters) {
+ // Non-matching delimiters.
ExpectFailure("OptionalGroup <\n \n}\n", "Expected \">\", found \"}\".",
3, 1);
- // Invalid delimeters.
+ // Invalid delimiters.
ExpectFailure("OptionalGroup [\n \n]\n", "Expected \"{\", found \"[\".",
1, 15);
@@ -1003,7 +1340,7 @@ TEST_F(TextFormatParserTest, MessageDelimeters) {
}
TEST_F(TextFormatParserTest, UnknownExtension) {
- // Non-matching delimeters.
+ // Non-matching delimiters.
ExpectFailure("[blahblah]: 123",
"Extension \"blahblah\" is not defined or is not an "
"extension of \"protobuf_unittest.TestAllTypes\".",
@@ -1136,6 +1473,7 @@ TEST_F(TextFormatMessageSetTest, Deserialize) {
EXPECT_EQ(2, descriptors.size());
}
+
} // namespace text_format_unittest
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto
new file mode 100644
index 00000000..ac8e009c
--- /dev/null
+++ b/src/google/protobuf/timestamp.proto
@@ -0,0 +1,103 @@
+// 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 google.protobuf;
+
+option java_generate_equals_and_hash = true;
+option java_multiple_files = true;
+option java_outer_classname = "TimestampProto";
+option java_package = "com.google.protobuf";
+
+
+// A Timestamp represents a point in time independent of any time zone
+// or calendar, represented as seconds and fractions of seconds at
+// nanosecond resolution in UTC Epoch time. It is encoded using the
+// Proleptic Gregorian Calendar which extends the Gregorian calendar
+// backwards to year one. It is encoded assuming all minutes are 60
+// seconds long, i.e. leap seconds are "smeared" so that no leap second
+// table is needed for interpretation. Range is from
+// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
+// By restricting to that range, we ensure that we can convert to
+// and from RFC 3339 date strings. (See https://www.ietf.org/rfc/rfc3339.txt.)
+//
+// Example 1: compute Timestamp from POSIX `time()`.
+//
+// Timestamp timestamp;
+// timestamp.set_seconds(time(NULL));
+// timestamp.set_nanos(0);
+//
+// Example 2: compute Timestamp from POSIX `gettimeofday()`.
+//
+// struct timeval tv;
+// gettimeofday(&tv, NULL);
+//
+// Timestamp timestamp;
+// timestamp.set_seconds(tv.tv_sec);
+// timestamp.set_nanos(tv.tv_usec * 1000);
+//
+// Example 3: compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+//
+// FILETIME ft;
+// GetSystemTimeAsFileTime(&ft);
+// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+//
+// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+// Timestamp timestamp;
+// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+//
+// Example 4: compute Timestamp from Java `System.currentTimeMillis()`.
+//
+// long millis = System.currentTimeMillis();
+//
+// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+// .setNanos((int) ((millis % 1000) * 1000000)).build();
+//
+// Example 5: compute Timestamp from Python `datetime.datetime`.
+//
+// now = datetime.datetime.utcnow()
+// seconds = int(time.mktime(now.timetuple()))
+// nanos = now.microsecond * 1000
+// timestamp = Timestamp(seconds=seconds, nanos=nanos)
+//
+message Timestamp {
+ // Represents seconds of UTC time since Unix epoch
+ // 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
+ // 9999-12-31T23:59:59Z inclusive.
+ int64 seconds = 1;
+
+ // Non-negative fractions of a second at nanosecond resolution. Negative
+ // second values with fractions must still have non-negative nanos values
+ // that count forward in time. Must be from 0 to 999,999,999
+ // inclusive.
+ int32 nanos = 2;
+}
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index 97ec6747..745f77c5 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,12 +34,14 @@
//
// 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
option cc_generic_services = true; // auto-added
option java_generic_services = true; // auto-added
option py_generic_services = true; // auto-added
+option cc_enable_arenas = true;
import "google/protobuf/unittest_import.proto";
@@ -69,6 +71,7 @@ message TestAllTypes {
FOO = 1;
BAR = 2;
BAZ = 3;
+ NEG = -1; // Intentionally negative.
}
// Singular
@@ -103,6 +106,12 @@ message TestAllTypes {
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;
@@ -135,6 +144,8 @@ message TestAllTypes {
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 ];
@@ -159,6 +170,20 @@ message TestAllTypes {
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;
+ }
+}
+
+// This proto includes a recusively nested message.
+message NestedTestAllTypes {
+ optional NestedTestAllTypes child = 1;
+ optional TestAllTypes payload = 2;
}
message TestDeprecatedFields {
@@ -216,6 +241,12 @@ extend TestAllExtensions {
optional string optional_string_piece_extension = 24 [ctype=STRING_PIECE];
optional string optional_cord_extension = 25 [ctype=CORD];
+ optional protobuf_unittest_import.PublicImportMessage
+ optional_public_import_message_extension = 26;
+
+ optional TestAllTypes.NestedMessage
+ optional_lazy_message_extension = 27 [lazy=true];
+
// Repeated
repeated int32 repeated_int32_extension = 31;
repeated int64 repeated_int64_extension = 32;
@@ -250,6 +281,9 @@ extend TestAllExtensions {
repeated string repeated_string_piece_extension = 54 [ctype=STRING_PIECE];
repeated string repeated_cord_extension = 55 [ctype=CORD];
+ repeated TestAllTypes.NestedMessage
+ repeated_lazy_message_extension = 57 [lazy=true];
+
// Singular with defaults
optional int32 default_int32_extension = 61 [default = 41 ];
optional int64 default_int64_extension = 62 [default = 42 ];
@@ -277,6 +311,12 @@ extend TestAllExtensions {
optional string default_string_piece_extension = 84 [ctype=STRING_PIECE,
default="abc"];
optional string default_cord_extension = 85 [ctype=CORD, default="123"];
+
+ // For oneof test
+ optional uint32 oneof_uint32_extension = 111;
+ optional TestAllTypes.NestedMessage oneof_nested_message_extension = 112;
+ optional string oneof_string_extension = 113;
+ optional bytes oneof_bytes_extension = 114;
}
message TestNestedExtension {
@@ -284,6 +324,9 @@ message TestNestedExtension {
// Check for bug where string extensions declared in tested scope did not
// compile.
optional string test = 1002 [default="test"];
+ // Used to test if generated extension name is correct when there are
+ // underscores.
+ optional string nested_string_extension = 1003;
}
}
@@ -388,7 +431,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
@@ -397,6 +440,13 @@ message TestDupFieldNumber { // NO_PROTO1
optional group Bar = 3 { optional int32 a = 1; } // NO_PROTO1
} // NO_PROTO1
+// Additional messages for testing lazy fields.
+message TestEagerMessage {
+ optional TestAllTypes sub_message = 1 [lazy=false];
+}
+message TestLazyMessage {
+ optional TestAllTypes sub_message = 1 [lazy=true];
+}
// Needed for a Python test.
message TestNestedMessageHasBits {
@@ -410,6 +460,8 @@ message TestNestedMessageHasBits {
// Test an enum that has multiple values with the same number.
enum TestEnumWithDupValue {
+ option allow_alias = true;
+
FOO1 = 1;
BAR1 = 2;
BAZ = 3;
@@ -455,6 +507,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;
}
@@ -470,6 +531,8 @@ message TestExtremeDefaultValues {
optional uint64 large_uint64 = 3 [default = 0xFFFFFFFFFFFFFFFF];
optional int32 small_int32 = 4 [default = -0x7FFFFFFF];
optional int64 small_int64 = 5 [default = -0x7FFFFFFFFFFFFFFF];
+ optional int32 really_small_int32 = 21 [default = -0x80000000];
+ optional int64 really_small_int64 = 22 [default = -0x8000000000000000];
// The default value here is UTF-8 for "\u1234". (We could also just type
// the UTF-8 text directly into this text file rather than escape it, but
@@ -500,6 +563,15 @@ message TestExtremeDefaultValues {
// Note that in .proto file, "\?" is a valid way to escape ? in string
// literals.
optional string cpp_trigraph = 20 [default = "? \? ?? \?? \??? ??/ ?\?-"];
+
+ // String defaults containing the character '\000'
+ optional string string_with_zero = 23 [default = "hel\000lo"];
+ optional bytes bytes_with_zero = 24 [default = "wor\000ld"];
+ optional string string_piece_with_zero = 25 [ctype=STRING_PIECE,
+ default="ab\000c"];
+ optional string cord_with_zero = 26 [ctype=CORD,
+ default="12\0003"];
+ optional string replacement_string = 27 [default="${unknown}"];
}
message SparseEnumMessage {
@@ -511,10 +583,113 @@ message OneString {
optional string data = 1;
}
+message MoreString {
+ repeated string data = 1;
+}
+
message OneBytes {
optional bytes data = 1;
}
+message MoreBytes {
+ repeated bytes data = 1;
+}
+
+// Test int32, uint32, int64, uint64, and bool are all compatible
+message Int32Message {
+ optional int32 data = 1;
+}
+
+message Uint32Message {
+ optional uint32 data = 1;
+}
+
+message Int64Message {
+ optional int64 data = 1;
+}
+
+message Uint64Message {
+ optional uint64 data = 1;
+}
+
+message BoolMessage {
+ optional bool data = 1;
+}
+
+// Test oneofs.
+message TestOneof {
+ oneof foo {
+ int32 foo_int = 1;
+ string foo_string = 2;
+ TestAllTypes foo_message = 3;
+ group FooGroup = 4 {
+ optional int32 a = 5;
+ optional string b = 6;
+ }
+ }
+}
+
+message TestOneofBackwardsCompatible {
+ optional int32 foo_int = 1;
+ optional string foo_string = 2;
+ optional TestAllTypes foo_message = 3;
+ optional group FooGroup = 4 {
+ optional int32 a = 5;
+ optional string b = 6;
+ }
+}
+
+message TestOneof2 {
+ oneof foo {
+ int32 foo_int = 1;
+ string foo_string = 2;
+ string foo_cord = 3 [ctype=CORD];
+ string foo_string_piece = 4 [ctype=STRING_PIECE];
+ bytes foo_bytes = 5;
+ NestedEnum foo_enum = 6;
+ NestedMessage foo_message = 7;
+ group FooGroup = 8 {
+ optional int32 a = 9;
+ optional string b = 10;
+ }
+ NestedMessage foo_lazy_message = 11 [lazy=true];
+ }
+
+ oneof bar {
+ int32 bar_int = 12 [default = 5];
+ string bar_string = 13 [default = "STRING"];
+ string bar_cord = 14 [ctype=CORD, default = "CORD"];
+ string bar_string_piece = 15 [ctype=STRING_PIECE, default = "SPIECE"];
+ bytes bar_bytes = 16 [default = "BYTES"];
+ NestedEnum bar_enum = 17 [default = BAR];
+ }
+
+ optional int32 baz_int = 18;
+ optional string baz_string = 19 [default = "BAZ"];
+
+ message NestedMessage {
+ optional int64 qux_int = 1;
+ repeated int32 corge_int = 2;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+}
+
+message TestRequiredOneof {
+ oneof foo {
+ int32 foo_int = 1;
+ string foo_string = 2;
+ NestedMessage foo_message = 3;
+ }
+ message NestedMessage {
+ required double required_double = 1;
+ }
+}
+
// Test messages for packed fields
message TestPackedTypes {
@@ -574,6 +749,27 @@ extend TestPackedExtensions {
repeated ForeignEnum packed_enum_extension = 103 [packed = true];
}
+message TestUnpackedExtensions {
+ extensions 1 to max;
+}
+
+extend TestUnpackedExtensions {
+ repeated int32 unpacked_int32_extension = 90 [packed = false];
+ repeated int64 unpacked_int64_extension = 91 [packed = false];
+ repeated uint32 unpacked_uint32_extension = 92 [packed = false];
+ repeated uint64 unpacked_uint64_extension = 93 [packed = false];
+ repeated sint32 unpacked_sint32_extension = 94 [packed = false];
+ repeated sint64 unpacked_sint64_extension = 95 [packed = false];
+ repeated fixed32 unpacked_fixed32_extension = 96 [packed = false];
+ repeated fixed64 unpacked_fixed64_extension = 97 [packed = false];
+ repeated sfixed32 unpacked_sfixed32_extension = 98 [packed = false];
+ repeated sfixed64 unpacked_sfixed64_extension = 99 [packed = false];
+ repeated float unpacked_float_extension = 100 [packed = false];
+ repeated double unpacked_double_extension = 101 [packed = false];
+ repeated bool unpacked_bool_extension = 102 [packed = false];
+ repeated ForeignEnum unpacked_enum_extension = 103 [packed = false];
+}
+
// Used by ExtensionSetTest/DynamicExtensions. The test actually builds
// a set of extensions to TestAllExtensions dynamically, based on the fields
// of this message type.
@@ -615,11 +811,56 @@ message TestRepeatedScalarDifferentTagSizes {
repeated uint64 repeated_uint64 = 262143;
}
+// Test that if an optional or required message/group field appears multiple
+// times in the input, they need to be merged.
+message TestParsingMerge {
+ // RepeatedFieldsGenerator defines matching field types as TestParsingMerge,
+ // except that all fields are repeated. In the tests, we will serialize the
+ // RepeatedFieldsGenerator to bytes, and parse the bytes to TestParsingMerge.
+ // Repeated fields in RepeatedFieldsGenerator are expected to be merged into
+ // the corresponding required/optional fields in TestParsingMerge.
+ message RepeatedFieldsGenerator {
+ repeated TestAllTypes field1 = 1;
+ repeated TestAllTypes field2 = 2;
+ repeated TestAllTypes field3 = 3;
+ repeated group Group1 = 10 {
+ optional TestAllTypes field1 = 11;
+ }
+ repeated group Group2 = 20 {
+ optional TestAllTypes field1 = 21;
+ }
+ repeated TestAllTypes ext1 = 1000;
+ repeated TestAllTypes ext2 = 1001;
+ }
+ required TestAllTypes required_all_types = 1;
+ optional TestAllTypes optional_all_types = 2;
+ repeated TestAllTypes repeated_all_types = 3;
+ optional group OptionalGroup = 10 {
+ optional TestAllTypes optional_group_all_types = 11;
+ }
+ repeated group RepeatedGroup = 20 {
+ optional TestAllTypes repeated_group_all_types = 21;
+ }
+ extensions 1000 to max;
+ extend TestParsingMerge {
+ optional TestAllTypes optional_ext = 1000;
+ repeated TestAllTypes repeated_ext = 1001;
+ }
+}
+
+message TestCommentInjectionMessage {
+ // */ <- This should not close the generated doc comment
+ optional string a = 1 [default="*/ <- Neither should this."];
+}
+
// Test that RPC services work.
message FooRequest {}
message FooResponse {}
+message FooClientMessage {}
+message FooServerMessage{}
+
service TestService {
rpc Foo(FooRequest) returns (FooResponse);
rpc Bar(BarRequest) returns (BarResponse);
@@ -628,3 +869,4 @@ service TestService {
message BarRequest {}
message BarResponse {}
+
diff --git a/src/google/protobuf/unittest_arena.proto b/src/google/protobuf/unittest_arena.proto
new file mode 100644
index 00000000..cd7e437e
--- /dev/null
+++ b/src/google/protobuf/unittest_arena.proto
@@ -0,0 +1,46 @@
+// 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;
+
+option cc_enable_arenas = true;
+
+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 a610785f..d4d6e869 100644
--- a/src/google/protobuf/unittest_custom_options.proto
+++ b/src/google/protobuf/unittest_custom_options.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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
@@ -116,6 +117,12 @@ message CustomOptionFooRequest {
message CustomOptionFooResponse {
}
+message CustomOptionFooClientMessage {
+}
+
+message CustomOptionFooServerMessage {
+}
+
service TestServiceWithCustomOptions {
option (service_opt1) = -9876543210;
@@ -212,6 +219,7 @@ message ComplexOptionType1 {
optional int32 foo = 1;
optional int32 foo2 = 2;
optional int32 foo3 = 3;
+ repeated int32 foo4 = 4;
extensions 100 to max;
}
@@ -229,6 +237,7 @@ message ComplexOptionType2 {
}
optional ComplexOptionType4 fred = 3;
+ repeated ComplexOptionType4 barney = 4;
extensions 100 to max;
}
@@ -265,6 +274,8 @@ message VariousComplexOptions {
option (.protobuf_unittest.complex_opt1).foo = 42;
option (protobuf_unittest.complex_opt1).(.protobuf_unittest.quux) = 324;
option (.protobuf_unittest.complex_opt1).(protobuf_unittest.corge).qux = 876;
+ option (protobuf_unittest.complex_opt1).foo4 = 99;
+ option (protobuf_unittest.complex_opt1).foo4 = 88;
option (complex_opt2).baz = 987;
option (complex_opt2).(grault) = 654;
option (complex_opt2).bar.foo = 743;
@@ -275,6 +286,8 @@ message VariousComplexOptions {
option (complex_opt2).(protobuf_unittest.garply).(corge).qux = 2121;
option (ComplexOptionType2.ComplexOptionType4.complex_opt4).waldo = 1971;
option (complex_opt2).fred.waldo = 321;
+ option (complex_opt2).barney = { waldo: 101 };
+ option (complex_opt2).barney = { waldo: 212 };
option (protobuf_unittest.complex_opt3).qux = 9;
option (complex_opt3).complexoptiontype5.plugh = 22;
option (complexopt6).xyzzy = 24;
@@ -364,3 +377,18 @@ enum AggregateEnum {
option (enumopt) = { s:'EnumAnnotation' };
VALUE = 1 [(enumvalopt) = { s:'EnumValueAnnotation' }];
}
+
+// Test custom options for nested type.
+message NestedOptionType {
+ message NestedMessage {
+ option (message_opt1) = 1001;
+ optional int32 nested_field = 1 [(field_opt1) = 1002];
+ }
+ enum NestedEnum {
+ option (enum_opt1) = 1003;
+ NESTED_ENUM_VALUE = 1 [(enum_value_opt1) = 1004];
+ }
+ extend google.protobuf.FileOptions {
+ optional int32 nested_extension = 7912573 [(field_opt2) = 1005];
+ }
+}
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 fa176259..d8b0f9b9 100644
--- a/src/google/protobuf/unittest_embed_optimize_for.proto
+++ b/src/google/protobuf/unittest_embed_optimize_for.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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 ab12d1fb..36443e7e 100644
--- a/src/google/protobuf/unittest_empty.proto
+++ b/src/google/protobuf/unittest_empty.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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 bc0b7c16..2250261d 100644
--- a/src/google/protobuf/unittest_enormous_descriptor.proto
+++ b/src/google/protobuf/unittest_enormous_descriptor.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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 cd533ecd..7e165220 100644
--- a/src/google/protobuf/unittest_import.proto
+++ b/src/google/protobuf/unittest_import.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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.
@@ -42,13 +43,17 @@
package protobuf_unittest_import;
option optimize_for = SPEED;
+option cc_enable_arenas = true;
-// Excercise the java_package option.
+// Exercise the java_package option.
option java_package = "com.google.protobuf.test";
// Do not set a java_outer_classname here to verify that Proto2 works without
// one.
+// Test public import
+import public "google/protobuf/unittest_import_public.proto";
+
message ImportMessage {
optional int32 d = 1;
}
diff --git a/src/google/protobuf/unittest_import_lite.proto b/src/google/protobuf/unittest_import_lite.proto
index ebaab5c0..a7afa452 100644
--- a/src/google/protobuf/unittest_import_lite.proto
+++ b/src/google/protobuf/unittest_import_lite.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,12 +32,15 @@
//
// This is like unittest_import.proto but with optimize_for = LITE_RUNTIME.
+syntax = "proto2";
package protobuf_unittest_import;
option optimize_for = LITE_RUNTIME;
option java_package = "com.google.protobuf";
+import public "google/protobuf/unittest_import_public_lite.proto";
+
message ImportMessageLite {
optional int32 d = 1;
}
diff --git a/src/google/protobuf/unittest_import_public.proto b/src/google/protobuf/unittest_import_public.proto
new file mode 100644
index 00000000..ffaf7736
--- /dev/null
+++ b/src/google/protobuf/unittest_import_public.proto
@@ -0,0 +1,41 @@
+// 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: liujisi@google.com (Pherl Liu)
+
+syntax = "proto2";
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.test";
+
+message PublicImportMessage {
+ optional int32 e = 1;
+}
diff --git a/src/google/protobuf/unittest_import_public_lite.proto b/src/google/protobuf/unittest_import_public_lite.proto
new file mode 100644
index 00000000..33549c22
--- /dev/null
+++ b/src/google/protobuf/unittest_import_public_lite.proto
@@ -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.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+syntax = "proto2";
+
+package protobuf_unittest_import;
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+message PublicImportMessageLite {
+ optional int32 e = 1;
+}
diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto
index cca6b497..662c0e46 100644
--- a/src/google/protobuf/unittest_lite.proto
+++ b/src/google/protobuf/unittest_lite.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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";
@@ -85,6 +86,12 @@ message TestAllTypesLite {
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.PublicImportMessageLite
+ optional_public_import_message = 26;
+
+ optional NestedMessage optional_lazy_message = 27 [lazy=true];
+
// Repeated
repeated int32 repeated_int32 = 31;
repeated int64 repeated_int64 = 32;
@@ -118,6 +125,8 @@ message TestAllTypesLite {
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 ];
@@ -143,6 +152,14 @@ message TestAllTypesLite {
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;
+ }
}
message ForeignMessageLite {
@@ -213,6 +230,12 @@ extend TestAllExtensionsLite {
[ctype=STRING_PIECE];
optional string optional_cord_extension_lite = 25 [ctype=CORD];
+ optional protobuf_unittest_import.PublicImportMessageLite
+ optional_public_import_message_extension_lite = 26;
+
+ optional TestAllTypesLite.NestedMessage
+ optional_lazy_message_extension_lite = 27 [lazy=true];
+
// Repeated
repeated int32 repeated_int32_extension_lite = 31;
repeated int64 repeated_int64_extension_lite = 32;
@@ -249,6 +272,9 @@ extend TestAllExtensionsLite {
[ctype=STRING_PIECE];
repeated string repeated_cord_extension_lite = 55 [ctype=CORD];
+ repeated TestAllTypesLite.NestedMessage
+ repeated_lazy_message_extension_lite = 57 [lazy=true];
+
// Singular with defaults
optional int32 default_int32_extension_lite = 61 [default = 41 ];
optional int64 default_int64_extension_lite = 62 [default = 42 ];
@@ -276,6 +302,12 @@ extend TestAllExtensionsLite {
optional string default_string_piece_extension_lite = 84 [ctype=STRING_PIECE,
default="abc"];
optional string default_cord_extension_lite = 85 [ctype=CORD, default="123"];
+
+ // For oneof test
+ optional uint32 oneof_uint32_extension_lite = 111;
+ optional TestAllTypesLite.NestedMessage oneof_nested_message_extension_lite = 112;
+ optional string oneof_string_extension_lite = 113;
+ optional bytes oneof_bytes_extension_lite = 114;
}
message TestPackedExtensionsLite {
@@ -310,3 +342,44 @@ message TestNestedExtensionLite {
message TestDeprecatedLite {
optional int32 deprecated_field = 1 [deprecated = true];
}
+
+// See the comments of the same type in unittest.proto.
+message TestParsingMergeLite {
+ message RepeatedFieldsGenerator {
+ repeated TestAllTypesLite field1 = 1;
+ repeated TestAllTypesLite field2 = 2;
+ repeated TestAllTypesLite field3 = 3;
+ repeated group Group1 = 10 {
+ optional TestAllTypesLite field1 = 11;
+ }
+ repeated group Group2 = 20 {
+ optional TestAllTypesLite field1 = 21;
+ }
+ repeated TestAllTypesLite ext1 = 1000;
+ repeated TestAllTypesLite ext2 = 1001;
+ }
+ required TestAllTypesLite required_all_types = 1;
+ optional TestAllTypesLite optional_all_types = 2;
+ repeated TestAllTypesLite repeated_all_types = 3;
+ optional group OptionalGroup = 10 {
+ optional TestAllTypesLite optional_group_all_types = 11;
+ }
+ repeated group RepeatedGroup = 20 {
+ optional TestAllTypesLite repeated_group_all_types = 21;
+ }
+ extensions 1000 to max;
+ extend TestParsingMergeLite {
+ optional TestAllTypesLite optional_ext = 1000;
+ repeated TestAllTypesLite repeated_ext = 1001;
+ }
+}
+
+// TestEmptyMessageLite is used to test unknown fields support in lite mode.
+message TestEmptyMessageLite{
+}
+
+// Like above, but declare all field numbers as potential extensions. No
+// actual extensions should ever be defined for this type.
+message TestEmptyMessageWithExtensionsLite {
+ extensions 1 to max;
+}
diff --git a/src/google/protobuf/unittest_lite_imports_nonlite.proto b/src/google/protobuf/unittest_lite_imports_nonlite.proto
index d52cb8cc..132d6a82 100644
--- a/src/google/protobuf/unittest_lite_imports_nonlite.proto
+++ b/src/google/protobuf/unittest_lite_imports_nonlite.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -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 3497f09f..3aa31fa9 100644
--- a/src/google/protobuf/unittest_mset.proto
+++ b/src/google/protobuf/unittest_mset.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,8 +34,10 @@
//
// This file contains messages for testing message_set_wire_format.
+syntax = "proto2";
package protobuf_unittest;
+option cc_enable_arenas = true;
option optimize_for = SPEED;
// A message with message_set_wire_format.
@@ -62,6 +64,17 @@ message TestMessageSetExtension2 {
optional string str = 25;
}
+// This message was used to generate
+// //net/proto2/python/internal/testdata/message_set_message, but is commented
+// out since it must not actually exist in code, to simulate an "unknown"
+// extension.
+// message TestMessageSetUnknownExtension {
+// extend TestMessageSet {
+// optional TestMessageSetUnknownExtension message_set_extension = 56141421;
+// }
+// optional int64 a = 1;
+// }
+
// MessageSet wire format is equivalent to this.
message RawMessageSet {
repeated group Item = 1 {
diff --git a/src/google/protobuf/unittest_no_arena.proto b/src/google/protobuf/unittest_no_arena.proto
new file mode 100644
index 00000000..36fb8656
--- /dev/null
+++ b/src/google/protobuf/unittest_no_arena.proto
@@ -0,0 +1,201 @@
+// 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
+option cc_enable_arenas = false;
+
+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_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;
+ NestedMessage lazy_oneof_nested_message = 115 [lazy=true];
+ }
+}
+
+// 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 cffb4122..8fc7713c 100644
--- a/src/google/protobuf/unittest_no_generic_services.proto
+++ b/src/google/protobuf/unittest_no_generic_services.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -30,8 +30,10 @@
// Author: kenton@google.com (Kenton Varda)
+syntax = "proto2";
package google.protobuf.no_generic_services_test;
+
// *_generic_services are false by default.
message TestMessage {
diff --git a/src/google/protobuf/unittest_optimize_for.proto b/src/google/protobuf/unittest_optimize_for.proto
index feecbef8..ee9cc7bd 100644
--- a/src/google/protobuf/unittest_optimize_for.proto
+++ b/src/google/protobuf/unittest_optimize_for.proto
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -34,6 +34,7 @@
//
// A proto file which uses optimize_for = CODE_SIZE.
+syntax = "proto2";
import "google/protobuf/unittest.proto";
package protobuf_unittest;
@@ -50,12 +51,17 @@ message TestOptimizedForSize {
optional int32 test_extension = 1234;
optional TestRequiredOptimizedForSize test_extension2 = 1235;
}
+
+ oneof foo {
+ int32 integer_field = 2;
+ string string_field = 3;
+ }
}
message TestRequiredOptimizedForSize {
required int32 x = 1;
}
-
+
message TestOptionalOptimizedForSize {
optional TestRequiredOptimizedForSize o = 1;
}
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..67e57499
--- /dev/null
+++ b/src/google/protobuf/unittest_preserve_unknown_enum.proto
@@ -0,0 +1,68 @@
+// 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 proto3_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];
+ repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4; // not packed
+ oneof o {
+ MyEnum oneof_e_1 = 5;
+ MyEnum oneof_e_2 = 6;
+ }
+}
+
+message MyMessagePlusExtra {
+ optional MyEnumPlusExtra e = 1;
+ repeated MyEnumPlusExtra repeated_e = 2;
+ repeated MyEnumPlusExtra repeated_packed_e = 3 [packed=true];
+ repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4 [packed=true];
+ oneof o {
+ MyEnumPlusExtra oneof_e_1 = 5;
+ MyEnumPlusExtra oneof_e_2 = 6;
+ }
+}
diff --git a/src/google/protobuf/unittest_preserve_unknown_enum2.proto b/src/google/protobuf/unittest_preserve_unknown_enum2.proto
new file mode 100644
index 00000000..adf42968
--- /dev/null
+++ b/src/google/protobuf/unittest_preserve_unknown_enum2.proto
@@ -0,0 +1,50 @@
+// 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_preserve_unknown_enum_unittest;
+
+enum MyEnum {
+ FOO = 0;
+ BAR = 1;
+ BAZ = 2;
+}
+
+message MyMessage {
+ optional MyEnum e = 1;
+ repeated MyEnum repeated_e = 2;
+ repeated MyEnum repeated_packed_e = 3 [packed=true];
+ repeated MyEnum repeated_packed_unexpected_e = 4; // not packed
+ oneof o {
+ MyEnum oneof_e_1 = 5;
+ MyEnum oneof_e_2 = 6;
+ }
+}
diff --git a/src/google/protobuf/unittest_proto3_arena.proto b/src/google/protobuf/unittest_proto3_arena.proto
new file mode 100644
index 00000000..6d7bada8
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3_arena.proto
@@ -0,0 +1,186 @@
+// 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";
+
+option cc_enable_arenas = true;
+
+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 {
+ ZERO = 0;
+ 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;
+
+ // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+ // inside proto2 messages.
+ //
+ // 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;
+
+ // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+ // inside proto2 messages.
+ //
+ // 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];
+
+ oneof oneof_field {
+ uint32 oneof_uint32 = 111;
+ NestedMessage oneof_nested_message = 112;
+ string oneof_string = 113;
+ bytes oneof_bytes = 114;
+ }
+}
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+ repeated int32 packed_int32 = 90 [packed = true];
+ repeated int64 packed_int64 = 91 [packed = true];
+ repeated uint32 packed_uint32 = 92 [packed = true];
+ repeated uint64 packed_uint64 = 93 [packed = true];
+ repeated sint32 packed_sint32 = 94 [packed = true];
+ repeated sint64 packed_sint64 = 95 [packed = true];
+ repeated fixed32 packed_fixed32 = 96 [packed = true];
+ repeated fixed64 packed_fixed64 = 97 [packed = true];
+ repeated sfixed32 packed_sfixed32 = 98 [packed = true];
+ repeated sfixed64 packed_sfixed64 = 99 [packed = true];
+ repeated float packed_float = 100 [packed = true];
+ repeated double packed_double = 101 [packed = true];
+ repeated bool packed_bool = 102 [packed = true];
+ repeated ForeignEnum packed_enum = 103 [packed = true];
+}
+
+// This proto includes a recusively nested message.
+message NestedTestAllTypes {
+ NestedTestAllTypes child = 1;
+ TestAllTypes payload = 2;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+ optional int32 c = 1;
+}
+
+enum ForeignEnum {
+ FOREIGN_ZERO = 0;
+ FOREIGN_FOO = 4;
+ FOREIGN_BAR = 5;
+ FOREIGN_BAZ = 6;
+}
+
+// TestEmptyMessage is used to test behavior of unknown fields.
+message TestEmptyMessage {
+}
+
diff --git a/src/google/protobuf/unknown_enum_impl.h b/src/google/protobuf/unknown_enum_impl.h
new file mode 100644
index 00000000..39c10cbc
--- /dev/null
+++ b/src/google/protobuf/unknown_enum_impl.h
@@ -0,0 +1,155 @@
+// 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 <stdlib.h>
+
+#include <google/protobuf/stubs/common.h>
+#include "net/proto/tagmapper.h"
+#include <google/protobuf/bridge/compatibility_mode_support.h>
+
+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<int32>* 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<int32>* unknown_values);
+// Invokes the appropriate version based on whether the message is proto1
+// or proto2.
+template <typename T>
+bool HasUnknownEnum_Template(const T& message, int32 field_number,
+ int32* unknown_value = nullptr) {
+ if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
+ !internal::is_base_of<ProtocolMessage, T>::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 <typename T>
+bool GetRepeatedEnumUnknowns_Template(
+ const T& message, int32 field_number,
+ vector<int32>* unknown_values = nullptr) {
+ if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
+ !internal::is_base_of<ProtocolMessage, T>::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
+// CLEAR_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.
+//
+// Clears the unknown entries of the given field of the message.
+void ClearUnknownEnum(Message* message, int32 field_number);
+// In proto1, clears the field if the value is out of range.
+// TODO(karner): Delete this or make it proto2-only once the migration
+// to proto2 is complete.
+void ClearUnknownEnumProto1(Message* message, int32 field_number);
+template <typename T>
+void ClearUnknownEnum_Template(T* message, int32 field_number) {
+ if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
+ !internal::is_base_of<ProtocolMessage, T>::value) {
+ ClearUnknownEnum(message, field_number);
+ } else {
+ ClearUnknownEnumProto1(message, field_number);
+ }
+}
+
+// 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 <typename T>
+void SetUnknownEnum_Template(T* message, int32 field_number,
+ int32 unknown_value) {
+ if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
+ !internal::is_base_of<ProtocolMessage, T>::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 e1f8b838..e15280c8 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -32,19 +32,39 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
-#include <google/protobuf/stubs/common.h>
#include <google/protobuf/unknown_field_set.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/stl_util.h>
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) {}
+ : fields_(NULL) {}
UnknownFieldSet::~UnknownFieldSet() {
Clear();
@@ -52,29 +72,70 @@ 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;
+ }
+}
+
+void UnknownFieldSet::ClearAndFreeMemory() {
+ if (fields_ != NULL) {
+ Clear();
+ }
+}
+
+void UnknownFieldSet::InternalMergeFrom(const UnknownFieldSet& other) {
+ int other_field_count = other.field_count();
+ if (other_field_count > 0) {
+ fields_ = new vector<UnknownField>();
+ for (int i = 0; i < other_field_count; i++) {
+ fields_->push_back((*other.fields_)[i]);
+ fields_->back().DeepCopy();
+ }
}
- fields_->clear();
}
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<UnknownField>();
+ 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<UnknownField>();
+ 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()) {
case UnknownField::TYPE_LENGTH_DELIMITED:
- total_size += sizeof(*field.length_delimited_) +
- internal::StringSpaceUsedExcludingSelf(*field.length_delimited_);
+ total_size += sizeof(*field.length_delimited_.string_value_) +
+ internal::StringSpaceUsedExcludingSelf(
+ *field.length_delimited_.string_value_);
break;
case UnknownField::TYPE_GROUP:
total_size += field.group_->SpaceUsed();
@@ -91,64 +152,106 @@ int UnknownFieldSet::SpaceUsed() const {
}
void UnknownFieldSet::AddVarint(int number, uint64 value) {
- if (fields_ == NULL) fields_ = new vector<UnknownField>;
UnknownField field;
field.number_ = number;
- field.type_ = UnknownField::TYPE_VARINT;
+ field.SetType(UnknownField::TYPE_VARINT);
field.varint_ = value;
+ if (fields_ == NULL) fields_ = new vector<UnknownField>();
fields_->push_back(field);
}
void UnknownFieldSet::AddFixed32(int number, uint32 value) {
- if (fields_ == NULL) fields_ = new vector<UnknownField>;
UnknownField field;
field.number_ = number;
- field.type_ = UnknownField::TYPE_FIXED32;
+ field.SetType(UnknownField::TYPE_FIXED32);
field.fixed32_ = value;
+ if (fields_ == NULL) fields_ = new vector<UnknownField>();
fields_->push_back(field);
}
void UnknownFieldSet::AddFixed64(int number, uint64 value) {
- if (fields_ == NULL) fields_ = new vector<UnknownField>;
UnknownField field;
field.number_ = number;
- field.type_ = UnknownField::TYPE_FIXED64;
+ field.SetType(UnknownField::TYPE_FIXED64);
field.fixed64_ = value;
+ if (fields_ == NULL) fields_ = new vector<UnknownField>();
fields_->push_back(field);
}
string* UnknownFieldSet::AddLengthDelimited(int number) {
- if (fields_ == NULL) fields_ = new vector<UnknownField>;
UnknownField field;
field.number_ = number;
- field.type_ = UnknownField::TYPE_LENGTH_DELIMITED;
- field.length_delimited_ = new string;
+ field.SetType(UnknownField::TYPE_LENGTH_DELIMITED);
+ field.length_delimited_.string_value_ = new string;
+ if (fields_ == NULL) fields_ = new vector<UnknownField>();
fields_->push_back(field);
- return field.length_delimited_;
+ return field.length_delimited_.string_value_;
}
+
UnknownFieldSet* UnknownFieldSet::AddGroup(int number) {
- if (fields_ == NULL) fields_ = new vector<UnknownField>;
UnknownField field;
field.number_ = number;
- field.type_ = UnknownField::TYPE_GROUP;
+ field.SetType(UnknownField::TYPE_GROUP);
field.group_ = new UnknownFieldSet;
+ if (fields_ == NULL) fields_ = new vector<UnknownField>();
fields_->push_back(field);
return field.group_;
}
void UnknownFieldSet::AddField(const UnknownField& field) {
- if (fields_ == NULL) fields_ = new vector<UnknownField>;
+ if (fields_ == NULL) fields_ = new vector<UnknownField>();
fields_->push_back(field);
fields_->back().DeepCopy();
}
-bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) {
+void UnknownFieldSet::DeleteSubrange(int start, int num) {
+ // Delete the specified fields.
+ for (int i = 0; i < num; ++i) {
+ (*fields_)[i + start].Delete();
+ }
+ // Slide down the remaining fields.
+ for (int i = start + num; i < fields_->size(); ++i) {
+ (*fields_)[i - num] = (*fields_)[i];
+ }
+ // Pop off the # of deleted fields.
+ 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) {
+ if (fields_ == NULL) return;
+ int left = 0; // The number of fields left after deletion.
+ for (int i = 0; i < fields_->size(); ++i) {
+ UnknownField* field = &(*fields_)[i];
+ if (field->number() == number) {
+ field->Delete();
+ } else {
+ if (i != left) {
+ (*fields_)[left] = (*fields_)[i];
+ }
+ ++left;
+ }
+ }
+ 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);
+ input->ConsumedEntireMessage()) {
+ MergeFromAndDestroy(&other);
return true;
} else {
return false;
@@ -162,8 +265,8 @@ bool UnknownFieldSet::ParseFromCodedStream(io::CodedInputStream* input) {
bool UnknownFieldSet::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
io::CodedInputStream coded_input(input);
- return ParseFromCodedStream(&coded_input) &&
- coded_input.ConsumedEntireMessage();
+ return (ParseFromCodedStream(&coded_input) &&
+ coded_input.ConsumedEntireMessage());
}
bool UnknownFieldSet::ParseFromArray(const void* data, int size) {
@@ -174,7 +277,7 @@ bool UnknownFieldSet::ParseFromArray(const void* data, int size) {
void UnknownField::Delete() {
switch (type()) {
case UnknownField::TYPE_LENGTH_DELIMITED:
- delete length_delimited_;
+ delete length_delimited_.string_value_;
break;
case UnknownField::TYPE_GROUP:
delete group_;
@@ -184,14 +287,31 @@ 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:
- length_delimited_ = new string(*length_delimited_);
+ length_delimited_.string_value_ = new string(
+ *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;
}
@@ -200,5 +320,22 @@ void UnknownField::DeepCopy() {
}
}
+
+void UnknownField::SerializeLengthDelimitedNoTag(
+ io::CodedOutputStream* output) const {
+ GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
+ const string& data = *length_delimited_.string_value_;
+ output->WriteVarint32(data.size());
+ output->WriteRawMaybeAliased(data.data(), data.size());
+}
+
+uint8* UnknownField::SerializeLengthDelimitedNoTagToArray(uint8* target) const {
+ GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
+ const string& data = *length_delimited_.string_value_;
+ target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target);
+ target = io::CodedOutputStream::WriteStringToArray(data, target);
+ return target;
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 84c2e2b6..987b1979 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -38,12 +38,23 @@
#ifndef GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
#define GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
+#include <assert.h>
#include <string>
#include <vector>
-#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
+ namespace io {
+ class CodedInputStream; // coded_stream.h
+ class CodedOutputStream; // coded_stream.h
+ class ZeroCopyInputStream; // zero_copy_stream.h
+ }
+ namespace internal {
+ class WireFormat; // wire_format.h
+ class MessageSetFieldSkipperUsingCord;
+ // extension_set_heavy.cc
+ }
class Message; // message.h
class UnknownField; // below
@@ -68,12 +79,18 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
// Remove all fields.
inline void Clear();
+ // Remove all fields and deallocate internal data objects
+ void ClearAndFreeMemory();
+
// Is this set empty?
inline bool empty() const;
// 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);
@@ -107,6 +124,15 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
// Adds an unknown field from another set.
void AddField(const UnknownField& field);
+ // Delete fields with indices in the range [start .. start+num-1].
+ // Caution: implementation moves all fields with indices [start+num .. ].
+ void DeleteSubrange(int start, int num);
+
+ // Delete all fields with a specific field number. The order of left fields
+ // is preserved.
+ // Caution: implementation moves all fields after the first deleted field.
+ void DeleteByNumber(int number);
+
// Parsing helpers -------------------------------------------------
// These work exactly like the similarly-named methods of Message.
@@ -115,14 +141,25 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);
bool ParseFromArray(const void* data, int size);
inline bool ParseFromString(const string& data) {
- return ParseFromArray(data.data(), data.size());
+ return ParseFromArray(data.data(), static_cast<int>(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();
- vector<UnknownField>* fields_;
-
+ // 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<UnknownField>* fields_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet);
};
@@ -159,22 +196,43 @@ class LIBPROTOBUF_EXPORT UnknownField {
inline string* mutable_length_delimited();
inline UnknownFieldSet* mutable_group();
+ // Serialization API.
+ // These methods can take advantage of the underlying implementation and may
+ // archieve a better performance than using getters to retrieve the data and
+ // do the serialization yourself.
+ void SerializeLengthDelimitedNoTag(io::CodedOutputStream* output) const;
+ uint8* SerializeLengthDelimitedNoTagToArray(uint8* target) const;
+
+ inline int GetLengthDelimitedSize() const;
+
private:
friend class UnknownFieldSet;
// 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();
- unsigned int number_ : 29;
- unsigned int type_ : 3;
+ // Set the wire type of this UnknownField. Should only be used when this
+ // UnknownField is being created.
+ inline void SetType(Type type);
+
+ union LengthDelimited {
+ string* string_value_;
+ };
+
+ uint32 number_;
+ uint32 type_;
union {
uint64 varint_;
uint32 fixed32_;
uint64 fixed64_;
- string* length_delimited_;
+ mutable union LengthDelimited length_delimited_;
UnknownFieldSet* group_;
};
};
@@ -183,13 +241,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) {
@@ -197,9 +256,10 @@ inline void UnknownFieldSet::Swap(UnknownFieldSet* x) {
}
inline int UnknownFieldSet::field_count() const {
- return (fields_ == NULL) ? 0 : fields_->size();
+ return fields_ ? static_cast<int>(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) {
@@ -211,57 +271,68 @@ inline void UnknownFieldSet::AddLengthDelimited(
AddLengthDelimited(number)->assign(value);
}
+
inline int UnknownField::number() const { return number_; }
inline UnknownField::Type UnknownField::type() const {
return static_cast<Type>(type_);
}
-inline uint64 UnknownField::varint () const {
- GOOGLE_DCHECK_EQ(type_, TYPE_VARINT);
+inline uint64 UnknownField::varint() const {
+ assert(type() == TYPE_VARINT);
return varint_;
}
inline uint32 UnknownField::fixed32() const {
- GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32);
+ assert(type() == TYPE_FIXED32);
return fixed32_;
}
inline uint64 UnknownField::fixed64() const {
- GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64);
+ assert(type() == TYPE_FIXED64);
return fixed64_;
}
inline const string& UnknownField::length_delimited() const {
- GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED);
- return *length_delimited_;
+ assert(type() == TYPE_LENGTH_DELIMITED);
+ return *length_delimited_.string_value_;
}
inline const UnknownFieldSet& UnknownField::group() const {
- GOOGLE_DCHECK_EQ(type_, TYPE_GROUP);
+ assert(type() == TYPE_GROUP);
return *group_;
}
inline void UnknownField::set_varint(uint64 value) {
- GOOGLE_DCHECK_EQ(type_, TYPE_VARINT);
+ assert(type() == TYPE_VARINT);
varint_ = value;
}
inline void UnknownField::set_fixed32(uint32 value) {
- GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32);
+ assert(type() == TYPE_FIXED32);
fixed32_ = value;
}
inline void UnknownField::set_fixed64(uint64 value) {
- GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64);
+ assert(type() == TYPE_FIXED64);
fixed64_ = value;
}
inline void UnknownField::set_length_delimited(const string& value) {
- GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED);
- length_delimited_->assign(value);
+ assert(type() == TYPE_LENGTH_DELIMITED);
+ length_delimited_.string_value_->assign(value);
}
inline string* UnknownField::mutable_length_delimited() {
- GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED);
- return length_delimited_;
+ assert(type() == TYPE_LENGTH_DELIMITED);
+ return length_delimited_.string_value_;
}
inline UnknownFieldSet* UnknownField::mutable_group() {
- GOOGLE_DCHECK_EQ(type_, TYPE_GROUP);
+ assert(type() == TYPE_GROUP);
return group_;
}
+inline int UnknownField::GetLengthDelimitedSize() const {
+ GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
+ return static_cast<int>(length_delimited_.string_value_->size());
+}
+
+inline void UnknownField::SetType(Type type) {
+ type_ = type;
+}
+
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
index 1235c9ee..9b02f0b0 100644
--- a/src/google/protobuf/unknown_field_set_unittest.cc
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -46,15 +46,13 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
using internal::WireFormat;
-namespace {
-
class UnknownFieldSetTest : public testing::Test {
protected:
virtual void SetUp() {
@@ -107,6 +105,8 @@ class UnknownFieldSetTest : public testing::Test {
UnknownFieldSet* unknown_fields_;
};
+namespace {
+
TEST_F(UnknownFieldSetTest, AllFieldsPresent) {
// All fields of TestAllTypes should be present, in numeric order (because
// that's the order we parsed them in). Fields that are not valid field
@@ -118,7 +118,12 @@ TEST_F(UnknownFieldSetTest, AllFieldsPresent) {
const FieldDescriptor* field = descriptor_->FindFieldByNumber(i);
if (field != NULL) {
ASSERT_LT(pos, unknown_fields_->field_count());
- EXPECT_EQ(i, unknown_fields_->field(pos++).number());
+ // Do not check oneof field if it is not set.
+ if (field->containing_oneof() == NULL) {
+ EXPECT_EQ(i, unknown_fields_->field(pos++).number());
+ } else if (i == unknown_fields_->field(pos).number()) {
+ pos++;
+ }
if (field->is_repeated()) {
// Should have a second instance.
ASSERT_LT(pos, unknown_fields_->field_count());
@@ -297,12 +302,21 @@ TEST_F(UnknownFieldSetTest, MergeFrom) {
destination.DebugString());
}
+
TEST_F(UnknownFieldSetTest, Clear) {
// Clear the set.
empty_message_.Clear();
EXPECT_EQ(0, unknown_fields_->field_count());
}
+TEST_F(UnknownFieldSetTest, ClearAndFreeMemory) {
+ EXPECT_GT(unknown_fields_->field_count(), 0);
+ unknown_fields_->ClearAndFreeMemory();
+ EXPECT_EQ(0, unknown_fields_->field_count());
+ unknown_fields_->AddVarint(123456, 654321);
+ EXPECT_EQ(1, unknown_fields_->field_count());
+}
+
TEST_F(UnknownFieldSetTest, ParseKnownAndUnknown) {
// Test mixing known and unknown fields when parsing.
@@ -468,6 +482,13 @@ TEST_F(UnknownFieldSetTest, UnknownEnumValue) {
}
}
+TEST_F(UnknownFieldSetTest, SpaceUsedExcludingSelf) {
+ UnknownFieldSet empty;
+ empty.AddVarint(1, 0);
+ EXPECT_EQ(sizeof(vector<UnknownField>) + sizeof(UnknownField),
+ empty.SpaceUsedExcludingSelf());
+}
+
TEST_F(UnknownFieldSetTest, SpaceUsed) {
unittest::TestEmptyMessage empty_message;
@@ -498,6 +519,7 @@ TEST_F(UnknownFieldSetTest, SpaceUsed) {
EXPECT_LT(base_size, empty_message.SpaceUsed());
}
+
TEST_F(UnknownFieldSetTest, Empty) {
UnknownFieldSet unknown_fields;
EXPECT_TRUE(unknown_fields.empty());
@@ -507,6 +529,78 @@ TEST_F(UnknownFieldSetTest, Empty) {
EXPECT_TRUE(unknown_fields.empty());
}
+TEST_F(UnknownFieldSetTest, DeleteSubrange) {
+ // Exhaustively test the deletion of every possible subrange in arrays of all
+ // sizes from 0 through 9.
+ for (int size = 0; size < 10; ++size) {
+ for (int num = 0; num <= size; ++num) {
+ for (int start = 0; start < size - num; ++start) {
+ // Create a set with "size" fields.
+ UnknownFieldSet unknown;
+ for (int i = 0; i < size; ++i) {
+ unknown.AddFixed32(i, i);
+ }
+ // Delete the specified subrange.
+ unknown.DeleteSubrange(start, num);
+ // Make sure the resulting field values are still correct.
+ EXPECT_EQ(size - num, unknown.field_count());
+ for (int i = 0; i < unknown.field_count(); ++i) {
+ if (i < start) {
+ EXPECT_EQ(i, unknown.field(i).fixed32());
+ } else {
+ EXPECT_EQ(i + num, unknown.field(i).fixed32());
+ }
+ }
+ }
+ }
+ }
+}
+
+void CheckDeleteByNumber(const vector<int>& field_numbers, int deleted_number,
+ const vector<int>& expected_field_nubmers) {
+ UnknownFieldSet unknown_fields;
+ for (int i = 0; i < field_numbers.size(); ++i) {
+ unknown_fields.AddFixed32(field_numbers[i], i);
+ }
+ unknown_fields.DeleteByNumber(deleted_number);
+ ASSERT_EQ(expected_field_nubmers.size(), unknown_fields.field_count());
+ for (int i = 0; i < expected_field_nubmers.size(); ++i) {
+ EXPECT_EQ(expected_field_nubmers[i],
+ unknown_fields.field(i).number());
+ }
+}
+
+#define MAKE_VECTOR(x) vector<int>(x, x + GOOGLE_ARRAYSIZE(x))
+TEST_F(UnknownFieldSetTest, DeleteByNumber) {
+ CheckDeleteByNumber(vector<int>(), 1, vector<int>());
+ static const int kTestFieldNumbers1[] = {1, 2, 3};
+ static const int kFieldNumberToDelete1 = 1;
+ static const int kExpectedFieldNumbers1[] = {2, 3};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers1), kFieldNumberToDelete1,
+ MAKE_VECTOR(kExpectedFieldNumbers1));
+ static const int kTestFieldNumbers2[] = {1, 2, 3};
+ static const int kFieldNumberToDelete2 = 2;
+ static const int kExpectedFieldNumbers2[] = {1, 3};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers2), kFieldNumberToDelete2,
+ MAKE_VECTOR(kExpectedFieldNumbers2));
+ static const int kTestFieldNumbers3[] = {1, 2, 3};
+ static const int kFieldNumberToDelete3 = 3;
+ static const int kExpectedFieldNumbers3[] = {1, 2};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers3), kFieldNumberToDelete3,
+ MAKE_VECTOR(kExpectedFieldNumbers3));
+ static const int kTestFieldNumbers4[] = {1, 2, 1, 4, 1};
+ static const int kFieldNumberToDelete4 = 1;
+ static const int kExpectedFieldNumbers4[] = {2, 4};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers4), kFieldNumberToDelete4,
+ MAKE_VECTOR(kExpectedFieldNumbers4));
+ static const int kTestFieldNumbers5[] = {1, 2, 3, 4, 5};
+ static const int kFieldNumberToDelete5 = 6;
+ static const int kExpectedFieldNumbers5[] = {1, 2, 3, 4, 5};
+ CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers5), kFieldNumberToDelete5,
+ MAKE_VECTOR(kExpectedFieldNumbers5));
+}
+#undef MAKE_VECTOR
} // namespace
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index 831a5794..c5bbbf2e 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -39,6 +39,7 @@
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.pb.h>
@@ -48,12 +49,11 @@
#include <google/protobuf/unknown_field_set.h>
+
namespace google {
namespace protobuf {
namespace internal {
-using internal::WireFormatLite;
-
namespace {
// This function turns out to be convenient when using some macros later.
@@ -141,7 +141,7 @@ bool WireFormat::SkipField(io::CodedInputStream* input, uint32 tag,
bool WireFormat::SkipMessage(io::CodedInputStream* input,
UnknownFieldSet* unknown_fields) {
- while(true) {
+ while (true) {
uint32 tag = input->ReadTag();
if (tag == 0) {
// End of input. This is a valid place to end, so return true.
@@ -159,6 +159,31 @@ bool WireFormat::SkipMessage(io::CodedInputStream* input,
}
}
+bool WireFormat::ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
+ uint32 field_number,
+ bool (*is_valid)(int),
+ UnknownFieldSet* unknown_fields,
+ RepeatedField<int>* values) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ io::CodedInputStream::Limit limit = input->PushLimit(length);
+ while (input->BytesUntilLimit() > 0) {
+ int value;
+ if (!google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ int, WireFormatLite::TYPE_ENUM>(input, &value)) {
+ return false;
+ }
+ if (is_valid == NULL || is_valid(value)) {
+ values->Add(value);
+ } else {
+ unknown_fields->AddVarint(field_number, value);
+ }
+ }
+ input->PopLimit(limit);
+ return true;
+}
+
+
void WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
io::CodedOutputStream* output) {
for (int i = 0; i < unknown_fields.field_count(); i++) {
@@ -183,7 +208,8 @@ void WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
output->WriteVarint32(WireFormatLite::MakeTag(field.number(),
WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
output->WriteVarint32(field.length_delimited().size());
- output->WriteString(field.length_delimited());
+ output->WriteRawMaybeAliased(field.length_delimited().data(),
+ field.length_delimited().size());
break;
case UnknownField::TYPE_GROUP:
output->WriteVarint32(WireFormatLite::MakeTag(field.number(),
@@ -239,8 +265,6 @@ void WireFormat::SerializeUnknownMessageSetItems(
// The only unknown fields that are allowed to exist in a MessageSet are
// messages, which are length-delimited.
if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
- const string& data = field.length_delimited();
-
// Start group.
output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag);
@@ -250,8 +274,7 @@ void WireFormat::SerializeUnknownMessageSetItems(
// Write message.
output->WriteVarint32(WireFormatLite::kMessageSetMessageTag);
- output->WriteVarint32(data.size());
- output->WriteString(data);
+ field.SerializeLengthDelimitedNoTag(output);
// End group.
output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag);
@@ -268,8 +291,6 @@ uint8* WireFormat::SerializeUnknownMessageSetItemsToArray(
// The only unknown fields that are allowed to exist in a MessageSet are
// messages, which are length-delimited.
if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
- const string& data = field.length_delimited();
-
// Start group.
target = io::CodedOutputStream::WriteTagToArray(
WireFormatLite::kMessageSetItemStartTag, target);
@@ -283,8 +304,7 @@ uint8* WireFormat::SerializeUnknownMessageSetItemsToArray(
// Write message.
target = io::CodedOutputStream::WriteTagToArray(
WireFormatLite::kMessageSetMessageTag, target);
- target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target);
- target = io::CodedOutputStream::WriteStringToArray(data, target);
+ target = field.SerializeLengthDelimitedNoTagToArray(target);
// End group.
target = io::CodedOutputStream::WriteTagToArray(
@@ -354,9 +374,10 @@ int WireFormat::ComputeUnknownMessageSetItemsSize(
if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
size += WireFormatLite::kMessageSetItemTagsSize;
size += io::CodedOutputStream::VarintSize32(field.number());
- size += io::CodedOutputStream::VarintSize32(
- field.length_delimited().size());
- size += field.length_delimited().size();
+
+ int field_size = field.GetLengthDelimitedSize();
+ size += io::CodedOutputStream::VarintSize32(field_size);
+ size += field_size;
}
}
@@ -417,6 +438,37 @@ bool WireFormat::ParseAndMergePartial(io::CodedInputStream* input,
}
}
+bool WireFormat::SkipMessageSetField(io::CodedInputStream* input,
+ uint32 field_number,
+ UnknownFieldSet* unknown_fields) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ return input->ReadString(
+ unknown_fields->AddLengthDelimited(field_number), length);
+}
+
+bool WireFormat::ParseAndMergeMessageSetField(uint32 field_number,
+ const FieldDescriptor* field,
+ Message* message,
+ io::CodedInputStream* input) {
+ const Reflection* message_reflection = message->GetReflection();
+ if (field == NULL) {
+ // We store unknown MessageSet extensions as groups.
+ return SkipMessageSetField(
+ input, field_number, message_reflection->MutableUnknownFields(message));
+ } else if (field->is_repeated() ||
+ field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ // This shouldn't happen as we only allow optional message extensions to
+ // MessageSet.
+ GOOGLE_LOG(ERROR) << "Extensions of MessageSets must be optional messages.";
+ return false;
+ } else {
+ Message* sub_message = message_reflection->MutableMessage(
+ message, field, input->GetExtensionFactory());
+ return WireFormatLite::ReadMessage(input, sub_message);
+ }
+}
+
bool WireFormat::ParseAndMergeField(
uint32 tag,
const FieldDescriptor* field, // May be NULL for unknown
@@ -485,10 +537,23 @@ bool WireFormat::ParseAndMergeField(
int value;
if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
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);
+ } else {
+ // The enum value is not one of the known values. Add it to the
+ // UnknownFieldSet.
+ int64 sign_extended_value = static_cast<int64>(value);
+ message_reflection->MutableUnknownFields(message)
+ ->AddVarint(
+ WireFormatLite::GetTagFieldNumber(tag),
+ sign_extended_value);
+ }
}
}
@@ -545,21 +610,31 @@ bool WireFormat::ParseAndMergeField(
int value;
if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
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<int64>(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<int64>(value);
+ message_reflection->MutableUnknownFields(message)
+ ->AddVarint(
+ WireFormatLite::GetTagFieldNumber(tag),
+ sign_extended_value);
+ }
}
break;
}
@@ -568,7 +643,8 @@ bool WireFormat::ParseAndMergeField(
case FieldDescriptor::TYPE_STRING: {
string value;
if (!WireFormatLite::ReadString(input, &value)) return false;
- VerifyUTF8String(value.data(), value.length(), PARSE);
+ VerifyUTF8StringNamedField(value.data(), value.length(), PARSE,
+ field->name().c_str());
if (field->is_repeated()) {
message_reflection->AddString(message, field, value);
} else {
@@ -632,20 +708,14 @@ bool WireFormat::ParseAndMergeMessageSetItem(
// required int32 type_id = 2;
// required data message = 3;
- // Once we see a type_id, we'll construct a fake tag for this extension
- // which is the tag it would have had under the proto2 extensions wire
- // format.
- uint32 fake_tag = 0;
+ uint32 last_type_id = 0;
// Once we see a type_id, we'll look up the FieldDescriptor for the
// extension.
const FieldDescriptor* field = NULL;
// If we see message data before the type_id, we'll append it to this so
- // we can parse it later. This will probably never happen in practice,
- // as no MessageSet encoder I know of writes the message before the type ID.
- // But, it's technically valid so we should allow it.
- // TODO(kenton): Use a Cord instead? Do I care?
+ // we can parse it later.
string message_data;
while (true) {
@@ -656,8 +726,7 @@ bool WireFormat::ParseAndMergeMessageSetItem(
case WireFormatLite::kMessageSetTypeIdTag: {
uint32 type_id;
if (!input->ReadVarint32(&type_id)) return false;
- fake_tag = WireFormatLite::MakeTag(
- type_id, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+ last_type_id = type_id;
field = message_reflection->FindKnownExtensionByNumber(type_id);
if (!message_data.empty()) {
@@ -666,8 +735,8 @@ bool WireFormat::ParseAndMergeMessageSetItem(
io::ArrayInputStream raw_input(message_data.data(),
message_data.size());
io::CodedInputStream sub_input(&raw_input);
- if (!ParseAndMergeField(fake_tag, field, message,
- &sub_input)) {
+ if (!ParseAndMergeMessageSetField(last_type_id, field, message,
+ &sub_input)) {
return false;
}
message_data.clear();
@@ -677,16 +746,20 @@ bool WireFormat::ParseAndMergeMessageSetItem(
}
case WireFormatLite::kMessageSetMessageTag: {
- if (fake_tag == 0) {
+ if (last_type_id == 0) {
// We haven't seen a type_id yet. Append this data to message_data.
string temp;
uint32 length;
if (!input->ReadVarint32(&length)) return false;
if (!input->ReadString(&temp, length)) return false;
- message_data.append(temp);
+ io::StringOutputStream output_stream(&message_data);
+ io::CodedOutputStream coded_output(&output_stream);
+ coded_output.WriteVarint32(length);
+ coded_output.WriteString(temp);
} else {
// Already saw type_id, so we can parse this directly.
- if (!ParseAndMergeField(fake_tag, field, message, input)) {
+ if (!ParseAndMergeMessageSetField(last_type_id, field, message,
+ input)) {
return false;
}
}
@@ -834,7 +907,8 @@ void WireFormat::SerializeFieldWithCachedSizes(
message_reflection->GetRepeatedStringReference(
message, field, j, &scratch) :
message_reflection->GetStringReference(message, field, &scratch);
- VerifyUTF8String(value.data(), value.length(), SERIALIZE);
+ VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE,
+ field->name().c_str());
WireFormatLite::WriteString(field->number(), value, output);
break;
}
@@ -1044,7 +1118,8 @@ int WireFormat::MessageSetItemByteSize(
void WireFormat::VerifyUTF8StringFallback(const char* data,
int size,
- Operation op) {
+ Operation op,
+ const char* field_name) {
if (!IsStructurallyValidUTF8(data, size)) {
const char* operation_str = NULL;
switch (op) {
@@ -1056,10 +1131,15 @@ void WireFormat::VerifyUTF8StringFallback(const char* data,
break;
// no default case: have the compiler warn if a case is not covered.
}
- GOOGLE_LOG(ERROR) << "Encountered string containing invalid UTF-8 data while "
- << operation_str
- << " protocol buffer. Strings must contain only UTF-8; "
- "use the 'bytes' type for raw bytes.";
+ string quoted_field_name = "";
+ if (field_name != NULL) {
+ quoted_field_name = StringPrintf(" '%s'", field_name);
+ }
+ // no space below to avoid double space when the field name is missing.
+ GOOGLE_LOG(ERROR) << "String field" << quoted_field_name << " contains invalid "
+ << "UTF-8 data when " << operation_str << " a protocol "
+ << "buffer. Use the 'bytes' type if you intend to send raw "
+ << "bytes. ";
}
}
diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h
index c7539250..8de491a6 100644
--- a/src/google/protobuf/wire_format.h
+++ b/src/google/protobuf/wire_format.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -40,6 +40,7 @@
#define GOOGLE_PROTOBUF_WIRE_FORMAT_H__
#include <string>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
@@ -78,7 +79,7 @@ class LIBPROTOBUF_EXPORT WireFormat {
static inline WireFormatLite::WireType WireTypeForField(
const FieldDescriptor* field);
- // Given a FieldSescriptor::Type return its WireType
+ // Given a FieldDescriptor::Type return its WireType
static inline WireFormatLite::WireType WireTypeForFieldType(
FieldDescriptor::Type type);
@@ -137,6 +138,14 @@ class LIBPROTOBUF_EXPORT WireFormat {
static bool SkipMessage(io::CodedInputStream* input,
UnknownFieldSet* unknown_fields);
+ // Read a packed enum field. If the is_valid function is not NULL, values for
+ // which is_valid(value) returns false are appended to unknown_fields_stream.
+ static bool ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
+ uint32 field_number,
+ bool (*is_valid)(int),
+ UnknownFieldSet* unknown_fields,
+ RepeatedField<int>* values);
+
// Write the contents of an UnknownFieldSet to the output.
static void SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
io::CodedOutputStream* output);
@@ -179,7 +188,7 @@ class LIBPROTOBUF_EXPORT WireFormat {
// of packed repeated fields.
static uint32 MakeTag(const FieldDescriptor* field);
- // Parse a single field. The input should start out positioned immidately
+ // Parse a single field. The input should start out positioned immediately
// after the tag.
static bool ParseAndMergeField(
uint32 tag,
@@ -227,14 +236,34 @@ class LIBPROTOBUF_EXPORT WireFormat {
};
// Verifies that a string field is valid UTF8, logging an error if not.
+ // This function will not be called by newly generated protobuf code
+ // but remains present to support existing code.
static void VerifyUTF8String(const char* data, int size, Operation op);
+ // The NamedField variant takes a field name in order to produce an
+ // informative error message if verification fails.
+ static void VerifyUTF8StringNamedField(const char* data,
+ int size,
+ Operation op,
+ const char* field_name);
private:
// Verifies that a string field is valid UTF8, logging an error if not.
static void VerifyUTF8StringFallback(
const char* data,
int size,
- Operation op);
+ Operation op,
+ const char* field_name);
+
+ // Skip a MessageSet field.
+ static bool SkipMessageSetField(io::CodedInputStream* input,
+ uint32 field_number,
+ UnknownFieldSet* unknown_fields);
+
+ // Parse a MessageSet field.
+ static bool ParseAndMergeMessageSetField(uint32 field_number,
+ const FieldDescriptor* field,
+ Message* message,
+ io::CodedInputStream* input);
@@ -253,7 +282,7 @@ class LIBPROTOBUF_EXPORT UnknownFieldSetFieldSkipper : public FieldSkipper {
virtual bool SkipMessage(io::CodedInputStream* input);
virtual void SkipUnknownEnum(int field_number, int value);
- private:
+ protected:
UnknownFieldSet* unknown_fields_;
};
@@ -292,7 +321,18 @@ inline int WireFormat::TagSize(int field_number, FieldDescriptor::Type type) {
inline void WireFormat::VerifyUTF8String(const char* data, int size,
WireFormat::Operation op) {
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
- WireFormat::VerifyUTF8StringFallback(data, size, op);
+ WireFormat::VerifyUTF8StringFallback(data, size, op, NULL);
+#else
+ // Avoid the compiler warning about unsued variables.
+ (void)data; (void)size; (void)op;
+#endif
+}
+
+inline void WireFormat::VerifyUTF8StringNamedField(
+ const char* data, int size, WireFormat::Operation op,
+ const char* field_name) {
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+ WireFormat::VerifyUTF8StringFallback(data, size, op, field_name);
#endif
}
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index d347d116..2ce4920c 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -40,7 +40,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream_inl.h>
#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
namespace google {
namespace protobuf {
@@ -55,11 +55,16 @@ const int WireFormatLite::kMessageSetMessageTag;
#endif
+// IBM xlC requires prefixing constants with WireFormatLite::
const int WireFormatLite::kMessageSetItemTagsSize =
- io::CodedOutputStream::VarintSize32(kMessageSetItemStartTag) +
- io::CodedOutputStream::VarintSize32(kMessageSetItemEndTag) +
- io::CodedOutputStream::VarintSize32(kMessageSetTypeIdTag) +
- io::CodedOutputStream::VarintSize32(kMessageSetMessageTag);
+ io::CodedOutputStream::StaticVarintSize32<
+ WireFormatLite::kMessageSetItemStartTag>::value +
+ io::CodedOutputStream::StaticVarintSize32<
+ WireFormatLite::kMessageSetItemEndTag>::value +
+ io::CodedOutputStream::StaticVarintSize32<
+ WireFormatLite::kMessageSetTypeIdTag>::value +
+ io::CodedOutputStream::StaticVarintSize32<
+ WireFormatLite::kMessageSetMessageTag>::value;
const WireFormatLite::CppType
WireFormatLite::kFieldTypeToCppTypeMap[MAX_FIELD_TYPE + 1] = {
@@ -153,8 +158,65 @@ bool WireFormatLite::SkipField(
}
}
+bool WireFormatLite::SkipField(
+ io::CodedInputStream* input, uint32 tag, io::CodedOutputStream* output) {
+ switch (WireFormatLite::GetTagWireType(tag)) {
+ case WireFormatLite::WIRETYPE_VARINT: {
+ uint64 value;
+ if (!input->ReadVarint64(&value)) return false;
+ output->WriteVarint32(tag);
+ output->WriteVarint64(value);
+ return true;
+ }
+ case WireFormatLite::WIRETYPE_FIXED64: {
+ uint64 value;
+ if (!input->ReadLittleEndian64(&value)) return false;
+ output->WriteVarint32(tag);
+ output->WriteLittleEndian64(value);
+ return true;
+ }
+ case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ output->WriteVarint32(tag);
+ output->WriteVarint32(length);
+ // TODO(mkilavuz): Provide API to prevent extra string copying.
+ string temp;
+ if (!input->ReadString(&temp, length)) return false;
+ output->WriteString(temp);
+ return true;
+ }
+ case WireFormatLite::WIRETYPE_START_GROUP: {
+ output->WriteVarint32(tag);
+ if (!input->IncrementRecursionDepth()) return false;
+ if (!SkipMessage(input, output)) return false;
+ input->DecrementRecursionDepth();
+ // Check that the ending tag matched the starting tag.
+ if (!input->LastTagWas(WireFormatLite::MakeTag(
+ WireFormatLite::GetTagFieldNumber(tag),
+ WireFormatLite::WIRETYPE_END_GROUP))) {
+ return false;
+ }
+ return true;
+ }
+ case WireFormatLite::WIRETYPE_END_GROUP: {
+ return false;
+ }
+ case WireFormatLite::WIRETYPE_FIXED32: {
+ uint32 value;
+ if (!input->ReadLittleEndian32(&value)) return false;
+ output->WriteVarint32(tag);
+ output->WriteLittleEndian32(value);
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
bool WireFormatLite::SkipMessage(io::CodedInputStream* input) {
- while(true) {
+ while (true) {
uint32 tag = input->ReadTag();
if (tag == 0) {
// End of input. This is a valid place to end, so return true.
@@ -172,6 +234,27 @@ bool WireFormatLite::SkipMessage(io::CodedInputStream* input) {
}
}
+bool WireFormatLite::SkipMessage(io::CodedInputStream* input,
+ io::CodedOutputStream* output) {
+ while (true) {
+ uint32 tag = input->ReadTag();
+ if (tag == 0) {
+ // End of input. This is a valid place to end, so return true.
+ return true;
+ }
+
+ WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+
+ if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
+ output->WriteVarint32(tag);
+ // Must be the end of the message.
+ return true;
+ }
+
+ if (!SkipField(input, tag, output)) return false;
+ }
+}
+
bool FieldSkipper::SkipField(
io::CodedInputStream* input, uint32 tag) {
return WireFormatLite::SkipField(input, tag);
@@ -182,10 +265,25 @@ bool FieldSkipper::SkipMessage(io::CodedInputStream* input) {
}
void FieldSkipper::SkipUnknownEnum(
- int field_number, int value) {
+ int /* field_number */, int /* value */) {
// Nothing.
}
+bool CodedOutputStreamFieldSkipper::SkipField(
+ io::CodedInputStream* input, uint32 tag) {
+ return WireFormatLite::SkipField(input, tag, unknown_fields_);
+}
+
+bool CodedOutputStreamFieldSkipper::SkipMessage(io::CodedInputStream* input) {
+ return WireFormatLite::SkipMessage(input, unknown_fields_);
+}
+
+void CodedOutputStreamFieldSkipper::SkipUnknownEnum(
+ int field_number, int value) {
+ unknown_fields_->WriteVarint32(field_number);
+ unknown_fields_->WriteVarint64(value);
+}
+
bool WireFormatLite::ReadPackedEnumNoInline(io::CodedInputStream* input,
bool (*is_valid)(int),
RepeatedField<int>* values) {
@@ -198,7 +296,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);
}
}
@@ -206,6 +304,34 @@ bool WireFormatLite::ReadPackedEnumNoInline(io::CodedInputStream* input,
return true;
}
+bool WireFormatLite::ReadPackedEnumPreserveUnknowns(
+ io::CodedInputStream* input,
+ int field_number,
+ bool (*is_valid)(int),
+ io::CodedOutputStream* unknown_fields_stream,
+ RepeatedField<int>* values) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ io::CodedInputStream::Limit limit = input->PushLimit(length);
+ while (input->BytesUntilLimit() > 0) {
+ int value;
+ if (!google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ int, WireFormatLite::TYPE_ENUM>(input, &value)) {
+ return false;
+ }
+ if (is_valid == NULL || is_valid(value)) {
+ values->Add(value);
+ } else {
+ uint32 tag = WireFormatLite::MakeTag(field_number,
+ WireFormatLite::WIRETYPE_VARINT);
+ unknown_fields_stream->WriteVarint32(tag);
+ unknown_fields_stream->WriteVarint32(value);
+ }
+ }
+ input->PopLimit(limit);
+ return true;
+}
+
void WireFormatLite::WriteInt32(int field_number, int32 value,
io::CodedOutputStream* output) {
WriteTag(field_number, WIRETYPE_VARINT, output);
@@ -281,15 +407,34 @@ void WireFormatLite::WriteString(int field_number, const string& value,
io::CodedOutputStream* output) {
// String is for UTF-8 text only
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+ GOOGLE_CHECK(value.size() <= kint32max);
output->WriteVarint32(value.size());
output->WriteString(value);
}
+void WireFormatLite::WriteStringMaybeAliased(
+ int field_number, const string& value,
+ io::CodedOutputStream* output) {
+ // String is for UTF-8 text only
+ WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+ GOOGLE_CHECK(value.size() <= kint32max);
+ output->WriteVarint32(value.size());
+ output->WriteRawMaybeAliased(value.data(), value.size());
+}
void WireFormatLite::WriteBytes(int field_number, const string& value,
io::CodedOutputStream* output) {
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+ GOOGLE_CHECK(value.size() <= kint32max);
output->WriteVarint32(value.size());
output->WriteString(value);
}
+void WireFormatLite::WriteBytesMaybeAliased(
+ int field_number, const string& value,
+ io::CodedOutputStream* output) {
+ WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+ GOOGLE_CHECK(value.size() <= kint32max);
+ output->WriteVarint32(value.size());
+ output->WriteRawMaybeAliased(value.data(), value.size());
+}
void WireFormatLite::WriteGroup(int field_number,
@@ -339,19 +484,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 e3d5b2d8..76bc75a1 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -41,16 +41,14 @@
#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
#include <string>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message_lite.h>
+#include <google/protobuf/io/coded_stream.h> // for CodedOutputStream::Varint32Size
namespace google {
namespace protobuf {
template <typename T> class RepeatedField; // repeated_field.h
- namespace io {
- class CodedInputStream; // coded_stream.h
- class CodedOutputStream; // coded_stream.h
- }
}
namespace protobuf {
@@ -165,11 +163,22 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
// records to an UnknownFieldSet.
static bool SkipField(io::CodedInputStream* input, uint32 tag);
+ // Skips a field value with the given tag. The input should start
+ // positioned immediately after the tag. Skipped values are recorded to a
+ // CodedOutputStream.
+ static bool SkipField(io::CodedInputStream* input, uint32 tag,
+ io::CodedOutputStream* output);
+
// Reads and ignores a message from the input. Skipped values are simply
// discarded, not recorded anywhere. See WireFormat::SkipMessage() for a
// version that records to an UnknownFieldSet.
static bool SkipMessage(io::CodedInputStream* input);
+ // Reads and ignores a message from the input. Skipped values are recorded
+ // to a CodedOutputStream.
+ static bool SkipMessage(io::CodedInputStream* input,
+ io::CodedOutputStream* output);
+
// This macro does the same thing as WireFormatLite::MakeTag(), but the
// result is usable as a compile-time constant, which makes it usable
// as a switch case or a template input. WireFormatLite::MakeTag() is more
@@ -230,9 +239,9 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
// that file to use these.
// Avoid ugly line wrapping
-#define input io::CodedInputStream* input
-#define output io::CodedOutputStream* output
-#define field_number int field_number
+#define input io::CodedInputStream* input_arg
+#define output io::CodedOutputStream* output_arg
+#define field_number int field_number_arg
#define INL GOOGLE_ATTRIBUTE_ALWAYS_INLINE
// Read fields, not including tags. The assumption is that you already
@@ -282,14 +291,32 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
template <typename CType, enum FieldType DeclaredType>
static bool ReadPackedPrimitiveNoInline(input, RepeatedField<CType>* value);
- // Read a packed enum field. Values for which is_valid() returns false are
- // dropped.
+ // Read a packed enum field. If the is_valid function is not NULL, values for
+ // which is_valid(value) returns false are silently dropped.
static bool ReadPackedEnumNoInline(input,
bool (*is_valid)(int),
- RepeatedField<int>* value);
+ RepeatedField<int>* values);
+
+ // Read a packed enum field. If the is_valid function is not NULL, values for
+ // which is_valid(value) returns false are appended to unknown_fields_stream.
+ static bool ReadPackedEnumPreserveUnknowns(
+ input,
+ field_number,
+ bool (*is_valid)(int),
+ io::CodedOutputStream* unknown_fields_stream,
+ RepeatedField<int>* values);
+
+ // 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 bool ReadString(input, string* value);
- static bool ReadBytes (input, string* value);
static inline bool ReadGroup (field_number, input, MessageLite* value);
static inline bool ReadMessage(input, MessageLite* value);
@@ -342,6 +369,10 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
static void WriteString(field_number, const string& value, output);
static void WriteBytes (field_number, const string& value, output);
+ static void WriteStringMaybeAliased(
+ field_number, const string& value, output);
+ static void WriteBytesMaybeAliased(
+ field_number, const string& value, output);
static void WriteGroup(
field_number, const MessageLite& value, output);
@@ -477,6 +508,10 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
template<typename MessageType>
static inline int MessageSizeNoVirtual(const MessageType& value);
+ // Given the length of data, calculate the byte size of the data on the
+ // wire if we encode the data as a length delimited field.
+ static inline int LengthDelimitedSize(int length);
+
private:
// A helper method for the repeated primitive reader. This method has
// optimizations for primitive types that have fixed size on the wire, and
@@ -488,6 +523,12 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
google::protobuf::io::CodedInputStream* input,
RepeatedField<CType>* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+ // Like ReadRepeatedFixedSizePrimitive but for packed primitive fields.
+ template <typename CType, enum FieldType DeclaredType>
+ static inline bool ReadPackedFixedSizePrimitive(
+ google::protobuf::io::CodedInputStream* input,
+ RepeatedField<CType>* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+
static const CppType kFieldTypeToCppTypeMap[];
static const WireFormatLite::WireType kWireTypeForFieldType[];
@@ -516,6 +557,24 @@ class LIBPROTOBUF_EXPORT FieldSkipper {
virtual void SkipUnknownEnum(int field_number, int value);
};
+// Subclass of FieldSkipper which saves skipped fields to a CodedOutputStream.
+
+class LIBPROTOBUF_EXPORT CodedOutputStreamFieldSkipper : public FieldSkipper {
+ public:
+ explicit CodedOutputStreamFieldSkipper(io::CodedOutputStream* unknown_fields)
+ : unknown_fields_(unknown_fields) {}
+ virtual ~CodedOutputStreamFieldSkipper() {}
+
+ // implements FieldSkipper -----------------------------------------
+ virtual bool SkipField(io::CodedInputStream* input, uint32 tag);
+ virtual bool SkipMessage(io::CodedInputStream* input);
+ virtual void SkipUnknownEnum(int field_number, int value);
+
+ protected:
+ io::CodedOutputStream* unknown_fields_;
+};
+
+
// inline methods ====================================================
inline WireFormatLite::CppType
@@ -597,7 +656,7 @@ inline double WireFormatLite::DecodeDouble(uint64 value) {
inline uint32 WireFormatLite::ZigZagEncode32(int32 n) {
// Note: the right-shift must be arithmetic
- return (n << 1) ^ (n >> 31);
+ return (static_cast<uint32>(n) << 1) ^ (n >> 31);
}
inline int32 WireFormatLite::ZigZagDecode32(uint32 n) {
@@ -606,13 +665,26 @@ inline int32 WireFormatLite::ZigZagDecode32(uint32 n) {
inline uint64 WireFormatLite::ZigZagEncode64(int64 n) {
// Note: the right-shift must be arithmetic
- return (n << 1) ^ (n >> 63);
+ return (static_cast<uint64>(n) << 1) ^ (n >> 63);
}
inline int64 WireFormatLite::ZigZagDecode64(uint64 n) {
return (n >> 1) ^ -static_cast<int64>(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 103b0bd0..129fc63f 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -36,13 +36,18 @@
#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
+#ifdef _MSC_VER
+// This is required for min/max on VS2013 only.
+#include <algorithm>
+#endif
+
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arenastring.h>
namespace google {
@@ -151,8 +156,8 @@ template <>
inline bool WireFormatLite::ReadPrimitive<bool, WireFormatLite::TYPE_BOOL>(
io::CodedInputStream* input,
bool* value) {
- uint32 temp;
- if (!input->ReadVarint32(&temp)) return false;
+ uint64 temp;
+ if (!input->ReadVarint64(&temp)) return false;
*value = temp != 0;
return true;
}
@@ -222,10 +227,11 @@ inline const uint8* WireFormatLite::ReadPrimitiveFromArray<
}
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
-inline bool WireFormatLite::ReadRepeatedPrimitive(int, // tag_size, unused.
- uint32 tag,
- io::CodedInputStream* input,
- RepeatedField<CType>* values) {
+inline bool WireFormatLite::ReadRepeatedPrimitive(
+ int, // tag_size, unused.
+ uint32 tag,
+ io::CodedInputStream* input,
+ RepeatedField<CType>* values) {
CType value;
if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
values->Add(value);
@@ -285,7 +291,7 @@ inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive(
return true;
}
-// Specializations of ReadRepeatedPrimitive for the fixed size types, which use
+// Specializations of ReadRepeatedPrimitive for the fixed size types, which use
// the optimized code path.
#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \
template <> \
@@ -300,12 +306,12 @@ inline bool WireFormatLite::ReadRepeatedPrimitive< \
tag_size, tag, input, values); \
}
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE);
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE
@@ -335,12 +341,93 @@ inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input,
}
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadPackedFixedSizePrimitive(
+ io::CodedInputStream* input, RepeatedField<CType>* values) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ const uint32 old_entries = values->size();
+ const uint32 new_entries = length / sizeof(CType);
+ const uint32 new_bytes = new_entries * sizeof(CType);
+ if (new_bytes != length) return false;
+ // We would *like* to pre-allocate the buffer to write into (for
+ // speed), but *must* avoid performing a very large allocation due
+ // to a malicious user-supplied "length" above. So we have a fast
+ // path that pre-allocates when the "length" is less than a bound.
+ // We determine the bound by calling BytesUntilTotalBytesLimit() and
+ // BytesUntilLimit(). These return -1 to mean "no limit set".
+ // There are four cases:
+ // TotalBytesLimit Limit
+ // -1 -1 Use slow path.
+ // -1 >= 0 Use fast path if length <= Limit.
+ // >= 0 -1 Use slow path.
+ // >= 0 >= 0 Use fast path if length <= min(both limits).
+ int64 bytes_limit = input->BytesUntilTotalBytesLimit();
+ if (bytes_limit == -1) {
+ bytes_limit = input->BytesUntilLimit();
+ } else {
+ bytes_limit =
+ min(bytes_limit, static_cast<int64>(input->BytesUntilLimit()));
+ }
+ if (bytes_limit >= new_bytes) {
+ // Fast-path that pre-allocates *values to the final size.
+#if defined(PROTOBUF_LITTLE_ENDIAN)
+ values->Resize(old_entries + new_entries, 0);
+ // values->mutable_data() may change after Resize(), so do this after:
+ void* dest = reinterpret_cast<void*>(values->mutable_data() + old_entries);
+ if (!input->ReadRaw(dest, new_bytes)) {
+ values->Truncate(old_entries);
+ return false;
+ }
+#else
+ values->Reserve(old_entries + new_entries);
+ CType value;
+ for (uint32 i = 0; i < new_entries; ++i) {
+ if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+ values->AddAlreadyReserved(value);
+ }
+#endif
+ } else {
+ // This is the slow-path case where "length" may be too large to
+ // safely allocate. We read as much as we can into *values
+ // without pre-allocating "length" bytes.
+ CType value;
+ for (uint32 i = 0; i < new_entries; ++i) {
+ if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+ values->Add(value);
+ }
+ }
+ return true;
+}
+
+// Specializations of ReadPackedPrimitive for the fixed size types, which use
+// an optimized code path.
+#define READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \
+template <> \
+inline bool WireFormatLite::ReadPackedPrimitive< \
+ CPPTYPE, WireFormatLite::DECLARED_TYPE>( \
+ io::CodedInputStream* input, \
+ RepeatedField<CPPTYPE>* values) { \
+ return ReadPackedFixedSizePrimitive< \
+ CPPTYPE, WireFormatLite::DECLARED_TYPE>(input, values); \
+}
+
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE);
+
+#undef READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input,
RepeatedField<CType>* values) {
return ReadPackedPrimitive<CType, DeclaredType>(input, values);
}
+
inline bool WireFormatLite::ReadGroup(int field_number,
io::CodedInputStream* input,
MessageLite* value) {
@@ -357,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<io::CodedInputStream::Limit, int> 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
@@ -398,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<io::CodedInputStream::Limit, int> 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);
}
// ===================================================================
@@ -661,15 +742,13 @@ inline uint8* WireFormatLite::WriteStringToArray(int field_number,
// WriteString() to avoid code duplication. If the implementations become
// different, you will need to update that usage.
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
- target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target);
- return io::CodedOutputStream::WriteStringToArray(value, target);
+ return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
}
inline uint8* WireFormatLite::WriteBytesToArray(int field_number,
const string& value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
- target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target);
- return io::CodedOutputStream::WriteStringToArray(value, target);
+ return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
}
@@ -749,8 +828,7 @@ inline int WireFormatLite::GroupSize(const MessageLite& value) {
return value.ByteSize();
}
inline int WireFormatLite::MessageSize(const MessageLite& value) {
- int size = value.ByteSize();
- return io::CodedOutputStream::VarintSize32(size) + size;
+ return LengthDelimitedSize(value.ByteSize());
}
// See comment on ReadGroupNoVirtual to understand the need for this template
@@ -763,8 +841,12 @@ inline int WireFormatLite::GroupSizeNoVirtual(
template<typename MessageType_WorkAroundCppLookupDefect>
inline int WireFormatLite::MessageSizeNoVirtual(
const MessageType_WorkAroundCppLookupDefect& value) {
- int size = value.MessageType_WorkAroundCppLookupDefect::ByteSize();
- return io::CodedOutputStream::VarintSize32(size) + size;
+ return LengthDelimitedSize(
+ value.MessageType_WorkAroundCppLookupDefect::ByteSize());
+}
+
+inline int WireFormatLite::LengthDelimitedSize(int length) {
+ return io::CodedOutputStream::VarintSize32(length) + length;
}
} // namespace internal
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
index 867970c4..a3062a6a 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// http://code.google.com/p/protobuf/
+// 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
@@ -44,7 +44,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
@@ -175,6 +175,43 @@ TEST(WireFormatTest, ParsePackedExtensions) {
TestUtil::ExpectPackedExtensionsSet(dest);
}
+TEST(WireFormatTest, ParseOneof) {
+ unittest::TestOneof2 source, dest;
+ string data;
+
+ // Serialize using the generated code.
+ TestUtil::SetOneof1(&source);
+ source.SerializeToString(&data);
+
+ // Parse using WireFormat.
+ io::ArrayInputStream raw_input(data.data(), data.size());
+ io::CodedInputStream input(&raw_input);
+ WireFormat::ParseAndMergePartial(&input, &dest);
+
+ // Check.
+ TestUtil::ExpectOneofSet1(dest);
+}
+
+TEST(WireFormatTest, OneofOnlySetLast) {
+ unittest::TestOneofBackwardsCompatible source;
+ unittest::TestOneof oneof_dest;
+ string data;
+
+ // Set two fields
+ source.set_foo_int(100);
+ source.set_foo_string("101");
+
+ // Serialize and parse to oneof message.
+ source.SerializeToString(&data);
+ io::ArrayInputStream raw_input(data.data(), data.size());
+ io::CodedInputStream input(&raw_input);
+ WireFormat::ParseAndMergePartial(&input, &oneof_dest);
+
+ // Only the last field is set.
+ EXPECT_FALSE(oneof_dest.has_foo_int());
+ EXPECT_TRUE(oneof_dest.has_foo_string());
+}
+
TEST(WireFormatTest, ByteSize) {
unittest::TestAllTypes message;
TestUtil::SetAllFields(&message);
@@ -217,6 +254,18 @@ TEST(WireFormatTest, ByteSizePackedExtensions) {
EXPECT_EQ(0, WireFormat::ByteSize(message));
}
+TEST(WireFormatTest, ByteSizeOneof) {
+ unittest::TestOneof2 message;
+ TestUtil::SetOneof1(&message);
+
+ EXPECT_EQ(message.ByteSize(),
+ WireFormat::ByteSize(message));
+ message.Clear();
+
+ EXPECT_EQ(0, message.ByteSize());
+ EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
TEST(WireFormatTest, Serialize) {
unittest::TestAllTypes message;
string generated_data;
@@ -311,6 +360,36 @@ TEST(WireFormatTest, SerializeFieldsAndExtensions) {
TestUtil::ExpectAllFieldsAndExtensionsInOrder(generated_data);
}
+TEST(WireFormatTest, SerializeOneof) {
+ unittest::TestOneof2 message;
+ string generated_data;
+ string dynamic_data;
+
+ TestUtil::SetOneof1(&message);
+ int size = message.ByteSize();
+
+ // Serialize using the generated code.
+ {
+ io::StringOutputStream raw_output(&generated_data);
+ io::CodedOutputStream output(&raw_output);
+ message.SerializeWithCachedSizes(&output);
+ ASSERT_FALSE(output.HadError());
+ }
+
+ // Serialize using WireFormat.
+ {
+ io::StringOutputStream raw_output(&dynamic_data);
+ io::CodedOutputStream output(&raw_output);
+ WireFormat::SerializeWithCachedSizes(message, size, &output);
+ ASSERT_FALSE(output.HadError());
+ }
+
+ // Should be the same.
+ // Don't use EXPECT_EQ here because we're comparing raw binary data and
+ // we really don't want it dumped to stdout on failure.
+ EXPECT_TRUE(dynamic_data == generated_data);
+}
+
TEST(WireFormatTest, ParseMultipleExtensionRanges) {
// Make sure we can parse a message that contains multiple extensions ranges.
unittest::TestFieldOrderings source;
@@ -480,6 +559,54 @@ TEST(WireFormatTest, ParseMessageSet) {
EXPECT_EQ(message_set.DebugString(), dynamic_message_set.DebugString());
}
+TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) {
+ string data;
+ {
+ unittest::TestMessageSetExtension1 message;
+ message.set_i(123);
+ // Build a MessageSet manually with its message content put before its
+ // type_id.
+ io::StringOutputStream output_stream(&data);
+ io::CodedOutputStream coded_output(&output_stream);
+ coded_output.WriteTag(WireFormatLite::kMessageSetItemStartTag);
+ // Write the message content first.
+ WireFormatLite::WriteTag(WireFormatLite::kMessageSetMessageNumber,
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+ &coded_output);
+ coded_output.WriteVarint32(message.ByteSize());
+ message.SerializeWithCachedSizes(&coded_output);
+ // Write the type id.
+ uint32 type_id = message.GetDescriptor()->extension(0)->number();
+ WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
+ type_id, &coded_output);
+ coded_output.WriteTag(WireFormatLite::kMessageSetItemEndTag);
+ }
+ {
+ unittest::TestMessageSet message_set;
+ ASSERT_TRUE(message_set.ParseFromString(data));
+
+ EXPECT_EQ(123, message_set.GetExtension(
+ unittest::TestMessageSetExtension1::message_set_extension).i());
+ }
+ {
+ // Test parse the message via Reflection.
+ unittest::TestMessageSet message_set;
+ io::CodedInputStream input(
+ reinterpret_cast<const uint8*>(data.data()), data.size());
+ EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set));
+ EXPECT_TRUE(input.ConsumedEntireMessage());
+
+ EXPECT_EQ(123, message_set.GetExtension(
+ unittest::TestMessageSetExtension1::message_set_extension).i());
+ }
+}
+
+TEST(WireFormatTest, ParseBrokenMessageSet) {
+ unittest::TestMessageSet message_set;
+ string input("goodbye"); // Invalid wire format data.
+ EXPECT_FALSE(message_set.ParseFromString(input));
+}
+
TEST(WireFormatTest, RecursionLimit) {
unittest::TestRecursiveMessage message;
message.mutable_a()->mutable_a()->mutable_a()->mutable_a()->set_i(1);
@@ -639,6 +766,34 @@ TEST(WireFormatTest, RepeatedScalarsDifferentTagSizes) {
EXPECT_EQ(msg1.DebugString(), msg2.DebugString());
}
+TEST(WireFormatTest, CompatibleTypes) {
+ const int64 data = 0x100000000;
+ unittest::Int64Message msg1;
+ msg1.set_data(data);
+ string serialized;
+ msg1.SerializeToString(&serialized);
+
+ // Test int64 is compatible with bool
+ unittest::BoolMessage msg2;
+ ASSERT_TRUE(msg2.ParseFromString(serialized));
+ ASSERT_EQ(static_cast<bool>(data), msg2.data());
+
+ // Test int64 is compatible with uint64
+ unittest::Uint64Message msg3;
+ ASSERT_TRUE(msg3.ParseFromString(serialized));
+ ASSERT_EQ(static_cast<uint64>(data), msg3.data());
+
+ // Test int64 is compatible with int32
+ unittest::Int32Message msg4;
+ ASSERT_TRUE(msg4.ParseFromString(serialized));
+ ASSERT_EQ(static_cast<int32>(data), msg4.data());
+
+ // Test int64 is compatible with uint32
+ unittest::Uint32Message msg5;
+ ASSERT_TRUE(msg5.ParseFromString(serialized));
+ ASSERT_EQ(static_cast<uint32>(data), msg5.data());
+}
+
class WireFormatInvalidInputTest : public testing::Test {
protected:
// Make a serialized TestAllTypes in which the field optional_nested_message
@@ -800,7 +955,20 @@ bool ReadMessage(const string &wire_buffer, T *message) {
return message->ParseFromArray(wire_buffer.data(), wire_buffer.size());
}
-TEST(Utf8ValidationTest, WriteInvalidUTF8String) {
+bool StartsWith(const string& s, const string& prefix) {
+ return s.substr(0, prefix.length()) == prefix;
+}
+
+class Utf8ValidationTest : public ::testing::Test {
+ protected:
+ Utf8ValidationTest() {}
+ virtual ~Utf8ValidationTest() {}
+ virtual void SetUp() {
+ }
+
+};
+
+TEST_F(Utf8ValidationTest, WriteInvalidUTF8String) {
string wire_buffer;
protobuf_unittest::OneString input;
vector<string> errors;
@@ -811,17 +979,18 @@ TEST(Utf8ValidationTest, WriteInvalidUTF8String) {
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
ASSERT_EQ(1, errors.size());
- EXPECT_EQ("Encountered string containing invalid UTF-8 data while "
- "serializing protocol buffer. Strings must contain only UTF-8; "
- "use the 'bytes' type for raw bytes.",
- errors[0]);
-
+ EXPECT_TRUE(StartsWith(errors[0],
+ "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
ASSERT_EQ(0, errors.size());
#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
}
-TEST(Utf8ValidationTest, ReadInvalidUTF8String) {
+
+TEST_F(Utf8ValidationTest, ReadInvalidUTF8String) {
string wire_buffer;
protobuf_unittest::OneString input;
WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
@@ -834,17 +1003,19 @@ TEST(Utf8ValidationTest, ReadInvalidUTF8String) {
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
ASSERT_EQ(1, errors.size());
- EXPECT_EQ("Encountered string containing invalid UTF-8 data while "
- "parsing protocol buffer. Strings must contain only UTF-8; "
- "use the 'bytes' type for raw bytes.",
- errors[0]);
+ EXPECT_TRUE(StartsWith(errors[0],
+ "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."));
#else
ASSERT_EQ(0, errors.size());
#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
}
-TEST(Utf8ValidationTest, WriteValidUTF8String) {
+
+TEST_F(Utf8ValidationTest, WriteValidUTF8String) {
string wire_buffer;
protobuf_unittest::OneString input;
vector<string> errors;
@@ -856,7 +1027,7 @@ TEST(Utf8ValidationTest, WriteValidUTF8String) {
ASSERT_EQ(0, errors.size());
}
-TEST(Utf8ValidationTest, ReadValidUTF8String) {
+TEST_F(Utf8ValidationTest, ReadValidUTF8String) {
string wire_buffer;
protobuf_unittest::OneString input;
WriteMessage(kValidUTF8String, &input, &wire_buffer);
@@ -872,7 +1043,7 @@ TEST(Utf8ValidationTest, ReadValidUTF8String) {
}
// Bytes: anything can pass as bytes, use invalid UTF-8 string to test
-TEST(Utf8ValidationTest, WriteArbitraryBytes) {
+TEST_F(Utf8ValidationTest, WriteArbitraryBytes) {
string wire_buffer;
protobuf_unittest::OneBytes input;
vector<string> errors;
@@ -884,7 +1055,7 @@ TEST(Utf8ValidationTest, WriteArbitraryBytes) {
ASSERT_EQ(0, errors.size());
}
-TEST(Utf8ValidationTest, ReadArbitraryBytes) {
+TEST_F(Utf8ValidationTest, ReadArbitraryBytes) {
string wire_buffer;
protobuf_unittest::OneBytes input;
WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
@@ -899,6 +1070,52 @@ TEST(Utf8ValidationTest, ReadArbitraryBytes) {
EXPECT_EQ(input.data(), output.data());
}
+TEST_F(Utf8ValidationTest, ParseRepeatedString) {
+ protobuf_unittest::MoreBytes input;
+ input.add_data(kValidUTF8String);
+ input.add_data(kInvalidUTF8String);
+ input.add_data(kInvalidUTF8String);
+ string wire_buffer = input.SerializeAsString();
+
+ protobuf_unittest::MoreString output;
+ vector<string> errors;
+ {
+ ScopedMemoryLog log;
+ ReadMessage(wire_buffer, &output);
+ errors = log.GetMessages(ERROR);
+ }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+ ASSERT_EQ(2, errors.size());
+#else
+ ASSERT_EQ(0, errors.size());
+#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+ EXPECT_EQ(wire_buffer, output.SerializeAsString());
+}
+
+// Test the old VerifyUTF8String() function, which may still be called by old
+// generated code.
+TEST_F(Utf8ValidationTest, OldVerifyUTF8String) {
+ string data(kInvalidUTF8String);
+
+ vector<string> errors;
+ {
+ ScopedMemoryLog log;
+ WireFormat::VerifyUTF8String(data.data(), data.size(),
+ WireFormat::SERIALIZE);
+ errors = log.GetMessages(ERROR);
+ }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+ ASSERT_EQ(1, errors.size());
+ EXPECT_TRUE(StartsWith(errors[0],
+ "String field contains invalid UTF-8 data when "
+ "serializing a protocol buffer. Use the "
+ "'bytes' type if you intend to send raw bytes."));
+#else
+ ASSERT_EQ(0, errors.size());
+#endif
+}
+
+
} // namespace
} // namespace internal
} // namespace protobuf
diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto
new file mode 100644
index 00000000..5164c24c
--- /dev/null
+++ b/src/google/protobuf/wrappers.proto
@@ -0,0 +1,97 @@
+// 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.
+
+// Wrappers for primitive (non-message) types. These types are useful
+// for embedding primitives in the `google.protobuf.Any` type and for places
+// where we need to distinguish between the absence of a primitive
+// typed field and its default value.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option java_multiple_files = true;
+option java_outer_classname = "WrappersProto";
+option java_package = "com.google.protobuf";
+
+
+// Wrapper message for double.
+message DoubleValue {
+ // The double value.
+ double value = 1;
+}
+
+// Wrapper message for float.
+message FloatValue {
+ // The float value.
+ float value = 1;
+}
+
+// Wrapper message for int64.
+message Int64Value {
+ // The int64 value.
+ int64 value = 1;
+}
+
+// Wrapper message for uint64.
+message UInt64Value {
+ // The uint64 value.
+ uint64 value = 1;
+}
+
+// Wrapper message for int32.
+message Int32Value {
+ // The int32 value.
+ int32 value = 1;
+}
+
+// Wrapper message for uint32.
+message UInt32Value {
+ // The uint32 value.
+ uint32 value = 1;
+}
+
+// Wrapper message for bool.
+message BoolValue {
+ // The bool value.
+ bool value = 1;
+}
+
+// Wrapper message for string.
+message StringValue {
+ // The string value.
+ string value = 1;
+}
+
+// Wrapper message for bytes.
+message BytesValue {
+ // The bytes value.
+ bytes value = 1;
+}
diff --git a/vsprojects/config.h b/vsprojects/config.h
index 2c64450a..a93bb033 100644..100755
--- a/vsprojects/config.h
+++ b/vsprojects/config.h
@@ -1,28 +1,19 @@
/* protobuf config.h for MSVC. On other platforms, this is generated
* automatically by autoheader / autoconf / configure. */
-/* the location of <hash_map> */
-#define HASH_MAP_H <hash_map>
+#include <google/protobuf/stubs/pbconfig.h>
-/* the namespace of hash_map/hash_set */
-// Apparently Microsoft decided to move hash_map *back* to the std namespace
-// in MSVC 2010:
-// http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx
-// TODO(kenton): Use unordered_map instead, which is available in MSVC 2010.
-#if _MSC_VER < 1310 || _MSC_VER >= 1600
-#define HASH_NAMESPACE std
-#else
-#define HASH_NAMESPACE stdext
-#endif
-
-/* the location of <hash_set> */
-#define HASH_SET_H <hash_set>
+#define HASH_MAP_H GOOGLE_PROTOBUF_HASH_MAP_H
+#define HASH_NAMESPACE GOOGLE_PROTOBUF_HASH_NAMESPACE
+#define HASH_SET_H GOOGLE_PROTOBUF_HASH_SET_H
-/* define if the compiler has hash_map */
-#define HAVE_HASH_MAP 1
+#ifdef GOOGLE_PROTOBUF_HAVE_HASH_MAP
+#define HAVE_HASH_MAP GOOGLE_PROTOBUF_HAVE_HASH_MAP
+#endif
-/* define if the compiler has hash_set */
-#define HAVE_HASH_SET 1
+#ifdef GOOGLE_PROTOBUF_HAVE_HASH_SET
+#define HAVE_HASH_SET GOOGLE_PROTOBUF_HAVE_HASH_SET
+#endif
/* define if you want to use zlib. See readme.txt for additional
* requirements. */
diff --git a/vsprojects/extract_includes.bat b/vsprojects/extract_includes.bat
index 386d2040..ddf7f33f 100755
--- a/vsprojects/extract_includes.bat
+++ b/vsprojects/extract_includes.bat
@@ -6,38 +6,82 @@ md include\google\protobuf\io
md include\google\protobuf\compiler
md include\google\protobuf\compiler\cpp
md include\google\protobuf\compiler\java
+md include\google\protobuf\compiler\javanano
md include\google\protobuf\compiler\python
-copy ..\src\google\protobuf\stubs\common.h include\google\protobuf\stubs\common.h
-copy ..\src\google\protobuf\stubs\once.h include\google\protobuf\stubs\once.h
+md include\google\protobuf\compiler\ruby
+copy ..\src\google\protobuf\arena.h include\google\protobuf\arena.h
+copy ..\src\google\protobuf\arenastring.h include\google\protobuf\arenastring.h
+copy ..\src\google\protobuf\compiler\code_generator.h include\google\protobuf\compiler\code_generator.h
+copy ..\src\google\protobuf\compiler\command_line_interface.h include\google\protobuf\compiler\command_line_interface.h
+copy ..\src\google\protobuf\compiler\cpp\cpp_generator.h include\google\protobuf\compiler\cpp\cpp_generator.h
+copy ..\src\google\protobuf\compiler\importer.h include\google\protobuf\compiler\importer.h
+copy ..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h
+copy ..\src\google\protobuf\compiler\javanano\javanano_generator.h include\google\protobuf\compiler\javanano\javanano_generator.h
+copy ..\src\google\protobuf\compiler\parser.h include\google\protobuf\compiler\parser.h
+copy ..\src\google\protobuf\compiler\plugin.h include\google\protobuf\compiler\plugin.h
+copy ..\src\google\protobuf\compiler\plugin.pb.h include\google\protobuf\compiler\plugin.pb.h
+copy ..\src\google\protobuf\compiler\python\python_generator.h include\google\protobuf\compiler\python\python_generator.h
+copy ..\src\google\protobuf\compiler\ruby\ruby_generator.h include\google\protobuf\compiler\ruby\ruby_generator.h
+copy ..\src\google\protobuf\descriptor_database.h include\google\protobuf\descriptor_database.h
copy ..\src\google\protobuf\descriptor.h include\google\protobuf\descriptor.h
copy ..\src\google\protobuf\descriptor.pb.h include\google\protobuf\descriptor.pb.h
-copy ..\src\google\protobuf\descriptor_database.h include\google\protobuf\descriptor_database.h
copy ..\src\google\protobuf\dynamic_message.h include\google\protobuf\dynamic_message.h
copy ..\src\google\protobuf\extension_set.h include\google\protobuf\extension_set.h
-copy ..\src\google\protobuf\generated_message_util.h include\google\protobuf\generated_message_util.h
+copy ..\src\google\protobuf\generated_enum_reflection.h include\google\protobuf\generated_enum_reflection.h
+copy ..\src\google\protobuf\generated_enum_util.h include\google\protobuf\generated_enum_util.h
copy ..\src\google\protobuf\generated_message_reflection.h include\google\protobuf\generated_message_reflection.h
+copy ..\src\google\protobuf\generated_message_util.h include\google\protobuf\generated_message_util.h
+copy ..\src\google\protobuf\io\coded_stream.h include\google\protobuf\io\coded_stream.h
+copy ..\src\google\protobuf\io\gzip_stream.h include\google\protobuf\io\gzip_stream.h
+copy ..\src\google\protobuf\io\printer.h include\google\protobuf\io\printer.h
+copy ..\src\google\protobuf\io\strtod.h include\google\protobuf\io\strtod.h
+copy ..\src\google\protobuf\io\tokenizer.h include\google\protobuf\io\tokenizer.h
+copy ..\src\google\protobuf\io\zero_copy_stream.h include\google\protobuf\io\zero_copy_stream.h
+copy ..\src\google\protobuf\io\zero_copy_stream_impl.h include\google\protobuf\io\zero_copy_stream_impl.h
+copy ..\src\google\protobuf\io\zero_copy_stream_impl_lite.h include\google\protobuf\io\zero_copy_stream_impl_lite.h
+copy ..\src\google\protobuf\map_entry.h include\google\protobuf\map_entry.h
+copy ..\src\google\protobuf\map_entry_lite.h include\google\protobuf\map_entry_lite.h
+copy ..\src\google\protobuf\map_field.h include\google\protobuf\map_field.h
+copy ..\src\google\protobuf\map_field_lite.h include\google\protobuf\map_field_lite.h
+copy ..\src\google\protobuf\map_field_inl.h include\google\protobuf\map_field_inl.h
+copy ..\src\google\protobuf\map.h include\google\protobuf\map.h
+copy ..\src\google\protobuf\map_type_handler.h include\google\protobuf\map_type_handler.h
copy ..\src\google\protobuf\message.h include\google\protobuf\message.h
copy ..\src\google\protobuf\message_lite.h include\google\protobuf\message_lite.h
+copy ..\src\google\protobuf\metadata.h include\google\protobuf\metadata.h
+copy ..\src\google\protobuf\reflection.h include\google\protobuf\reflection.h
copy ..\src\google\protobuf\reflection_ops.h include\google\protobuf\reflection_ops.h
copy ..\src\google\protobuf\repeated_field.h include\google\protobuf\repeated_field.h
+copy ..\src\google\protobuf\repeated_field_reflection.h include\google\protobuf\repeated_field_reflection.h
copy ..\src\google\protobuf\service.h include\google\protobuf\service.h
+copy ..\src\google\protobuf\stubs\atomicops.h include\google\protobuf\stubs\atomicops.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_aix.h include\google\protobuf\stubs\atomicops_internals_aix.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_arm64_gcc.h include\google\protobuf\stubs\atomicops_internals_arm64_gcc.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_arm_gcc.h include\google\protobuf\stubs\atomicops_internals_arm_gcc.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_arm_qnx.h include\google\protobuf\stubs\atomicops_internals_arm_qnx.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_atomicword_compat.h include\google\protobuf\stubs\atomicops_internals_atomicword_compat.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_generic_gcc.h include\google\protobuf\stubs\atomicops_internals_generic_gcc.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_macosx.h include\google\protobuf\stubs\atomicops_internals_macosx.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_mips_gcc.h include\google\protobuf\stubs\atomicops_internals_mips_gcc.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_pnacl.h include\google\protobuf\stubs\atomicops_internals_pnacl.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_solaris.h include\google\protobuf\stubs\atomicops_internals_solaris.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_tsan.h include\google\protobuf\stubs\atomicops_internals_tsan.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_x86_gcc.h include\google\protobuf\stubs\atomicops_internals_x86_gcc.h
+copy ..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.h include\google\protobuf\stubs\atomicops_internals_x86_msvc.h
+copy ..\src\google\protobuf\stubs\atomic_sequence_num.h include\google\protobuf\stubs\atomic_sequence_num.h
+copy ..\src\google\protobuf\stubs\casts.h include\google\protobuf\stubs\casts.h
+copy ..\src\google\protobuf\stubs\common.h include\google\protobuf\stubs\common.h
+copy ..\src\google\protobuf\stubs\fastmem.h include\google\protobuf\stubs\fastmem.h
+copy ..\src\google\protobuf\stubs\once.h include\google\protobuf\stubs\once.h
+copy ..\src\google\protobuf\stubs\platform_macros.h include\google\protobuf\stubs\platform_macros.h
+copy ..\src\google\protobuf\stubs\singleton.h include\google\protobuf\stubs\singleton.h
+copy ..\src\google\protobuf\stubs\hash.h include\google\protobuf\stubs\hash.h
+copy ..\src\google\protobuf\stubs\stl_util.h include\google\protobuf\stubs\stl_util.h
+copy ..\src\google\protobuf\stubs\template_util.h include\google\protobuf\stubs\template_util.h
+copy ..\src\google\protobuf\stubs\type_traits.h include\google\protobuf\stubs\type_traits.h
copy ..\src\google\protobuf\text_format.h include\google\protobuf\text_format.h
copy ..\src\google\protobuf\unknown_field_set.h include\google\protobuf\unknown_field_set.h
copy ..\src\google\protobuf\wire_format.h include\google\protobuf\wire_format.h
copy ..\src\google\protobuf\wire_format_lite.h include\google\protobuf\wire_format_lite.h
copy ..\src\google\protobuf\wire_format_lite_inl.h include\google\protobuf\wire_format_lite_inl.h
-copy ..\src\google\protobuf\io\coded_stream.h include\google\protobuf\io\coded_stream.h
-copy ..\src\google\protobuf\io\gzip_stream.h include\google\protobuf\io\gzip_stream.h
-copy ..\src\google\protobuf\io\printer.h include\google\protobuf\io\printer.h
-copy ..\src\google\protobuf\io\tokenizer.h include\google\protobuf\io\tokenizer.h
-copy ..\src\google\protobuf\io\zero_copy_stream.h include\google\protobuf\io\zero_copy_stream.h
-copy ..\src\google\protobuf\io\zero_copy_stream_impl.h include\google\protobuf\io\zero_copy_stream_impl.h
-copy ..\src\google\protobuf\io\zero_copy_stream_impl_lite.h include\google\protobuf\io\zero_copy_stream_impl_lite.h
-copy ..\src\google\protobuf\compiler\code_generator.h include\google\protobuf\compiler\code_generator.h
-copy ..\src\google\protobuf\compiler\command_line_interface.h include\google\protobuf\compiler\command_line_interface.h
-copy ..\src\google\protobuf\compiler\importer.h include\google\protobuf\compiler\importer.h
-copy ..\src\google\protobuf\compiler\parser.h include\google\protobuf\compiler\parser.h
-copy ..\src\google\protobuf\compiler\cpp\cpp_generator.h include\google\protobuf\compiler\cpp\cpp_generator.h
-copy ..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h
-copy ..\src\google\protobuf\compiler\python\python_generator.h include\google\protobuf\compiler\python\python_generator.h
-copy ..\src\google\protobuf\compiler\plugin.h include\google\protobuf\compiler\plugin.h
+copy google\protobuf\stubs\pbconfig.h include\google\protobuf\stubs\pbconfig.h
diff --git a/vsprojects/google/protobuf/stubs/pbconfig.h b/vsprojects/google/protobuf/stubs/pbconfig.h
new file mode 100755
index 00000000..18250a22
--- /dev/null
+++ b/vsprojects/google/protobuf/stubs/pbconfig.h
@@ -0,0 +1,39 @@
+/* protobuf config.h for MSVC. On other platforms, this is generated
+ * automatically by autoheader / autoconf / configure. */
+
+// NOTE: if you add new macros in this file manually, please propagate the macro
+// to vsprojects/config.h.
+
+/* the namespace of hash_map/hash_set */
+// Apparently Microsoft decided to move hash_map *back* to the std namespace
+// in MSVC 2010:
+// http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx
+// And.. they are moved back to stdext in MSVC 2013 (haven't checked 2012). That
+// said, use unordered_map for MSVC 2010 and beyond is our safest bet.
+#if _MSC_VER >= 1600
+#define GOOGLE_PROTOBUF_HASH_NAMESPACE std
+#define GOOGLE_PROTOBUF_HASH_MAP_H <unordered_map>
+#define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map
+#define GOOGLE_PROTOBUF_HASH_SET_H <unordered_set>
+#define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set
+#elif _MSC_VER >= 1310
+#define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
+#define GOOGLE_PROTOBUF_HASH_MAP_H <hash_map>
+#define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
+#define GOOGLE_PROTOBUF_HASH_SET_H <hash_set>
+#define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
+#else
+#define GOOGLE_PROTOBUF_HASH_NAMESPACE std
+#define GOOGLE_PROTOBUF_HASH_MAP_H <hash_map>
+#define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
+#define GOOGLE_PROTOBUF_HASH_SET_H <hash_set>
+#define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
+#endif
+
+/* the location of <hash_set> */
+
+/* define if the compiler has hash_map */
+#define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1
+
+/* define if the compiler has hash_set */
+#define GOOGLE_PROTOBUF_HAVE_HASH_SET 1
diff --git a/vsprojects/libprotobuf-lite.vcproj b/vsprojects/libprotobuf-lite.vcproj
index 2966c979..d245448d 100644
--- a/vsprojects/libprotobuf-lite.vcproj
+++ b/vsprojects/libprotobuf-lite.vcproj
@@ -18,7 +18,7 @@
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
- IntermediateDirectory="Debug"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="4"
>
<Tool
@@ -81,7 +81,7 @@
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
- IntermediateDirectory="Release"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="4"
>
<Tool
@@ -164,6 +164,10 @@
>
</File>
<File
+ RelativePath=".\google\protobuf\stubs\pbconfig.h"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\extension_set.h"
>
</File>
@@ -179,6 +183,9 @@
RelativePath="..\src\google\protobuf\stubs\map-util.h"
>
</File>
+ <File RelativePath="..\src\google\protobuf\generated_enum_util.h"></File>
+ <File RelativePath="..\src\google\protobuf\map_entry_lite.h"></File>
+ <File RelativePath="..\src\google\protobuf\map_field_lite.h"></File>
<File
RelativePath="..\src\google\protobuf\message_lite.h"
>
@@ -188,11 +195,23 @@
>
</File>
<File
+ RelativePath="..\src\google\protobuf\stubs\atomicops.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\platform_macros.h"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\repeated_field.h"
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\stl_util-inl.h"
+ RelativePath="..\src\google\protobuf\stubs\stl_util.h"
>
</File>
<File
@@ -211,6 +230,18 @@
RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl_lite.h"
>
</File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\stringprintf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\template_util.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\type_traits.h"
+ >
+ </File>
</Filter>
<Filter
Name="Resource Files"
@@ -224,7 +255,11 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
- RelativePath="..\src\google\protobuf\io\coded_stream.cc"
+ RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_gcc.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.cc"
>
</File>
<File
@@ -232,6 +267,22 @@
>
</File>
<File
+ RelativePath="..\src\google\protobuf\stubs\once.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\stringprintf.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\arena.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\arenastring.cc"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\extension_set.cc"
>
</File>
@@ -244,15 +295,15 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\once.cc"
+ RelativePath="..\src\google\protobuf\repeated_field.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\repeated_field.cc"
+ RelativePath="..\src\google\protobuf\wire_format_lite.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\wire_format_lite.cc"
+ RelativePath="..\src\google\protobuf\io\coded_stream.cc"
>
</File>
<File
diff --git a/vsprojects/libprotobuf.vcproj b/vsprojects/libprotobuf.vcproj
index 65bd6abb..e782885f 100644
--- a/vsprojects/libprotobuf.vcproj
+++ b/vsprojects/libprotobuf.vcproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
@@ -18,7 +18,7 @@
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
- IntermediateDirectory="Debug"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="4"
>
<Tool
@@ -81,7 +81,7 @@
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
- IntermediateDirectory="Release"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="4"
>
<Tool
@@ -164,6 +164,10 @@
>
</File>
<File
+ RelativePath=".\google\protobuf\stubs\pbconfig.h"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\descriptor.h"
>
</File>
@@ -196,6 +200,10 @@
>
</File>
<File
+ RelativePath="..\src\google\protobuf\io\strtod.h"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\stubs\hash.h"
>
</File>
@@ -204,7 +212,7 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\map-util.h"
+ RelativePath="..\src\google\protobuf\stubs\map_util.h"
>
</File>
<File
@@ -215,6 +223,21 @@
RelativePath="..\src\google\protobuf\message_lite.h"
>
</File>
+ <File RelativePath="..\src\google\protobuf\generated_enum_util.h"></File>
+ <File RelativePath="..\src\google\protobuf\map_entry_lite.h"></File>
+ <File RelativePath="..\src\google\protobuf\map_field_lite.h"></File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\atomicops.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\platform_macros.h"
+ >
+ </File>
<File
RelativePath="..\src\google\protobuf\stubs\once.h"
>
@@ -240,7 +263,19 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\stl_util-inl.h"
+ RelativePath="..\src\google\protobuf\stubs\stl_util.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\stringprintf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\template_util.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\type_traits.h"
>
</File>
<File
@@ -300,7 +335,11 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
- RelativePath="..\src\google\protobuf\io\coded_stream.cc"
+ RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_gcc.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.cc"
>
</File>
<File
@@ -308,19 +347,19 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\descriptor.cc"
+ RelativePath="..\src\google\protobuf\stubs\once.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\descriptor.pb.cc"
+ RelativePath="..\src\google\protobuf\stubs\stringprintf.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\descriptor_database.cc"
+ RelativePath="..\src\google\protobuf\arena.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\dynamic_message.cc"
+ RelativePath="..\src\google\protobuf\arenastring.cc"
>
</File>
<File
@@ -328,75 +367,99 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\extension_set_heavy.cc"
+ RelativePath="..\src\google\protobuf\generated_message_util.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\generated_message_reflection.cc"
+ RelativePath="..\src\google\protobuf\map_field.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\generated_message_util.cc"
+ RelativePath="..\src\google\protobuf\message_lite.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\io\gzip_stream.cc"
+ RelativePath="..\src\google\protobuf\repeated_field.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\compiler\importer.cc"
+ RelativePath="..\src\google\protobuf\wire_format_lite.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\message.cc"
+ RelativePath="..\src\google\protobuf\io\coded_stream.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\message_lite.cc"
+ RelativePath="..\src\google\protobuf\io\zero_copy_stream.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\once.cc"
+ RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl_lite.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\compiler\parser.cc"
+ RelativePath="..\src\google\protobuf\stubs\strutil.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\io\printer.cc"
+ RelativePath="..\src\google\protobuf\stubs\strutil.h"
>
</File>
<File
- RelativePath="..\src\google\protobuf\reflection_ops.cc"
+ RelativePath="..\src\google\protobuf\stubs\substitute.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\repeated_field.cc"
+ RelativePath="..\src\google\protobuf\stubs\substitute.h"
>
</File>
<File
- RelativePath="..\src\google\protobuf\service.cc"
+ RelativePath="..\src\google\protobuf\stubs\structurally_valid.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\structurally_valid.cc"
+ RelativePath="..\src\google\protobuf\descriptor.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\strutil.cc"
+ RelativePath="..\src\google\protobuf\descriptor_database.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\substitute.cc"
+ RelativePath="..\src\google\protobuf\descriptor.pb.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\text_format.cc"
+ RelativePath="..\src\google\protobuf\dynamic_message.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\io\tokenizer.cc"
+ RelativePath="..\src\google\protobuf\extension_set_heavy.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\generated_message_reflection.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\message.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\reflection_internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\reflection_ops.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\service.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\text_format.cc"
>
</File>
<File
@@ -408,11 +471,19 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\wire_format_lite.cc"
+ RelativePath="..\src\google\protobuf\io\gzip_stream.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\io\zero_copy_stream.cc"
+ RelativePath="..\src\google\protobuf\io\printer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\strtod.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\tokenizer.cc"
>
</File>
<File
@@ -420,7 +491,11 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl_lite.cc"
+ RelativePath="..\src\google\protobuf\compiler\importer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\parser.cc"
>
</File>
</Filter>
diff --git a/vsprojects/libprotoc.vcproj b/vsprojects/libprotoc.vcproj
index d55e24e0..455c2cc2 100644
--- a/vsprojects/libprotoc.vcproj
+++ b/vsprojects/libprotoc.vcproj
@@ -1,414 +1,542 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="libprotoc"
- ProjectGUID="{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}"
- Keyword="Win32Proj"
- TargetFrameworkVersion="0"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
- ConfigurationType="4"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
- Optimization="0"
- AdditionalIncludeDirectories="../src;."
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBPROTOC_EXPORTS;"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- Detect64BitPortabilityProblems="true"
- DebugInformationFormat="4"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLibrarianTool"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="Release"
- ConfigurationType="4"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
- AdditionalIncludeDirectories="../src;."
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBPROTOC_EXPORTS;"
- RuntimeLibrary="2"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- Detect64BitPortabilityProblems="true"
- DebugInformationFormat="3"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLibrarianTool"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
- >
- <File
- RelativePath="..\src\google\protobuf\compiler\code_generator.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\command_line_interface.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\subprocess.h"
- >
- </File>
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libprotoc"
+ ProjectGUID="{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="0"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
+ ConfigurationType="4"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBPROTOC_EXPORTS;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
+ ConfigurationType="4"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBPROTOC_EXPORTS;"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\google\protobuf\compiler\code_generator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\command_line_interface.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\subprocess.h"
+ >
+ </File>
<File
RelativePath="..\src\google\protobuf\compiler\zip_writer.h"
>
</File>
- <File
- RelativePath="..\src\google\protobuf\compiler\plugin.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\plugin.pb.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_extension.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_file.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_generator.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_helpers.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_primitive_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_service.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_string_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_enum.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_enum_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_extension.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_file.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_generator.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_helpers.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_message.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_message_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_service.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_string_field.h"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\python\python_generator.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
- >
- </Filter>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
- >
- <File
- RelativePath="..\src\google\protobuf\compiler\code_generator.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\command_line_interface.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\subprocess.cc"
- >
- </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\plugin.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\plugin.pb.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_extension.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_generator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_helpers.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_options.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_primitive_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_service.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_string_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_context.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_enum.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_enum_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_extension.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_generator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_generator_factory.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_helpers.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_lazy_message_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_message_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_name_resolver.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_service.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_shared_code_generator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_string_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment.cc"
+ >
+ </File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_enum_field.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_enum.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_extension.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_field.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_file.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_generator.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_helpers.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_map_field.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_message_field.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_message.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_params.h"></File>
+ <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_primitive_field.h"></File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\python\python_generator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\ruby\ruby_generator.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\google\protobuf\compiler\code_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\command_line_interface.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_extension.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_file.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_helpers.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_map_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_primitive_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_service.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_string_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\ruby\ruby_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_context.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_enum.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_enum_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_extension.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_file.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_generator_factory.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_helpers.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_lazy_message_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_map_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_message.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_message_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_name_resolver.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_service.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_shared_code_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_string_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_enum.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_enum_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_extension.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_file.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_helpers.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_map_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_message.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_message_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\javanano\javanano_primitive_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\plugin.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\plugin.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\python\python_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\subprocess.cc"
+ >
+ </File>
<File
RelativePath="..\src\google\protobuf\compiler\zip_writer.cc"
>
</File>
- <File
- RelativePath="..\src\google\protobuf\compiler\plugin.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\plugin.pb.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_extension.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_file.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_generator.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_helpers.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_primitive_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_service.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_string_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_enum.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_enum_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_extension.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_file.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_generator.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_helpers.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_message.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_message_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_service.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\java\java_string_field.cc"
- >
- </File>
- <File
- RelativePath="..\src\google\protobuf\compiler\python\python_generator.cc"
- >
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
</VisualStudioProject>
diff --git a/vsprojects/lite-test.vcproj b/vsprojects/lite-test.vcproj
index f66556ab..8d172248 100644
--- a/vsprojects/lite-test.vcproj
+++ b/vsprojects/lite-test.vcproj
@@ -19,7 +19,7 @@
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
- IntermediateDirectory="Debug"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="1"
>
<Tool
@@ -46,7 +46,7 @@
AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
Optimization="0"
AdditionalIncludeDirectories="../src;.;../gtest/include"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_VARIADIC_MAX=10;"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
@@ -96,7 +96,7 @@
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
- IntermediateDirectory="Release"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="1"
>
<Tool
@@ -122,7 +122,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
AdditionalIncludeDirectories="../src;.;../gtest/include"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_VARIADIC_MAX=10;"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
@@ -182,6 +182,8 @@
RelativePath="..\src\google\protobuf\test_util_lite.h"
>
</File>
+ <File RelativePath=".\google\protobuf\map_lite_unittest.pb.h"></File>
+ <File RelativePath="..\src\google\protobuf\map_lite_test_util.h"></File>
<File
RelativePath=".\google\protobuf\unittest_lite.pb.h"
>
@@ -190,6 +192,10 @@
RelativePath=".\google\protobuf\unittest_import_lite.pb.h"
>
</File>
+ <File
+ RelativePath=".\google\protobuf\unittest_import_public_lite.pb.h"
+ >
+ </File>
</Filter>
<Filter
Name="Resource Files"
@@ -214,10 +220,16 @@
RelativePath=".\google\protobuf\unittest_lite.pb.cc"
>
</File>
+ <File RelativePath=".\google\protobuf\map_lite_unittest.pb.cc"></File>
+ <File RelativePath="..\src\google\protobuf\map_lite_test_util.cc"></File>
<File
RelativePath=".\google\protobuf\unittest_import_lite.pb.cc"
>
</File>
+ <File
+ RelativePath=".\google\protobuf\unittest_import_public_lite.pb.cc"
+ >
+ </File>
</Filter>
<File
RelativePath="..\src\google\protobuf\unittest_lite.proto"
@@ -267,6 +279,54 @@
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_import_public_lite.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import_public_lite.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public_lite.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_import_public_lite.pb.h;google\protobuf\unittest_import_public_lite.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import_public_lite.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public_lite.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_import_public_lite.pb.h;google\protobuf\unittest_import_public_lite.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\map_lite_unittest.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating map_lite_unittest.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/map_lite_unittest.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\map_lite_unittest.pb.h;google\protobuf\map_lite_unittest.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating map_lite_unittest.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/map_lite_unittest.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\map_lite_unittest.pb.h;google\protobuf\map_lite_unittest.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
</Files>
<Globals>
</Globals>
diff --git a/vsprojects/protoc.vcproj b/vsprojects/protoc.vcproj
index 17e8474e..4359e238 100644
--- a/vsprojects/protoc.vcproj
+++ b/vsprojects/protoc.vcproj
@@ -18,7 +18,7 @@
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
- IntermediateDirectory="Debug"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="1"
>
<Tool
@@ -91,7 +91,7 @@
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
- IntermediateDirectory="Release"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="1"
>
<Tool
diff --git a/vsprojects/readme.txt b/vsprojects/readme.txt
index 288345ad..ad342497 100644
--- a/vsprojects/readme.txt
+++ b/vsprojects/readme.txt
@@ -6,6 +6,13 @@ accessible to those who primarily work with MSVC.
Compiling and Installing
========================
+0) Check whether a gtest directory exists in the upper level directory. If
+ you checkout the code from github via "git clone", this gtest directory
+ won't exist and you won't be able to build the tests described below. To
+ avoid this problem consider downloading one of the release tar balls which
+ contains gtest already and copying the gest directory from there to your
+ protobuf directory:
+ https://github.com/google/protobuf/releases
1) Open protobuf.sln in Microsoft Visual Studio.
2) Choose "Debug" or "Release" configuration as desired.*
3) From the Build menu, choose "Build Solution". Wait for compiling to finish.
diff --git a/vsprojects/test_plugin.vcproj b/vsprojects/test_plugin.vcproj
index 44a18c3e..549f9503 100755
--- a/vsprojects/test_plugin.vcproj
+++ b/vsprojects/test_plugin.vcproj
@@ -19,7 +19,7 @@
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
- IntermediateDirectory="Debug"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="1"
>
<Tool
@@ -46,7 +46,7 @@
AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
Optimization="0"
AdditionalIncludeDirectories="../src;.;../gtest/include"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_VARIADIC_MAX=10;"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
@@ -96,7 +96,7 @@
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
- IntermediateDirectory="Release"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="1"
>
<Tool
@@ -122,7 +122,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
AdditionalIncludeDirectories="../src;.;../gtest/include"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_VARIADIC_MAX=10;"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
diff --git a/vsprojects/tests.vcproj b/vsprojects/tests.vcproj
index 6f730289..0d42949e 100644
--- a/vsprojects/tests.vcproj
+++ b/vsprojects/tests.vcproj
@@ -19,7 +19,7 @@
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
- IntermediateDirectory="Debug"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="1"
>
<Tool
@@ -46,7 +46,7 @@
AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
Optimization="0"
AdditionalIncludeDirectories="../src;.;../gtest/include"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_VARIADIC_MAX=10;"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
@@ -96,7 +96,7 @@
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
- IntermediateDirectory="Release"
+ IntermediateDirectory="$(OutDir)\$(ProjectName)"
ConfigurationType="1"
>
<Tool
@@ -122,7 +122,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
AdditionalIncludeDirectories="../src;.;../gtest/include"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_VARIADIC_MAX=10;"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
@@ -194,6 +194,9 @@
RelativePath="..\src\google\protobuf\test_util.h"
>
</File>
+ <File RelativePath="..\src\google\protobuf\map_test_util_impl.h"></File>
+ <File RelativePath="..\src\google\protobuf\map_test_util.h"></File>
+ <File RelativePath="..\src\google\protobuf\arena_test_util.h"></File>
<File
RelativePath="..\src\google\protobuf\compiler\mock_code_generator.h"
>
@@ -215,6 +218,10 @@
>
</File>
<File
+ RelativePath=".\google\protobuf\unittest_import_public.pb.h"
+ >
+ </File>
+ <File
RelativePath=".\google\protobuf\unittest_lite_imports_nonline.pb.h"
>
</File>
@@ -243,35 +250,35 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
- RelativePath="..\src\google\protobuf\io\coded_stream_unittest.cc"
+ RelativePath="..\src\google\protobuf\arenastring_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\compiler\command_line_interface_unittest.cc"
+ RelativePath="..\src\google\protobuf\arena_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\compiler\mock_code_generator.cc"
+ RelativePath="..\src\google\protobuf\compiler\command_line_interface_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\common_unittest.cc"
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_bootstrap_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_bootstrap_unittest.cc"
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_plugin_unittest.cc"
>
</File>
<File
- RelativePath=".\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_unittest.cc"
+ RelativePath="..\src\google\protobuf\compiler\importer_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_plugin_unittest.cc"
+ RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment_unittest.cc"
>
</File>
<File
@@ -279,6 +286,14 @@
>
</File>
<File
+ RelativePath="..\src\google\protobuf\compiler\mock_code_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\parser_unittest.cc"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\compiler\python\python_plugin_unittest.cc"
>
</File>
@@ -291,6 +306,10 @@
>
</File>
<File
+ RelativePath="..\src\google\protobuf\drop_unknown_fields_test.cc"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\dynamic_message_unittest.cc"
>
</File>
@@ -299,35 +318,52 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\testing\file.cc"
+ RelativePath="..\src\google\protobuf\generated_message_reflection_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\generated_message_reflection_unittest.cc"
+ RelativePath="..\src\google\protobuf\io\coded_stream_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\testing\googletest.cc"
+ RelativePath="..\src\google\protobuf\io\printer_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\compiler\importer_unittest.cc"
+ RelativePath="..\src\google\protobuf\io\tokenizer_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\zero_copy_stream_unittest.cc"
>
</File>
<File
+ RelativePath="..\src\google\protobuf\map_field_test.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\map_test.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\map_test_util.cc"
+ >
+ </File>
+ <File RelativePath="..\src\google\protobuf\arena_test_util.cc"></File>
+ <File
RelativePath="..\src\google\protobuf\message_unittest.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\stubs\once_unittest.cc"
+ RelativePath="..\src\google\protobuf\no_field_presence_test.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\compiler\parser_unittest.cc"
+ RelativePath="..\src\google\protobuf\preserve_unknown_enum_test.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\io\printer_unittest.cc"
+ RelativePath="..\src\google\protobuf\proto3_arena_unittest.cc"
>
</File>
<File
@@ -335,10 +371,26 @@
>
</File>
<File
+ RelativePath="..\src\google\protobuf\repeated_field_reflection_unittest.cc"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\repeated_field_unittest.cc"
>
</File>
<File
+ RelativePath="..\src\google\protobuf\stubs\common_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\once_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\stringprintf_unittest.cc"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\stubs\structurally_valid_unittest.cc"
>
</File>
@@ -347,6 +399,22 @@
>
</File>
<File
+ RelativePath="..\src\google\protobuf\stubs\template_util_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\type_traits_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\testing\file.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\testing\googletest.cc"
+ >
+ </File>
+ <File
RelativePath="..\src\google\protobuf\test_util.cc"
>
</File>
@@ -355,11 +423,31 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\io\tokenizer_unittest.cc"
+ RelativePath="..\src\google\protobuf\unknown_field_set_unittest.cc"
>
</File>
<File
- RelativePath=".\google\protobuf\unittest.pb.cc"
+ RelativePath="..\src\google\protobuf\wire_format_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_preserve_unknown_enum2.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\map_proto2_unittest.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\map_unittest.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_arena.pb.cc"
>
</File>
<File
@@ -367,23 +455,55 @@
>
</File>
<File
+ RelativePath=".\google\protobuf\unittest_drop_unknown_fields.pb.cc"
+ >
+ </File>
+ <File
RelativePath=".\google\protobuf\unittest_embed_optimize_for.pb.cc"
>
</File>
<File
+ RelativePath=".\google\protobuf\unittest_empty.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_import_lite.pb.cc"
+ >
+ </File>
+ <File
RelativePath=".\google\protobuf\unittest_import.pb.cc"
>
</File>
<File
+ RelativePath=".\google\protobuf\unittest_import_public_lite.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_import_public.pb.cc"
+ >
+ </File>
+ <File
RelativePath=".\google\protobuf\unittest_lite_imports_nonlite.pb.cc"
>
</File>
<File
+ RelativePath=".\google\protobuf\unittest_lite.pb.cc"
+ >
+ </File>
+ <File
RelativePath=".\google\protobuf\unittest_mset.pb.cc"
>
</File>
<File
- RelativePath=".\google\protobuf\unittest_optimize_for.pb.cc"
+ RelativePath=".\google\protobuf\unittest_no_arena_import.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_no_arena.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_no_field_presence.pb.cc"
>
</File>
<File
@@ -391,29 +511,33 @@
>
</File>
<File
- RelativePath="..\src\google\protobuf\unknown_field_set_unittest.cc"
+ RelativePath=".\google\protobuf\unittest_optimize_for.pb.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\wire_format_unittest.cc"
+ RelativePath=".\google\protobuf\unittest.pb.cc"
>
</File>
<File
- RelativePath="..\src\google\protobuf\io\zero_copy_stream_unittest.cc"
+ RelativePath=".\google\protobuf\unittest_preserve_unknown_enum.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_proto3_arena.pb.cc"
>
</File>
</Filter>
<File
- RelativePath="..\src\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.proto"
+ RelativePath="..\src\google\protobuf\unittest_preserve_unknown_enum2.proto"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCustomBuildTool"
- Description="Generating cpp_test_bad_identifiers.pb.{h,cc}..."
- CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto&#x0D;&#x0A;"
- Outputs="google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h;google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
+ Description="Generating unittest_preserve_unknown_enum2.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_preserve_unknown_enum2.proto"
+ Outputs="google\protobuf\unittest_preserve_unknown_enum2.pb.h;google\protobuf\unittest_preserve_unknown_enum2.pb.cc"
/>
</FileConfiguration>
<FileConfiguration
@@ -421,9 +545,57 @@
>
<Tool
Name="VCCustomBuildTool"
- Description="Generating cpp_test_bad_identifiers.pb.{h,cc}..."
- CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto&#x0D;&#x0A;"
- Outputs="google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h;google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
+ Description="Generating unittest_preserve_unknown_enum2.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_preserve_unknown_enum2.proto"
+ Outputs="google\protobuf\unittest_preserve_unknown_enum2.pb.h;google\protobuf\unittest_preserve_unknown_enum2.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\map_proto2_unittest.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating map_proto2_unittest.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/map_proto2_unittest.proto"
+ Outputs="google\protobuf\map_proto2_unittest.pb.h;google\protobuf\map_proto2_unittest.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating map_proto2_unittest.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/map_proto2_unittest.proto"
+ Outputs="google\protobuf\map_proto2_unittest.pb.h;google\protobuf\map_proto2_unittest.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\map_unittest.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating map_unittest.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/map_unittest.proto"
+ Outputs="google\protobuf\map_unittest.pb.h;google\protobuf\map_unittest.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating map_unittest.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/map_unittest.proto"
+ Outputs="google\protobuf\map_unittest.pb.h;google\protobuf\map_unittest.pb.cc"
/>
</FileConfiguration>
</File>
@@ -436,7 +608,7 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest.pb.{h,cc}..."
- CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest.proto&#x0D;&#x0A;"
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest.proto"
Outputs="google\protobuf\unittest.pb.h;google\protobuf\unittest.pb.cc"
/>
</FileConfiguration>
@@ -446,12 +618,36 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest.pb.{h,cc}..."
- CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest.proto&#x0D;&#x0A;"
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest.proto"
Outputs="google\protobuf\unittest.pb.h;google\protobuf\unittest.pb.cc"
/>
</FileConfiguration>
</File>
<File
+ RelativePath="..\src\google\protobuf\unittest_arena.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_arena.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_arena.proto"
+ Outputs="google\protobuf\unittest_arena.pb.h;google\protobuf\unittest_arena.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_arena.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_arena.proto"
+ Outputs="google\protobuf\unittest_arena.pb.h;google\protobuf\unittest_arena.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\src\google\protobuf\unittest_custom_options.proto"
>
<FileConfiguration
@@ -460,7 +656,7 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_custom_options.pb.{h,cc}..."
- CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_custom_options.proto&#x0D;&#x0A;"
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_custom_options.proto"
Outputs="google\protobuf\unittest_custom_options.pb.h;google\protobuf\unittest_custom_options.pb.cc"
/>
</FileConfiguration>
@@ -470,12 +666,36 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_custom_options.pb.{h,cc}..."
- CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_custom_options.proto&#x0D;&#x0A;"
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_custom_options.proto"
Outputs="google\protobuf\unittest_custom_options.pb.h;google\protobuf\unittest_custom_options.pb.cc"
/>
</FileConfiguration>
</File>
<File
+ RelativePath="..\src\google\protobuf\unittest_drop_unknown_fields.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_drop_unknown_fields.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_drop_unknown_fields.proto"
+ Outputs="google\protobuf\unittest_drop_unknown_fields.pb.h;google\protobuf\unittest_drop_unknown_fields.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_drop_unknown_fields.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_drop_unknown_fields.proto"
+ Outputs="google\protobuf\unittest_drop_unknown_fields.pb.h;google\protobuf\unittest_drop_unknown_fields.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\src\google\protobuf\unittest_embed_optimize_for.proto"
>
<FileConfiguration
@@ -484,7 +704,7 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_embed_optimize_for.pb.{h,cc}..."
- CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_embed_optimize_for.proto&#x0D;&#x0A;"
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_embed_optimize_for.proto"
Outputs="google\protobuf\unittest_embed_optimize_for.pb.h;google\protobuf\unittest_embed_optimize_for.pb.cc"
/>
</FileConfiguration>
@@ -494,12 +714,60 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_embed_optimize_for.pb.{h,cc}..."
- CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_embed_optimize_for.proto&#x0D;&#x0A;"
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_embed_optimize_for.proto"
Outputs="google\protobuf\unittest_embed_optimize_for.pb.h;google\protobuf\unittest_embed_optimize_for.pb.cc"
/>
</FileConfiguration>
</File>
<File
+ RelativePath="..\src\google\protobuf\unittest_empty.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_empty.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_empty.proto"
+ Outputs="google\protobuf\unittest_empty.pb.h;google\protobuf\unittest_empty.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_empty.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_empty.proto"
+ Outputs="google\protobuf\unittest_empty.pb.h;google\protobuf\unittest_empty.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_import_lite.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import_lite.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_lite.proto"
+ Outputs="google\protobuf\unittest_import_lite.pb.h;google\protobuf\unittest_import_lite.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import_lite.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_lite.proto"
+ Outputs="google\protobuf\unittest_import_lite.pb.h;google\protobuf\unittest_import_lite.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\src\google\protobuf\unittest_import.proto"
>
<FileConfiguration
@@ -508,7 +776,7 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_import.pb.{h,cc}..."
- CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import.proto&#x0D;&#x0A;"
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import.proto"
Outputs="google\protobuf\unittest_import.pb.h;google\protobuf\unittest_import.pb.cc"
/>
</FileConfiguration>
@@ -518,12 +786,60 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_import.pb.{h,cc}..."
- CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import.proto&#x0D;&#x0A;"
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import.proto"
Outputs="google\protobuf\unittest_import.pb.h;google\protobuf\unittest_import.pb.cc"
/>
</FileConfiguration>
</File>
<File
+ RelativePath="..\src\google\protobuf\unittest_import_public_lite.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import_public_lite.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public_lite.proto"
+ Outputs="google\protobuf\unittest_import_public_lite.pb.h;google\protobuf\unittest_import_public_lite.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import_public_lite.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public_lite.proto"
+ Outputs="google\protobuf\unittest_import_public_lite.pb.h;google\protobuf\unittest_import_public_lite.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_import_public.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import_public.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public.proto"
+ Outputs="google\protobuf\unittest_import_public.pb.h;google\protobuf\unittest_import_public.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import_public.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public.proto"
+ Outputs="google\protobuf\unittest_import_public.pb.h;google\protobuf\unittest_import_public.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\src\google\protobuf\unittest_lite_imports_nonlite.proto"
>
<FileConfiguration
@@ -532,7 +848,7 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_lite_imports_nonlite.pb.{h,cc}..."
- CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite_imports_nonlite.proto&#x0D;&#x0A;"
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite_imports_nonlite.proto"
Outputs="google\protobuf\unittest_lite_imports_nonlite.pb.h;google\protobuf\unittest_lite_imports_nonlite.pb.cc"
/>
</FileConfiguration>
@@ -542,12 +858,36 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_lite_imports_nonlite.pb.{h,cc}..."
- CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite_imports_nonlite.proto&#x0D;&#x0A;"
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite_imports_nonlite.proto"
Outputs="google\protobuf\unittest_lite_imports_nonlite.pb.h;google\protobuf\unittest_lite_imports_nonlite.pb.cc"
/>
</FileConfiguration>
</File>
<File
+ RelativePath="..\src\google\protobuf\unittest_lite.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_lite.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite.proto"
+ Outputs="google\protobuf\unittest_lite.pb.h;google\protobuf\unittest_lite.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_lite.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite.proto"
+ Outputs="google\protobuf\unittest_lite.pb.h;google\protobuf\unittest_lite.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\src\google\protobuf\unittest_mset.proto"
>
<FileConfiguration
@@ -556,7 +896,7 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_mset.pb.{h,cc}..."
- CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_mset.proto&#x0D;&#x0A;"
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_mset.proto"
Outputs="google\protobuf\unittest_mset.pb.h;google\protobuf\unittest_mset.pb.cc"
/>
</FileConfiguration>
@@ -566,22 +906,22 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_mset.pb.{h,cc}..."
- CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_mset.proto&#x0D;&#x0A;"
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_mset.proto"
Outputs="google\protobuf\unittest_mset.pb.h;google\protobuf\unittest_mset.pb.cc"
/>
</FileConfiguration>
</File>
<File
- RelativePath="..\src\google\protobuf\unittest_optimize_for.proto"
+ RelativePath="..\src\google\protobuf\unittest_no_arena_import.proto"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCustomBuildTool"
- Description="Generating unittest_optimize_for.pb.{h,cc}..."
- CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_optimize_for.proto&#x0D;&#x0A;"
- Outputs="google\protobuf\unittest_optimize_for.pb.h;google\protobuf\unittest_optimize_for.pb.cc"
+ Description="Generating unittest_no_arena_import.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_arena_import.proto"
+ Outputs="google\protobuf\unittest_no_arena_import.pb.h;google\protobuf\unittest_no_arena_import.pb.cc"
/>
</FileConfiguration>
<FileConfiguration
@@ -589,9 +929,57 @@
>
<Tool
Name="VCCustomBuildTool"
- Description="Generating unittest_optimize_for.pb.{h,cc}..."
- CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_optimize_for.proto&#x0D;&#x0A;"
- Outputs="google\protobuf\unittest_optimize_for.pb.h;google\protobuf\unittest_optimize_for.pb.cc"
+ Description="Generating unittest_no_arena_import.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_arena_import.proto"
+ Outputs="google\protobuf\unittest_no_arena_import.pb.h;google\protobuf\unittest_no_arena_import.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_no_arena.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_no_arena.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_arena.proto"
+ Outputs="google\protobuf\unittest_no_arena.pb.h;google\protobuf\unittest_no_arena.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_no_arena.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_arena.proto"
+ Outputs="google\protobuf\unittest_no_arena.pb.h;google\protobuf\unittest_no_arena.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_no_field_presence.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_no_field_presence.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_field_presence.proto"
+ Outputs="google\protobuf\unittest_no_field_presence.pb.h;google\protobuf\unittest_no_field_presence.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_no_field_presence.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_field_presence.proto"
+ Outputs="google\protobuf\unittest_no_field_presence.pb.h;google\protobuf\unittest_no_field_presence.pb.cc"
/>
</FileConfiguration>
</File>
@@ -604,7 +992,7 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_no_generic_services.pb.{h,cc}..."
- CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_generic_services.proto&#x0D;&#x0A;"
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_generic_services.proto"
Outputs="google\protobuf\unittest_no_generic_services.pb.h;google\protobuf\unittest_no_generic_services.pb.cc"
/>
</FileConfiguration>
@@ -614,11 +1002,107 @@
<Tool
Name="VCCustomBuildTool"
Description="Generating unittest_no_generic_services.pb.{h,cc}..."
- CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_generic_services.proto&#x0D;&#x0A;"
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_generic_services.proto"
Outputs="google\protobuf\unittest_no_generic_services.pb.h;google\protobuf\unittest_no_generic_services.pb.cc"
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_optimize_for.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_optimize_for.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_optimize_for.proto"
+ Outputs="google\protobuf\unittest_optimize_for.pb.h;google\protobuf\unittest_optimize_for.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_optimize_for.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_optimize_for.proto"
+ Outputs="google\protobuf\unittest_optimize_for.pb.h;google\protobuf\unittest_optimize_for.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_preserve_unknown_enum.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_preserve_unknown_enum.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_preserve_unknown_enum.proto"
+ Outputs="google\protobuf\unittest_preserve_unknown_enum.pb.h;google\protobuf\unittest_preserve_unknown_enum.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_preserve_unknown_enum.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_preserve_unknown_enum.proto"
+ Outputs="google\protobuf\unittest_preserve_unknown_enum.pb.h;google\protobuf\unittest_preserve_unknown_enum.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_proto3_arena.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_proto3_arena.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_proto3_arena.proto"
+ Outputs="google\protobuf\unittest_proto3_arena.pb.h;google\protobuf\unittest_proto3_arena.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_proto3_arena.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_proto3_arena.proto"
+ Outputs="google\protobuf\unittest_proto3_arena.pb.h;google\protobuf\unittest_proto3_arena.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating cpp_test_bad_identifiers.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto"
+ Outputs="google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h;google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating cpp_test_bad_identifiers.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto"
+ Outputs="google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h;google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
</Files>
<Globals>
</Globals>